[英]PL/SQL dynamic query based on multiple rows
我正在嘗試編寫一個 PL/SQL 腳本來讀取表並根據rule_id
和parameter_id
生成動態查詢。
我的腳本應該根據規則 ID 和參數 ID 從parameter_value
讀取並在動態查詢中使用參數值。
所以我的rules
表看起來像這樣:
這是我的腳本 - 我做錯了什么? 我收到一個錯誤
ORA-01747 無效的 user.table.column、table.column 或列規范
declare
v_rule_id number(10);
v_parameter_id number(10);
v_parameter_value varchar2(100);
v_source_table varchar2(100);
v_lookup_table varhcar2(100);
v_source_column varchar2(100);
v_lookup_column varchar2(100);
v_date varhchar2(100);
v_query varchar2(1000);
BEGIN
FOR RL IN (SELECT RULE_ID FROM RULE)
LOOP
FOR PRM IN (SELECT PARAMETER_ID,PARAMETER_VALUE FROM RULE)
LOOP
IF PRM.PARAM_ID = 1 THEN
v_source_table:= PRM.PARAMETER_VALUE;
ELSIF PRM.PARAM_ID = 2 THEN
V_lookup_table := PRM.PARAMETER_VALUE;
ELSIF PRM.PARAM_ID = 3 THEN
V_source_column := PRM.PARAMETER_VALUE;
ELSIF PRM.PARAM_ID = 4 THEN
V_lookup_column := PRM.PARAMETER_VALUE;
ELSIF PRM.PARAM_ID = 5 THEN
V_date := PRM.PARAMETER_VALUE;
END IF;
v_query := 'SELECT * FROM (SELECT DISTINCT A.' || v_source_column || ', count(*) as count from'|| v_source_table || ' A LEFT JOIN' || V_lookup_table || ' ON A.'||V_source_column ||' = B.'|| V_lookup_column || 'WHERE B.'||V_lookup_table||' IS NULL GROUP BY A.'||V_source_column ||'ORDER BY 2 DESC' );
EXECUTE IMMEDIATE v_query;
END LOOP;
END LOOP;
END;
好吧...調試,您應該會發現問題所在。
dbms_output.put_line
(或像 logger 這樣的日志記錄框架)來檢測您的代碼。享受下面的調試過程!
由於海報提供了屏幕截圖,因此手動創建示例數據。 下次請自己提供此代碼 - 這是您的工作,而不是我們的工作。
CREATE TABLE rule (RULE_ID,PARAMETER_ID,PARAMETER_EXPLANATION,PARAMETER_VALUE) AS
SELECT 1,1,'TABLE_1','A' FROM DUAL UNION ALL
SELECT 1,2,'TABLE_2','B' FROM DUAL UNION ALL
SELECT 1,3,'COLUMN_1','X' FROM DUAL UNION ALL
SELECT 1,4,'COLUMN_2','Y' FROM DUAL UNION ALL
SELECT 1,5,'DATE','20221231' FROM DUAL UNION ALL
SELECT 2,1,'TABLE_1','C' FROM DUAL UNION ALL
SELECT 2,2,'TABLE_2','D' FROM DUAL UNION ALL
SELECT 2,3,'COLUMN_1','Z' FROM DUAL UNION ALL
SELECT 2,4,'COLUMN_2','Q' FROM DUAL UNION ALL
SELECT 2,5,'DATE','20221231' FROM DUAL;
Table RULE created.
運行上面的代碼:
run anonymous pl/sql block
ORA-06550: line 28, column 299:
PLS-00103: Encountered the symbol ")" when expecting one of the following:
* & = - + ; < / > at in is mod remainder not rem
<an exponent (**)> <> or != or ~= >= <= <> and or like like2
like4 likec between || member submultiset
ORA-06550: line 31, column 5:
PLS-00103: Encountered the symbol "LOOP" when expecting one of the following:
;
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
修復第 28 行的錯誤,運行塊
Error report -
ORA-06550: line 6, column 16:
PLS-00201: identifier 'VARHCAR2' must be declared
ORA-06550: line 0, column 1:
PL/SQL: Compilation unit analysis terminated
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
修復第 6 行的錯誤,運行塊
ORA-06550: line 9, column 8:
PLS-00201: identifier 'VARHCHAR2' must be declared
ORA-06550: line 0, column 1:
PL/SQL: Compilation unit analysis terminated
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
修復第 8 行的錯誤,運行塊
Error report -
ORA-06550: line 17, column 8:
PLS-00302: component 'PARAM_ID' must be declared
ORA-06550: line 17, column 1:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
用 PARAMETER_ID 替換出現的 PARAM_ID,運行塊
Error report -
ORA-01747: invalid user.table.column, table.column, or column specification
ORA-06512: at line 29
ORA-06512: at line 29
01747. 00000 - "invalid user.table.column, table.column, or column specification"
*Cause:
*Action:
啊...我們得到了錯誤!
這是給出原始錯誤的代碼:
declare
v_rule_id number(10);
v_parameter_id number(10);
v_parameter_value varchar2(100);
v_source_table varchar2(100);
v_lookup_table varchar2(100);
v_source_column varchar2(100);
v_lookup_column varchar2(100);
v_date varchar2(100);
v_query varchar2(1000);
BEGIN
FOR RL IN (SELECT RULE_ID FROM RULE)
LOOP
FOR PRM IN (SELECT PARAMETER_ID,PARAMETER_VALUE FROM RULE)
LOOP
IF PRM.PARAMETER_ID = 1 THEN
v_source_table:= PRM.PARAMETER_VALUE;
ELSIF PRM.PARAMETER_ID = 2 THEN
V_lookup_table := PRM.PARAMETER_VALUE;
ELSIF PRM.PARAMETER_ID = 3 THEN
V_source_column := PRM.PARAMETER_VALUE;
ELSIF PRM.PARAMETER_ID = 4 THEN
V_lookup_column := PRM.PARAMETER_VALUE;
ELSIF PRM.PARAMETER_ID = 5 THEN
V_date := PRM.PARAMETER_VALUE;
END IF;
v_query := 'SELECT * FROM (SELECT DISTINCT A.' || v_source_column || ', count(*) as count from'|| v_source_table || ' A LEFT JOIN' || V_lookup_table || ' ON A.'||V_source_column ||' = B.'|| V_lookup_column || 'WHERE B.'||V_lookup_table||' IS NULL GROUP BY A.'||V_source_column ||'ORDER BY 2 DESC';
EXECUTE IMMEDIATE v_query;
END LOOP;
END LOOP;
END;
/
現在是時候進行適當的調試了。 注釋掉EXECUTE IMMEDIATE v_query;
並替換添加dbms_output.put_line(v_query);
查看您要執行的操作。 結果:很多行,例如:
SELECT * FROM (SELECT DISTINCT A., count(*) as count fromA A LEFT JOIN ON A. = B.WHERE B. IS NULL GROUP BY A.ORDER BY 2 DESC
SELECT * FROM (SELECT DISTINCT A., count(*) as count fromA A LEFT JOINB ON A. = B.WHERE B.B IS NULL GROUP BY A.ORDER BY 2 DESC
SELECT * FROM (SELECT DISTINCT A.X, count(*) as count fromA A LEFT JOINB ON A.X = B.WHERE B.B IS NULL GROUP BY A.XORDER BY 2 DESC
SELECT * FROM (SELECT DISTINCT A.X, count(*) as count fromA A LEFT JOINB ON A.X = B.YWHERE B.B IS NULL GROUP BY A.XORDER BY 2 DESC
SELECT * FROM (SELECT DISTINCT A.X, count(*) as count fromA A LEFT JOINB ON A.X = B.YWHERE B.B IS NULL GROUP BY A.XORDER BY 2 DESC
SELECT * FROM (SELECT DISTINCT A.X, count(*) as count fromC A LEFT JOINB ON A.X = B.YWHERE B.B IS NULL GROUP BY A.XORDER BY 2 DESC
etc...
sql 語句 (1) 不完整,(2) 關鍵字連接在一起,行數太多。 內循環和外循環都做一個完整的 select。
...一些工作...
最終解決方案:
set serveroutput on size 999999
clear screen
declare
v_rule_id number(10);
v_parameter_id number(10);
v_parameter_value varchar2(100);
v_source_table varchar2(100);
v_lookup_table varchar2(100);
v_source_column varchar2(100);
v_lookup_column varchar2(100);
v_date varchar2(100);
v_query varchar2(1000);
BEGIN
FOR RL IN (SELECT RULE_ID FROM RULE)
LOOP
FOR PRM IN (SELECT PARAMETER_ID,PARAMETER_VALUE FROM RULE WHERE rule_id = rl.rule_id)
LOOP
IF PRM.PARAMETER_ID = 1 THEN
v_source_table:= PRM.PARAMETER_VALUE;
ELSIF PRM.PARAMETER_ID = 2 THEN
V_lookup_table := PRM.PARAMETER_VALUE;
ELSIF PRM.PARAMETER_ID = 3 THEN
V_source_column := PRM.PARAMETER_VALUE;
ELSIF PRM.PARAMETER_ID = 4 THEN
V_lookup_column := PRM.PARAMETER_VALUE;
ELSIF PRM.PARAMETER_ID = 5 THEN
V_date := PRM.PARAMETER_VALUE;
END IF;
END LOOP;
v_query := 'SELECT * FROM (SELECT DISTINCT A.' || v_source_column || ', count(*) as count from '|| v_source_table || ' A LEFT JOIN ' || V_lookup_table || ' ON A.'||V_source_column ||' = B.'|| V_lookup_column || ' WHERE B.'||V_lookup_table||' IS NULL GROUP BY A.'||V_source_column ||' ORDER BY 2 DESC' ;
dbms_output.put_line(v_query);
--EXECUTE IMMEDIATE v_query; --uncomment if all tables exist.
END LOOP;
END;
/
SELECT * FROM (SELECT DISTINCT A.X, count(*) as count from A A LEFT JOIN B ON A.X = B.Y WHERE B.B IS NULL GROUP BY A.X ORDER BY 2 DESC
SELECT * FROM (SELECT DISTINCT A.X, count(*) as count from A A LEFT JOIN B ON A.X = B.Y WHERE B.B IS NULL GROUP BY A.X ORDER BY 2 DESC
SELECT * FROM (SELECT DISTINCT A.X, count(*) as count from A A LEFT JOIN B ON A.X = B.Y WHERE B.B IS NULL GROUP BY A.X ORDER BY 2 DESC
SELECT * FROM (SELECT DISTINCT A.X, count(*) as count from A A LEFT JOIN B ON A.X = B.Y WHERE B.B IS NULL GROUP BY A.X ORDER BY 2 DESC
SELECT * FROM (SELECT DISTINCT A.X, count(*) as count from A A LEFT JOIN B ON A.X = B.Y WHERE B.B IS NULL GROUP BY A.X ORDER BY 2 DESC
SELECT * FROM (SELECT DISTINCT A.Z, count(*) as count from C A LEFT JOIN D ON A.Z = B.Q WHERE B.D IS NULL GROUP BY A.Z ORDER BY 2 DESC
SELECT * FROM (SELECT DISTINCT A.Z, count(*) as count from C A LEFT JOIN D ON A.Z = B.Q WHERE B.D IS NULL GROUP BY A.Z ORDER BY 2 DESC
SELECT * FROM (SELECT DISTINCT A.Z, count(*) as count from C A LEFT JOIN D ON A.Z = B.Q WHERE B.D IS NULL GROUP BY A.Z ORDER BY 2 DESC
SELECT * FROM (SELECT DISTINCT A.Z, count(*) as count from C A LEFT JOIN D ON A.Z = B.Q WHERE B.D IS NULL GROUP BY A.Z ORDER BY 2 DESC
SELECT * FROM (SELECT DISTINCT A.Z, count(*) as count from C A LEFT JOIN D ON A.Z = B.Q WHERE B.D IS NULL GROUP BY A.Z ORDER BY 2 DESC
如果每個 select 語句中的所有表都實際存在於數據庫中,這將成功執行。
如果您可以在沒有 PL/SQL 的情況下獲得您的查詢 - 只是簡單的 SQL 會怎么樣?
假設您的兩個表如下所示:
CREATE TABLE
A_TBL_1 (ID, TXT, SOME_COL, COL_1_T1, DATE_T1) AS
(
SELECT 1, 'TEXT for ID 1', 'Something else 1 in tbl_1', 'X', To_Date('20221231', 'yyyymmdd') From Dual Union All
SELECT 2, 'TEXT for ID 2', 'Something else 2 in tbl_1', 'Y', To_Date('20221231', 'yyyymmdd') From Dual Union All
SELECT 3, 'TEXT for ID 3', 'Something else 3 in tbl_1', 'Z', To_Date('20221231', 'yyyymmdd') From Dual
);
CREATE TABLE
A_TBL_2 (ID, TXT, SOME_COL, COL_1_T2) AS
(
SELECT 11, 'TEXT for ID 11', 'Something else 11 in tbl_2', 'X' From Dual Union All
SELECT 12, 'TEXT for ID 12', 'Something else 12 in tbl_2', 'Y' From Dual Union All
SELECT 13, 'TEXT for ID 13', 'Something else 13 in tbl_2', 'X' From Dual
);
...並且您的規則設置如下
CREATE TABLE
A_RULE_TBL (RULE_ID, PAR_ID, PAR_EXPL, PAR_VAL) AS
(
SELECT 1, 1, 'A_TBL_1', 'a' FROM DUAL UNION ALL
SELECT 1, 2, 'A_TBL2', 'b' FROM DUAL UNION ALL
SELECT 1, 3, 'COL_1_T1', 'X' FROM DUAL UNION ALL
SELECT 1, 4, 'COL_1_T2', 'X' FROM DUAL UNION ALL
SELECT 1, 5, 'DATE_T1', '20221231' FROM DUAL UNION ALL
SELECT 2, 1, 'A_TBL_1', 'a' FROM DUAL UNION ALL
SELECT 2, 2, 'A_TBL_2', 'b' FROM DUAL UNION ALL
SELECT 2, 3, 'COL_1_T1', 'Y' FROM DUAL UNION ALL
SELECT 2, 4, 'COL_1_T2', 'Y' FROM DUAL UNION ALL
SELECT 2, 5, 'DATE_T1', '20221231' FROM DUAL
);
如果我們 Pivot 並使用 CTE(命名參數)反透視規則_
WITH
params AS
( Select *
From A_RULE_TBL
PIVOT (
Max(CASE WHEN PAR_ID = 1 THEN PAR_EXPL END) "SRC_TBL",
Max(CASE WHEN PAR_ID = 2 THEN PAR_EXPL END) "LKP_TBL",
Max(CASE WHEN PAR_ID = 3 THEN PAR_EXPL END) "SRC_COL",
Max(CASE WHEN PAR_ID = 4 THEN PAR_EXPL END) "LKP_COL",
Max(CASE WHEN PAR_ID = 5 THEN PAR_EXPL END) "DATE",
--
Max(CASE WHEN PAR_ID = 1 THEN PAR_VAL END) "SRC_TBL_VAL",
Max(CASE WHEN PAR_ID = 2 THEN PAR_VAL END) "LKP_TBL_VAL",
Max(CASE WHEN PAR_ID = 3 THEN PAR_VAL END) "SRC_COL_VAL",
Max(CASE WHEN PAR_ID = 4 THEN PAR_VAL END) "LKP_COL_VAL",
Max(CASE WHEN PAR_ID = 5 THEN PAR_VAL END) "DATE_VAL"
FOR RULE_ID IN(1 "ID1", 2 "ID2") )
UNPIVOT( (SRC_TBL, SRC_COL, LKP_TBL, LKP_COL, A_DATE, SRC_TBL_VAL, SRC_COL_VAL, LKP_TBL_VAL, LKP_COL_VAL, DATE_VAL)
FOR RULE_ID
IN (
(ID1_SRC_TBL, ID1_SRC_COL, ID1_LKP_TBL, ID1_LKP_COL, ID1_DATE, ID1_SRC_TBL_VAL, ID1_SRC_COL_VAL, ID1_LKP_TBL_VAL, ID1_LKP_COL_VAL, ID1_DATE_VAL ) as 1,
(ID2_SRC_TBL, ID2_SRC_COL, ID2_LKP_TBL, ID2_LKP_COL, ID2_DATE, ID2_SRC_TBL_VAL, ID2_SRC_COL_VAL, ID2_LKP_TBL_VAL, ID2_LKP_COL_VAL, ID2_DATE_VAL ) as 2 )
)
ORDER BY RULE_ID
)
--
-- R e s u l t
-- RULE_ID SRC_TBL SRC_COL LKP_TBL LKP_COL A_DATE SRC_TBL_VAL SRC_COL_VAL LKP_TBL_VAL LKP_COL_VAL DATE_VAL
-- ---------- -------- -------- -------- -------- -------- ----------- ----------- ----------- ----------- --------
-- 1 A_TBL_1 COL_1_T1 A_TBL_2 COL_1_T2 DATE_T1 a X b X 20221231
-- 2 A_TBL_1 COL_1_T1 A_TBL_2 COL_1_T2 DATE_T1 a Y b Y 20221231
生成的數據集包含構建不同 sql 命令所需的一切。 這里對於 RULE_ID = 1 將有 SQL 用於左連接表和選擇不匹配的行。 對於 RULE_ID = 2 匹配的行。
SELECT
'Select ' || SRC_TBL_VAL || '.' || SRC_COL || ', Count(*) "CNT" ' || Chr(10) ||
'From ' || SRC_TBL || ' ' || SRC_TBL_VAL || ' ' || Chr(10) ||
'Left Join ' || LKP_TBL || ' ' || LKP_TBL_VAL || ' ON(' || LKP_TBL_VAL || '.' || LKP_COL || ' = ' || SRC_TBL_VAL || '.' || SRC_COL || ')' || Chr(10) ||
'Where ' || LKP_TBL_VAL || '.' || LKP_COL || ' Is ' || CASE RULE_ID WHEN 2 THEN 'Not' ELSE '' END || ' Null ' || Chr(10) ||
'Group By ' || SRC_TBL_VAL || '.' || SRC_COL || ' ' || Chr(10) ||
'Order By Count(*) DESC' "SQL_COMMANDS"
FROM params
ORDER BY RULE_ID
/* R e s u l t :
SQL_COMMANDS
--------------------------------------------------
Select a.COL_1_T1, Count(*) "CNT"
From A_TBL_1 a
Left Join A_TBL_2 b ON(b.COL_1_T2 = a.COL_1_T1)
Where b.COL_1_T2 Is Null
Group By a.COL_1_T1
Order By Count(*) DESC
Select a.COL_1_T1, Count(*) "CNT"
From A_TBL_1 a
Left Join A_TBL_2 b ON(b.COL_1_T2 = a.COL_1_T1)
Where b.COL_1_T2 Is Not Null
Group By a.COL_1_T1
Order By Count(*) DESC
*/
如果針對上述示例數據運行第一個查詢,結果如下:
-- COL_1_T1 CNT
-- -------- ----------
-- Z 1
...而第二個結果為:
-- COL_1_T1 CNT
-- -------- ----------
-- X 2
-- Y 1
您可以 select 一些或所有其他列,您可以構造具有不同連接和條件、分組、排序等的 sql 命令...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.