【问题标题】:How to write a dynamic SQL code in Teradata?如何在 Teradata 中编写动态 SQL 代码?
【发布时间】:2017-06-11 16:36:30
【问题描述】:

我正在尝试转换此代码(它接受列名作为输入,对输入列进行计算并将数据插入表中)。现在我知道我们不能通过存储的过程或宏传递表/列名称,我开始知道我们可以通过动态 SQL 来完成。我不确定语法应该如何,因为我找不到一个清晰易懂的例子。以下是我需要转换的代码:

INSERT INTO PROD_CE_WORK_SPACE.NPVAZ_CVM_CHECK_TEST_CASE_5

                    SELECT 
                                'DURATION_CELL_CURR' AS COLMN,
                                PW_END_DATE,
                                'ACPT' AS TAB,
                                MIN(DURATION_CELL_CURR) AS PER_MIN,
                                MIN(CASE WHEN SEQNUM / 0.25 >= CNT THEN DURATION_CELL_CURR END) AS PER_25,
                                MIN(CASE WHEN SEQNUM / 0.50 >= CNT THEN DURATION_CELL_CURR END) AS PER_50,
                                MIN(CASE WHEN SEQNUM / 0.75 >= CNT THEN DURATION_CELL_CURR END) AS PER_75,
                                MAX(DURATION_CELL_CURR) AS PER_MAX
                    FROM (
                                SELECT PC.*,
                                 ROW_NUMBER() OVER (ORDER BY DURATION_CELL_CURR) AS SEQNUM,
                                 COUNT(*) OVER () AS CNT
                                  FROM PROD_EXP_DL_CVM.ACPT_PROD_CVM PC
                                  WHERE PC.PW_END_DATE =  '2017-01-17'
                                )A
                                GROUP BY 1,2,3

UNION ALL

                    SELECT 
                                'DURATION_CELL_CURR' AS COLMN,
                                PW_END_DATE,
                                'PROD' AS TAB,
                                MIN(DURATION_CELL_CURR) AS PER_MIN,
                                MIN(CASE WHEN SEQNUM / 0.25 >= CNT THEN DURATION_CELL_CURR END) AS PER_25,
                                MIN(CASE WHEN SEQNUM / 0.50 >= CNT THEN DURATION_CELL_CURR END) AS PER_50,
                                MIN(CASE WHEN SEQNUM / 0.75 >= CNT THEN DURATION_CELL_CURR END) AS PER_75,
                                MAX(DURATION_CELL_CURR) AS PER_MAX
                    FROM (
                                SELECT PC.*,
                                 ROW_NUMBER() OVER (ORDER BY DURATION_CELL_CURR) AS SEQNUM,
                                 COUNT(*) OVER () AS CNT
                                  FROM PROD_EXP_DL_CVM.PROD_CVM PC
                                  WHERE PC.PW_END_DATE =  '2017-01-17'
                                )B
                                GROUP BY 1,2,3

下面是我对它在动态SQL中转换的理解:

REPLACE PROCEDURE PROD_CE_WORK_SPACE.NPVAZ_CVM_CHECK_TEST_CASE (IN COL CHAR(50))
(
BEGIN REQUEST
CALL DBC.SYSEXECSQL
('
INSERT INTO PROD_CE_WORK_SPACE.NPVAZ_CVM_CHECK_TEST_CASE_5
                            SELECT
                            '||COL||' AS COLMN,
                            PW_END_DATE,
                            ''ACPT'' AS TAB,
                            MIN( '||COL||') AS PER_MIN,
                            MIN(CASE WHEN SEQNUM / 0.25 >= CNT THEN  '||COL||' END) AS PER_25,
                            MIN(CASE WHEN SEQNUM / 0.50 >= CNT THEN  '||COL||' END) AS PER_50,
                            MIN(CASE WHEN SEQNUM / 0.75 >= CNT THEN  '||COL||' END) AS PER_75,
                            MAX( '||COL||') AS PER_MAX
                            FROM (
                                        SELECT PC.*,
                                         ROW_NUMBER() OVER (ORDER BY  '||COL||') AS SEQNUM,
                                         COUNT(*) OVER () AS CNT
                                          FROM PROD_EXP_DL_CVM.ACPT_PROD_CVM PC
                                          WHERE PC.PW_END_DATE =  '2017-01-17'
                                         )A
                            GROUP BY 1,2,3

            UNION ALL

                            SELECT 
                            '||COL||' AS COLMN,
                            PW_END_DATE,
                            ''PROD'' AS TAB,
                            MIN( '||COL||') AS PER_MIN,
                            MIN(CASE WHEN SEQNUM / 0.25 >= CNT THEN  '||COL||' END) AS PER_25,
                            MIN(CASE WHEN SEQNUM / 0.50 >= CNT THEN  '||COL||' END) AS PER_50,
                            MIN(CASE WHEN SEQNUM / 0.75 >= CNT THEN  '||COL||' END) AS PER_75,
                            MAX( '||COL||') AS PER_MAX
                            FROM (
                                SELECT PC.*,
                                 ROW_NUMBER() OVER (ORDER BY  '||COL||') AS SEQNUM,
                                 COUNT(*) OVER () AS CNT
                                  FROM PROD_EXP_DL_CVM.PROD_CVM PC
                                  WHERE PC.PW_END_DATE =  '2017-01-17'
                                )B
                          GROUP BY 1,2,3
')

END REQUEST;
);

我知道在此代码准备好运行之前,我必须解决许多错误。所以我得到的第一个错误如下:

谁能帮我解决这个问题。我必须计算 60 多个这样的列的分位数分布,手动操作是很疯狂的。 非常感激。 皮尤什

【问题讨论】:

    标签: sql stored-procedures dynamic teradata


    【解决方案1】:

    应删除在BEGIN 之前开始的一对括号,并且字符串周围的所有单引号(包括日期)都必须加倍:

    REPLACE PROCEDURE NPVAZ_CVM_CHECK_TEST_CASE (IN COL CHAR(50))
    BEGIN
    CALL DBC.SYSEXECSQL
    ('
    INSERT INTO PROD_CE_WORK_SPACE.NPVAZ_CVM_CHECK_TEST_CASE_5
                                SELECT
                                '||COL||' AS COLMN,
                                PW_END_DATE,
                                ''ACPT'' AS TAB,
                                MIN( '||COL||') AS PER_MIN,
                                MIN(CASE WHEN SEQNUM / 0.25 >= CNT THEN  '||COL||' END) AS PER_25,
                                MIN(CASE WHEN SEQNUM / 0.50 >= CNT THEN  '||COL||' END) AS PER_50,
                                MIN(CASE WHEN SEQNUM / 0.75 >= CNT THEN  '||COL||' END) AS PER_75,
                                MAX( '||COL||') AS PER_MAX
                                FROM (
                                            SELECT PC.*,
                                             ROW_NUMBER() OVER (ORDER BY  '||COL||') AS SEQNUM,
                                             COUNT(*) OVER () AS CNT
                                              FROM PROD_EXP_DL_CVM.ACPT_PROD_CVM PC
                                              WHERE PC.PW_END_DATE = DATE ''2017-01-17''
                                             )A
                                GROUP BY 1,2,3
    
                UNION ALL
    
                                SELECT 
                                '||COL||' AS COLMN,
                                PW_END_DATE,
                                ''PROD'' AS TAB,
                                MIN( '||COL||') AS PER_MIN,
                                MIN(CASE WHEN SEQNUM / 0.25 >= CNT THEN  '||COL||' END) AS PER_25,
                                MIN(CASE WHEN SEQNUM / 0.50 >= CNT THEN  '||COL||' END) AS PER_50,
                                MIN(CASE WHEN SEQNUM / 0.75 >= CNT THEN  '||COL||' END) AS PER_75,
                                MAX( '||COL||') AS PER_MAX
                                FROM (
                                    SELECT PC.*,
                                     ROW_NUMBER() OVER (ORDER BY  '||COL||') AS SEQNUM,
                                     COUNT(*) OVER () AS CNT
                                      FROM PROD_EXP_DL_CVM.PROD_CVM PC
                                      WHERE PC.PW_END_DATE =  DATE ''2017-01-17''
                                    )B
                              GROUP BY 1,2,3
    ');
    
    END;
    

    【讨论】:

    • 嗨@dnoeth。我可以成功运行您的版本,但我认为我没有在SELECT '||COL||' AS COLMN, 正确处理列名,因此我得到以下结果:stackoverflow.com/questions/41875937/… 在 列
    • 我正在使用''||COL||'' AS COLMN 来查看这是否会修改结果。
    • @PiyushVerma:引用参数应该可以解决它。
    • 在select语句中还是在call语句中?将'||COL||' AS COLMN 更改为'||'COL'||' AS COLMN
    • @PiyushVerma:实际上它应该是SELECT ''''||COL||''' AS COLMN, PW_END_DATE, ''ACPT'' AS TAB, ...',在结果字符串中它必须是a'COL'。您最好先将 SELECT 分配给一个变量,您可以轻松地将其作为 OUT-var 返回,而不是执行并检查结果字符串是否有效。
    猜你喜欢
    • 2010-11-27
    • 2012-12-03
    • 2016-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-17
    • 2014-03-25
    相关资源
    最近更新 更多