问题
I am trying to convert this code (which accepts a column name as input, does calculations on the input column and inserts data into a table). Now that I know that we can't pass table/column names through a stored proc or macro, I came to know that we can do it through a dynamic SQL. I am not sure how the syntax should be as I could not find a clear and easy example. Below is my code which needs to be converted:
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
Below is my understanding of its conversion in dynamic 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;
);
I understand I have to resolve many errors before this code is run-ready. So one of the first errors I am getting is below:
Can anyone please help me with this. I have to calculate quantile distribution of 60+ such columns which doing manually is insane. Much appreciated. Piyush
回答1:
The pair of parens starting before the BEGIN
should be removed and all single quotes around strings including the dates must be doubled:
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;
来源:https://stackoverflow.com/questions/41869526/how-to-write-a-dynamic-sql-code-in-teradata