RPGLE 准备语句抛出 SQLSTATE=42601

RPGLE prepare statement throwing SQLSTATE=42601

我正在尝试在 SQLRPGLE 中使用准备好的语句,但它不起作用。

这是我的 RPGLE 程序。

      * TR * 01/10/21 - CREATION
      **************************************************************************
      * Extraction RCPENT dans Excel
      **************************************************************************
     Dx1nrc            S              8s 0
     Dsql              S           1000a
     DwhereOrAnd       S              7a
     Doperator         S              4a
     Ddate_deb         S             10a
     Ddate_fin         S             10a
     D
      * Date de début
     DDAT_DEB          DS                  QUALIFIED
     DX1DEBA                   1      4  0
     DX1DEBM                   5      6  0
     DX1DEBJ                   7      8  0
      * Date de fin
     DDAT_FIN          DS                  QUALIFIED
     DX1FINA                   1      4  0
     DX1FINM                   5      6  0
     DX1FINJ                   7      8  0
     D
     D RCP1304         PR                  EXTPGM('RCP1304')
     D  ZPDEB                              LIKEDS(DAT_DEB)
     D  ZPFIN                              LIKEDS(DAT_FIN)
     D  ZPRAD                         1
     D  ZPCLO                         1
     D  ZPRET                         1
     D
     D RCP1304         PI
     D  ZPDEB                              LIKEDS(DAT_DEB)
     D  ZPFIN                              LIKEDS(DAT_FIN)
     D  ZPRAD                         1
     D  ZPCLO                         1
     D  ZPRET                         1
     C/exec sql
     C+ set option commit=*none,
     C+ datfmt=*iso
     C/end-exec
      *
      /Free

          sql = 'INSERT INTO XLSRCP +
          SELECT ''Adhérent'', ''Nom'', ''Date Création'', +
         ''Montant récup.'', ''Montant réglé'', +
         ''Cloturé'', ''Radié'' FROM SYSIBM.SYSDUMMY1 +
         UNION ALL +
         SELECT ADSTE || DIGITS(ADGRP) || DIGITS(ADIND), +
         ADNOM,  (DIGITS(RC1CRS) || +
         DIGITS(RC1CRA) || ''-'' || +
         DIGITS(RC1CRM) || ''-'' || +
         DIGITS(RC1CRJ)), CAST(RC1MRC as CHAR(7)), +
         CASE +
            WHEN cumul IS NULL THEN 0 +
            ELSE CAST(cumul as CHAR(7)) +
         END, +
         CASE +
            WHEN RC1CCM = 0 THEN ''Non soldé'' +
            ELSE ''Soldé'' +
         END, +
         CASE +
            WHEN ADRADM = 0 THEN ''Actif'' +
            ELSE ''Radié'' +
         END +
         FROM RCPENT +
         LEFT JOIN (SELECT SJSTE, SJGRP, SJIND, SUM(SJETM + SJEDEP) +
         as cumul FROM QS36F.SINATT +
         GROUP BY SJSTE, SJGRP, SJIND) +
         ON  SJSTE = RC1STE AND SJGRP = RC1GRP AND SJIND = RC1IND +
         JOIN ADHERE01 ON ADSTE = RC1STE +
         AND ADGRP = RC1GRP AND ADIND = RC1IND ';

        //*- Verification si plage de date renseignée
          if zpdeb.X1DEBM > 0 and zpfin.X1FINM > 0;

              date_deb = %editc(zpdeb.X1DEBA:'X') + '-' +
                         %editc(zpdeb.X1DEBM:'X') + '-' +
                         %editc(zpdeb.X1DEBJ:'X');


              date_fin = %editc(zpfin.X1FINA:'X') + '-' +
                         %editc(zpfin.X1FINM:'X') + '-' +
                         %editc(zpfin.X1FINJ:'X');

              sql = %trim(sql) + ' WHERE DATE((DIGITS(RC1CRS) || +
                           DIGITS(RC1CRA) || ''-'' || +
                           DIGITS(RC1CRM) || ''-'' || +
                           DIGITS(RC1CRJ))) +
                       BETWEEN DATE(''?'') AND DATE(''?'') ';

              *In80 = *On;

          endif;
        //*- Verification si on a parametré selon recup cloturée ou pas
          if ZPCLO <> ' ';

              whereOrAnd = ' WHERE ';
              operator = ' != ';

              if *In80;
                  whereOrAnd = ' AND ';
              endif;

              if ZPCLO = 'N';
                  operator = ' = ';
              endif;

              sql = %trim(sql) + whereOrAnd + 'RC1CCM' + operator + '0';
              *In80 = *On;

          endif;

          if ZPRAD <> ' ';

              whereOrAnd = ' WHERE ';
              operator = ' != ';

              if *In80;
                  whereOrAnd = ' AND ';
              endif;

              if ZPCLO = 'N';
                  operator = ' = ';
              endif;

              sql = %trim(sql) + whereOrAnd + 'ADRADM' + operator + '0';
              *In80 = *On;

          endif;

          exec sql prepare s1 from :sql;

          exec sql execute s1 using :date_deb, :date_fin;

      /end-free
     C                   Eval      *Inlr=*On 

这是连接后的语句的样子。

SELECT 'Adhérent', 'Nom', 'Date Création',
 'Montant recup.', 'Montant réglé.', 'Cloturé', 'Radié' FROM SYSIBM.SYSDUMMY1 

UNION ALL 

SELECT ADSTE  || DIGITS(ADGRP) || DIGITS(ADIND), 
       ADNOM,  
       (DIGITS(RC1CRS) || 
        DIGITS(RC1CRA) || '-' || 
        DIGITS(RC1CRM) || '-' || DIGITS(RC1CRJ)), 
       CAST(RC1MRC as CHAR(7)), 
       CASE WHEN cumul IS NULL THEN '0' ELSE CAST(cumul as CHAR(7)) END,
       CASE WHEN RC1CCM = '0' THEN 'Non soldé' ELSE 'Soldé' END, 
       CASE WHEN ADRADM = '0' THEN 'Actif' ELSE 'Radié' END 
 FROM CGMF99.RCPENT 
 LEFT JOIN (SELECT SJSTE, SJGRP, SJIND, SUM(SJETM + SJEDEP) as cumul 
            FROM QS36F.SINATT 
            GROUP BY SJSTE, SJGRP, SJIND) 
   ON SJSTE = RC1STE AND SJGRP = RC1GRP AND SJIND = RC1IND 
 LEFT JOIN CGMF99.ADHERE01 
   ON ADSTE = RC1STE AND ADGRP = RC1GRP AND ADIND = RC1IND 
 WHERE DATE((DIGITS(RC1CRS) || 
             DIGITS(RC1CRA) || '-' || 
             DIGITS(RC1CRM) || '-' || 
             DIGITS(RC1CRJ))) BETWEEN DATE('?') AND DATE('?')       

我尝试在 iAccess SQL 实用程序中 运行 手动替换 '?'日期和它正常工作。

然而,当我 运行 程序正常时它不工作并抛出 SQLSTATE = 42601(发现调试)。

我试图删除 '?' 周围的引号但它没有帮助。

更新 1:

所以我尝试使用 EXECUTE IMMEDIATE 语句而不是 prepare/execute 语句,只是将 date_deb 和 [=39= 的值连接起来]date_fin个变量。它没有帮助,但是我注意到这两种方法的 SQLCA 是相同的。这让我假设错误来自其他原因。

这是我在 SQLCA

拥有的
EVAL SQLCA                         
SQLCAID OF SQLCA = 'SQLCA   '      
SQLAID OF SQLCA = 'SQLCA   '       
SQLABC OF SQLCA = 000000136.       
SQLCABC OF SQLCA = 136             
SQLCODE OF SQLCA = -104            
SQLCOD OF SQLCA = -000000104.      
SQLERRML OF SQLCA = 24             
SQLERL OF SQLCA = 0024.            
SQLERM OF SQLCA =                  
          ....5...10...15...20...25...30...3
     1   ' ?| ?+ - AS <IDENTIFIER> '
    61   '          '              
SQLERRMC OF SQLCA =       
          ....5...10...15...20...25...30...3
     1   ' ?| ?+ - AS <IDENTIFIER> '         
    61   '          '                       
SQLERRP OF SQLCA = 'QSQRPARS'               
SQLERP OF SQLCA = 'QSQRPARS'                
SQLER1 OF SQLCA = 000000000.                
SQLERRD OF SQLCA(1) = 0                     
SQLERRD OF SQLCA(2) = 0                     
SQLERRD OF SQLCA(3) = 0                     
SQLERRD OF SQLCA(4) = 0                     
SQLERRD OF SQLCA(5) = 169                   
SQLERRD OF SQLCA(6) = 0                     
SQLERR OF SQLCA = '                   z    '
SQLER2 OF SQLCA = 000000000.
SQLER3 OF SQLCA = 000000000.          
SQLER4 OF SQLCA = 000000000.          
SQLER5 OF SQLCA = 000000169.          
SQLER6 OF SQLCA = 000000000.          
SQLWRN OF SQLCA = '           '       
SQLWN0 OF SQLCA = ' '                 
SQLWARN OF SQLCA(1) = ' '             
SQLWARN OF SQLCA(2) = ' '             
SQLWARN OF SQLCA(3) = ' '             
SQLWARN OF SQLCA(4) = ' '             
SQLWARN OF SQLCA(5) = ' '             
SQLWARN OF SQLCA(6) = ' '             
SQLWARN OF SQLCA(7) = ' '             
SQLWARN OF SQLCA(8) = ' '             
SQLWARN OF SQLCA(9) = ' '            
SQLWARN OF SQLCA(10) = ' '           
SQLWARN OF SQLCA(11) = ' '           
SQLWN1 OF SQLCA = ' '                
SQLWN2 OF SQLCA = ' '                
SQLWN3 OF SQLCA = ' '                
SQLWN4 OF SQLCA = ' '                
SQLWN5 OF SQLCA = ' '                
SQLWN6 OF SQLCA = ' '                
SQLWN7 OF SQLCA = ' '                
SQLWN8 OF SQLCA = ' '                
SQLWN9 OF SQLCA = ' '                
SQLWNA OF SQLCA = ' '                
SQLSTATE OF SQLCA = '42601'                                   

我无法从中提取任何有趣的东西,除了 SQLERRD OF SQLCA(5) = 169 据说它表示列或 PREPARE 和 EXECUTE 语句中错误的位置,但我不明白如何使用它。

这是我的 sql 字符串中的内容,以防万一..

       ....5...10...15...20...25...30...35...40...45...50...55...60 
  1   'INSERT INTO CGMF99.XLSRCP SELECT 'Adhérent', 'Nom', 'Date Cr'
 61   'éation', 'Montant récup.', 'Montant réglé', 'Cloturé', 'Radi'
121   'é' FROM SYSIBM.SYSDUMMY1 UNION ALL SELECT ADSTE || DIGITS(AD'
181   'GRP) || DIGITS(ADIND), ADNOM,  (DIGITS(RC1CRS) || DIGITS(RC1'
241   'CRA) || '-' || DIGITS(RC1CRM) || '-' || DIGITS(RC1CRJ)), CAS'
301   'T(RC1MRC as CHAR(7)), CASE WHEN cumul IS NULL THEN '0' ELSE '
361   'CAST(cumul as CHAR(7)) END, CASE WHEN RC1CCM = 0 THEN 'Non s'
421   'oldé' ELSE 'Soldé' END, CASE WHEN ADRADM = 0 THEN 'Actif' EL'
481   'SE 'Radié' END FROM CGMF99.RCPENT LEFT JOIN (SELECT SJSTE, S'
541   'JGRP, SJIND, SUM(SJETM + SJEDEP) as cumul FROM QS36F.SINATT '
601   'GROUP BY SJSTE, SJGRP, SJIND) ON  SJSTE = RC1STE AND SJGRP ='
661   ' RC1GRP AND SJIND = RC1IND JOIN CGMF99.ADHERE01 ON ADSTE = R' 
721   'C1STE AND ADGRP = RC1GRP AND ADIND = RC1IND WHERE DATE((DIGI' 
781   'TS(RC1CRS) || DIGITS(RC1CRA) || '-' || DIGITS(RC1CRM) || '-'' 
841   ' || DIGITS(RC1CRJ))) BETWEEN DATE(?) AND DATE(?)            ' 
901   '                                                            ' 
961   '                                        '                     

我做错了什么?

最终 SQLCA 找到了我的问题的答案。

SQLERRMC OF SQLCA =       
          ....5...10...15...20...25...30...3
     1   ' ?| ?+ - AS <IDENTIFIER> '         
    61   '         

这里的消息指出了我在查询中用来替换 CONCAT 的管道。 这些管道确实适用于预编译 SQL 但由于某些原因它们不适用于动态 SQL...

顺便说一下SQLERRD(5)确实给出了语法错误的位置。在我的例子中 SQLERRD OF SQLCA(5) = 169 它是字符串的第 169 个字符(竖线)。

更换所有管道解决了问题,但我遇到了新错误。

这次是DB2SQL错误:SQLCODE=-418,SQLSTATE=42610

这个来自我使用参数的方式,再次出于我所不知道的原因,这不起作用 DATE(?) 但这样做 CAST(? AS date).

解决了这两个错误后,我终于设法让我的程序运行了。

如果有人对这种行为有解释,我非常有兴趣在评论中看到它!