动态准备 SQL 语句的逻辑
Logic to prepare SQL statements dynamically
所以我有一个要求,我需要通读一个文件的所有记录的记录,如果它们符合另一个 table 中描述的一组规则,则将它们插入另一个文件,如下所示。 .
从第一个文件读取后的记录必须满足至少一个规则的所有序列才能使其有资格写入第二个table。
例如,一旦从CAR文件中读取一条记录,就必须检查下面的规则,直到满足至少一个规则集的所有序列。为此,我计划创建一个动态的 SQL 程序。但这不起作用,因为 Prepared SQL 不支持主机变量。
如果有人可以就如何动态创建 SQL statemtns 并检查记录是否满足将它们输入第二个文件所需的规则提出建议或提供任何指导,那就太好了
所以基本上我正在寻找的是一旦我 select 来自 table 的字段,我如何将它存储在某个地方以进行进一步的验证和检查。
Update
:
根据 Danny117 的智能建议,我想出了以下代码:
H Option(*NoDebugIO:*SrcStmt)
D RULEDS E DS EXTNAME(RULESTABLE)
D MAXRUL S 1 0
D MAXSEQ S 1 0
D STMT S 512
D WHERESTMT S 512 INZ('')
D FullSqlStmt S 512 INZ('')
D RULINDEX S 1 0 INZ(1)
D SEQINDEX S 1 0 INZ(1)
D APOS C CONST('''')
/Free
Exec SQL SELECT MAX(RULENO)INTO :MAXRUL FROM RULESTABLE;
Exec SQL DECLARE RULCRS CURSOR FOR SELECT * FROM RULESTABLE;
Exec SQL OPEN RULCRS;
Exec SQL FETCH RULCRS INTO :RULEDS;
DoW (Sqlcod = 0 AND RULINDEX <= MAXRUL);
Exec SQL SELECT MAX(SEQNO) INTO :MAXSEQ FROM RULESTABLE
WHERE RULENO=:RULINDEX ;
DoW (SEQINDEX <= MAXSEQ);
If (Position <> '');
Field = 'SUBSTR('+%Trim(Field)+','+%Trim(Position)+','
+'1'+')';
EndIf;
WhereStmt = %Trim(WhereStmt) + ' ' + %Trim(field)+ ' ' +
%Trim(condition) + ' ' + APOS + %Trim(Value) + APOS;
If (SeqIndex < MaxSeq);
WhereStmt = %Trim(WhereStmt) + ' AND ';
EndIf;
Exec SQL FETCH NEXT FROM RULCRS INTO :RULEDS;
SeqIndex = SeqIndex + 1;
EndDo;
FullSqlStmt = %Trim('INSERT INTO ITMRVAT SELECT * +
FROM ITMRVA WHERE '+ %Trim(WhereStmt));
Exec SQL Prepare InsertStmt from :FullSqlStmt;
Exec SQL EXECUTE InsertStmt;
RulIndex = RulIndex + 1;
EndDo;
这会生成如下所示的 SQL 语句,这正是我想要的。现在让我继续看看代码的其他部分。
> EVAL FullSqlStmt
FULLSQLSTMT =
....5...10...15...20...25...30...35...40...45...50...55...60
1 'INSERT INTO ITMRVAT SELECT * FROM ITMRVA WHERE STID = 'PLD' '
61 'AND ENGNO LIKE '%415015%' AND SUBSTR(ENGNO,1,1) = 'R' AND SU'
121 'BSTR(ENGNO,5,1) = 'Y' '
181 ' '
241 ' '
301 ' '
361 ' '
421 ' '
481 ' '
但现在的问题是,正如我在对 Danny 的评论中提到的,如果指定了涉及第二个 table 的新规则,如何处理..
嵌入式 SQL 允许在 ILE 语言中使用 'dynamic statements'。您可以在字符字段中进行查询,然后将其传递到嵌入式 SQL.
Dcl-S lQuery Varchar(100);
lQuery = 'SELECT * FROM CUST';
EXEC SQL
PREPARE SCust FROM :lQuery;
EXEC SQL
DECLARE SearchCust CURSOR FOR SCust;
//Continue working with cursor..
您可能只想准备、执行和return一个结果集:
lQuery = 'SELECT * FROM CUST WHERE ID = ' + %Char(CustID);
EXEC SQL
PREPARE SCust FROM :lQuery;
DECLARE c1 CURSOR FOR SCust;
OPEN c1;
FETCH c1 INTO :CustDS;
CLOSE c1;
额外可选:您可能还想在查询中使用字段标记 (?)。
//'SELECT * FROM CUST WHERE CUSTID = ?';
EXEC SQL OPEN SearchCust USING :CustID;
//'INSERT INTO CUST VALUES(?,?)';
EXEC SQL EXECUTE CUST USING :CustID;
您必须将规则转换为连接语句或 where 子句。连接语句更复杂,所以走那条路。
如果您很聪明(并且您很聪明),请考虑将规则保存为 SQL 子句,您可以加入或在 where 子句中使用。它以这种方式无限灵活,更现代的设计。
rule 1 / car.year = 1990 and car.engno like '%43243%' and substring(car.vin,12,1) = 'X'
eval statement =
insert into sometable
Select car.* from car
join sysibm.sysdummy1
on car.year = 1990
and car.engno lile '%43243%'
...等规则 2 从 "OR"
开始
or car.year = PLD
and car.engno like '%1234%'
...等等其他以"OR"
开头的规则
exec immediate statement
所以我有一个要求,我需要通读一个文件的所有记录的记录,如果它们符合另一个 table 中描述的一组规则,则将它们插入另一个文件,如下所示。 .
从第一个文件读取后的记录必须满足至少一个规则的所有序列才能使其有资格写入第二个table。
例如,一旦从CAR文件中读取一条记录,就必须检查下面的规则,直到满足至少一个规则集的所有序列。为此,我计划创建一个动态的 SQL 程序。但这不起作用,因为 Prepared SQL 不支持主机变量。
如果有人可以就如何动态创建 SQL statemtns 并检查记录是否满足将它们输入第二个文件所需的规则提出建议或提供任何指导,那就太好了
所以基本上我正在寻找的是一旦我 select 来自 table 的字段,我如何将它存储在某个地方以进行进一步的验证和检查。
Update
:
根据 Danny117 的智能建议,我想出了以下代码:
H Option(*NoDebugIO:*SrcStmt)
D RULEDS E DS EXTNAME(RULESTABLE)
D MAXRUL S 1 0
D MAXSEQ S 1 0
D STMT S 512
D WHERESTMT S 512 INZ('')
D FullSqlStmt S 512 INZ('')
D RULINDEX S 1 0 INZ(1)
D SEQINDEX S 1 0 INZ(1)
D APOS C CONST('''')
/Free
Exec SQL SELECT MAX(RULENO)INTO :MAXRUL FROM RULESTABLE;
Exec SQL DECLARE RULCRS CURSOR FOR SELECT * FROM RULESTABLE;
Exec SQL OPEN RULCRS;
Exec SQL FETCH RULCRS INTO :RULEDS;
DoW (Sqlcod = 0 AND RULINDEX <= MAXRUL);
Exec SQL SELECT MAX(SEQNO) INTO :MAXSEQ FROM RULESTABLE
WHERE RULENO=:RULINDEX ;
DoW (SEQINDEX <= MAXSEQ);
If (Position <> '');
Field = 'SUBSTR('+%Trim(Field)+','+%Trim(Position)+','
+'1'+')';
EndIf;
WhereStmt = %Trim(WhereStmt) + ' ' + %Trim(field)+ ' ' +
%Trim(condition) + ' ' + APOS + %Trim(Value) + APOS;
If (SeqIndex < MaxSeq);
WhereStmt = %Trim(WhereStmt) + ' AND ';
EndIf;
Exec SQL FETCH NEXT FROM RULCRS INTO :RULEDS;
SeqIndex = SeqIndex + 1;
EndDo;
FullSqlStmt = %Trim('INSERT INTO ITMRVAT SELECT * +
FROM ITMRVA WHERE '+ %Trim(WhereStmt));
Exec SQL Prepare InsertStmt from :FullSqlStmt;
Exec SQL EXECUTE InsertStmt;
RulIndex = RulIndex + 1;
EndDo;
这会生成如下所示的 SQL 语句,这正是我想要的。现在让我继续看看代码的其他部分。
> EVAL FullSqlStmt
FULLSQLSTMT =
....5...10...15...20...25...30...35...40...45...50...55...60
1 'INSERT INTO ITMRVAT SELECT * FROM ITMRVA WHERE STID = 'PLD' '
61 'AND ENGNO LIKE '%415015%' AND SUBSTR(ENGNO,1,1) = 'R' AND SU'
121 'BSTR(ENGNO,5,1) = 'Y' '
181 ' '
241 ' '
301 ' '
361 ' '
421 ' '
481 ' '
但现在的问题是,正如我在对 Danny 的评论中提到的,如果指定了涉及第二个 table 的新规则,如何处理..
嵌入式 SQL 允许在 ILE 语言中使用 'dynamic statements'。您可以在字符字段中进行查询,然后将其传递到嵌入式 SQL.
Dcl-S lQuery Varchar(100);
lQuery = 'SELECT * FROM CUST';
EXEC SQL
PREPARE SCust FROM :lQuery;
EXEC SQL
DECLARE SearchCust CURSOR FOR SCust;
//Continue working with cursor..
您可能只想准备、执行和return一个结果集:
lQuery = 'SELECT * FROM CUST WHERE ID = ' + %Char(CustID);
EXEC SQL
PREPARE SCust FROM :lQuery;
DECLARE c1 CURSOR FOR SCust;
OPEN c1;
FETCH c1 INTO :CustDS;
CLOSE c1;
额外可选:您可能还想在查询中使用字段标记 (?)。
//'SELECT * FROM CUST WHERE CUSTID = ?';
EXEC SQL OPEN SearchCust USING :CustID;
//'INSERT INTO CUST VALUES(?,?)';
EXEC SQL EXECUTE CUST USING :CustID;
您必须将规则转换为连接语句或 where 子句。连接语句更复杂,所以走那条路。
如果您很聪明(并且您很聪明),请考虑将规则保存为 SQL 子句,您可以加入或在 where 子句中使用。它以这种方式无限灵活,更现代的设计。
rule 1 / car.year = 1990 and car.engno like '%43243%' and substring(car.vin,12,1) = 'X'
eval statement =
insert into sometable
Select car.* from car
join sysibm.sysdummy1
on car.year = 1990
and car.engno lile '%43243%'
...等规则 2 从 "OR"
开始or car.year = PLD
and car.engno like '%1234%'
...等等其他以"OR"
开头的规则exec immediate statement