Teradata 过程中的 WHILE 循环

WHILE loop in Teradata procedure

我正在尝试编写一个程序,在行号未知的情况下连接 table 中的所有行。

我有这段代码,但它不起作用。

CREATE PROCEDURE Test (OUT r VARCHAR(3000))

BEGIN
DECLARE RowCnt INT;
DECLARE CurrRow INT ;
SET CurrRow = 1,
       r = 'SELECT ', 
       RowCnt = (SELECT COUNT(*) 
                   FROM tableWithSQLStmnts
                   )    
WHILE CurrRow <= RowCnt DO
BEGIN 
           SET r = r + 
           CASE WHEN CurrRow = 1  
                THEN 'MAX( CASE Seq WHEN ' + CAST( CurrRow AS VARCHAR ) + ' 
                                 THEN SqlStmnt 
                                            ELSE SPACE(0) END ) + ' + CHAR(13) 
           WHEN i = RowCnt 
             THEN 'MAX( CASE Seq WHEN ' + CAST( CurrRow AS VARCHAR ) + ' 
                                 THEN ''  '' + SqlStmnt 
                                 ELSE SPACE(0) END ) ' + CHAR(13) 
             ELSE 'MAX( CASE Seq WHEN ' + CAST( CurrRow AS VARCHAR ) + ' 
                                 THEN ''  '' + SqlStmnt
                                 ELSE SPACE(0) END ) + ' + CHAR(13)  
           END 
           SET CurrRow = CurrRow + 1 ;
END ;
SET r = r + ' 
    FROM ( SELECT SqlStmnt, 
                  ROW_NUMBER() OVER ( PARTITION BY TabName ORDER BY SQlStmnt )
             FROM tableWithSQLStmnts t ) D ( SqlStmnt, Seq ) 
           GROUP BY TabName;' 

END WHILE;
END

;

我收到以下错误:

新代码,如 dnoeth 所建议。

REPLACE PROCEDURE Test3 (IN TbName VARCHAR(256)) --, OUT r2 VARCHAR(3000))

BEGIN
DECLARE RowCnt INT;
DECLARE i INT;
DECLARE CurrRow INT;
DECLARE r VARCHAR(3000);
DECLARE r2 VARCHAR(3000);
SET CurrRow = 1;
SET r = 'SELECT ';
SET RowCnt = (SELECT COUNT(*) 
              FROM tableWithSQLStmnts
              WHERE tabname = :TbName
             );

WHILE CurrRow <= RowCnt DO
   BEGIN 
      SET r = r ||
   'MAX( CASE Seq WHEN ' || CAST( CurrRow AS VARCHAR(10) ) || ' 
           THEN '' , '' || SqlStmnt
           ELSE '''' END ) 
   '
      || CASE WHEN CurrRow = RowCnt 
              THEN '' 
              ELSE ' ||  '
         END;
      SET CurrRow = CurrRow + 1 ;
   END;
END WHILE;

SET r = r || ' 
    FROM ( SELECT SqlStmnt, 
                  ROW_NUMBER() OVER ( PARTITION BY TbName ORDER BY SQlStmnt )
             FROM tableWithSQLStmnts t ) D ( SqlStmnt ) 
           GROUP BY TbName
           ;';

SET r2 = r;
CALL dbc.sysexecsql(:r);
END;

现在我得到这个错误:

[3706] Syntax error: Column name list shorter than select list.

编辑 2:

我现在改写成这样了:

REPLACE PROCEDURE Test3 (IN TabName VARCHAR(256))
DYNAMIC RESULT SETS 1
BEGIN
DECLARE RowCnt INT;
DECLARE Seq INT;
DECLARE QRY VARCHAR(3000);
DECLARE CurrRow INT;
SET QRY= 'INSERT INTO vt21 SELECT   ';
SET CurrRow = 1;

CREATE VOLATILE TABLE vt21(QRY VARCHAR(3000)) ON COMMIT PRESERVE ROWS;
SET RowCnt = (SELECT COUNT(*) 
              FROM TestTable
              WHERE tabname = :TabName
             );
FOR CurrentRefRow AS SourceCursor CURSOR FOR   
            SELECT SqlStmnt
            FROM TestTable
            DO
WHILE CurrRow <= RowCnt 
DO
   BEGIN 
      SET QRY = QRY ||
      CASE  WHEN CurrRow=1
      THEN   'MAX( CASE Seq  WHEN ' || CAST( CurrRow AS VARCHAR(10) ) || ' 
           THEN '' , '' || SqlStmnt
           ELSE '''' END )     ' 

         WHEN CurrRow < RowCnt
         THEN ', MAX( CASE Seq WHEN ' || CAST( CurrRow AS VARCHAR(10) ) || ' 
           THEN '' , '' || SqlStmnt
           ELSE '''' END )    ' 
         WHEN CurrRow=RowCnt
      THEN   ', MAX( CASE Seq WHEN ' || CAST( CurrRow AS VARCHAR(10) ) || ' 
           THEN '' , '' || SqlStmnt
           ELSE '''' END ) '
              ELSE ' ||  '
         END;
                  SET CurrRow = CurrRow + 1 ;
         END;
         END WHILE;

SET QRY = QRY || ' 
    FROM ( SELECT SqlStmnt, Tabname,
                  ROW_NUMBER() OVER ( PARTITION BY TabName ORDER BY SQlStmnt )
             FROM TestTable t ) D ( Seq, Tabname, SqlStmnt ) 
           GROUP BY TabName
           ;';

EXECUTE IMMEDIATE QRY;
END FOR;   


 BEGIN -- return the result set
      DECLARE resultset CURSOR WITH RETURN ONLY FOR S1;
      SET QRY = 'SELECT * FROM  vt21;';
      PREPARE S1 FROM QRY;
      OPEN resultset;
   END;

DROP TABLE vt21;
END;

但我收到以下错误:

通话失败。 [3813] 位置分配列表的值太多。

我试过修改它,但是当我删除一个值时,它说列名列表比 select 列表长。

这被翻译成 Teradata/Standard SQL 的有效语法(并稍微简化):

REPLACE PROCEDURE Test (OUT r2 VARCHAR(3000))

BEGIN
DECLARE RowCnt INT;
DECLARE i INT;

DECLARE CurrRow INT;
DECLARE r VARCHAR(3000);

SET CurrRow = 1;
SET r = 'SELECT ';
SET RowCnt = (SELECT Count(*) 
              FROM tableWithSQLStmnts
             );

WHILE CurrRow <= RowCnt DO
   BEGIN 
      SET r = r ||
   'MAX( CASE Seq WHEN ' || Cast( CurrRow AS VARCHAR(10) ) || ' 
           THEN ''  '' || SqlStmnt
           ELSE '''' END )
   '
      || CASE WHEN CurrRow = RowCnt 
              THEN '' 
              ELSE ' || '
         END;
      SET CurrRow = CurrRow + 1 ;
   END;
END WHILE;

SET r = r || ' 
    FROM ( SELECT department_name--SqlStmnt, 
                  ROW_NUMBER() OVER ( PARTITION BY TabName ORDER BY SQlStmnt )
             FROM tableWithSQLStmnts t ) D ( SqlStmnt, Seq ) 
           GROUP BY TabName
           ;';

SET r2 = r;
END
;

tableWithSQLStmnts的内容是什么?

为什么要单行?有更简单的方法来获得一种 LISTAGG.

编辑:

根据您的评论(此处和 Teradata 的 Developer Exchange),您似乎想对每一列应用某种计数。但是你不需要 MAX/CASE/ROW_NUMBER,只需连接所有行以获得 table 然后执行它。这会计算 table:

的每一列中的 NULL
REPLACE PROCEDURE Test3 (IN DBName VARCHAR(128),IN TabName VARCHAR(128))
DYNAMIC RESULT SETS 1
BEGIN

   DECLARE QRY VARCHAR(3000);

   CREATE VOLATILE TABLE vt21(col VARCHAR(128) CHARACTER SET Unicode, NullCnt BIGINT) ON COMMIT PRESERVE ROWS;

   SET QRY = 'INSERT INTO vt21 ';

   FOR c AS   
      SELECT DatabaseName, TableName, ColumnName, 
         Row_Number()
         Over (PARTITION BY tablename
                ORDER BY columnname) AS rn,
         Count(*)
         Over (PARTITION BY tablename) AS Cnt
      FROM dbc.ColumnsV
      WHERE DatabaseName = :DBName
        AND TableName = :TabName
   DO 
      SET QRY = QRY
        || 'SELECT ''' || c.ColumnName
        || ''', COUNT(CASE WHEN ' || c.columnname
        || ' IS NULL THEN 1 END) FROM '
        || c.DatabaseName || '.' || c.TableName
        || CASE WHEN c.rn = c.Cnt -- last row
                THEN ';' 
                ELSE ' UNION ALL ' 
           END;

   END FOR;

   EXECUTE IMMEDIATE QRY;

   BEGIN -- return the result set
      DECLARE resultset CURSOR WITH RETURN ONLY FOR S1;
      SET QRY = 'SELECT * FROM  vt21;';
      PREPARE S1 FROM QRY;
      OPEN resultset;
   END;

   DROP TABLE vt21;

END;

CALL Test3('dbc', 'dbcinfoV');