我正在尝试编写一个过程,在行号未知的情况下连接表中的所有行。
我有这段代码,但它无效。
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;
但我收到以下错误:
CALL失败。 [3813]位置分配列表的值太多。
我尝试过修改它,但是当我删除一个值时,列表名列表比选择列表长。
答案 0 :(得分:1)
这被转换为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的开发人员交流中),您似乎希望对每列应用某种计数。但是你不需要MAX/CASE/ROW_NUMBER
,只需为表格连接所有行然后执行它。这会在表的每一列中计算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');