我有一个查询,我需要查看是否可以转换为Oracle
WITH Cte
AS (SELECT cast('<S>' + replace(replace(N'$(AppServers)', ';', ','), ',', '</S><S>') + '</S>' AS XML) AS Servers)
INSERT INTO INSTANCE
(INSTANCE_ID,
SERVER_NAME,
INSTANCE_IDENTIFIER,
IDENTIFIER_PREFIX)
SELECT ROW_NUMBER() OVER (ORDER BY SERVER_NAME) - 1,
SERVER_NAME,
NULL,
0
FROM (SELECT DISTINCT upper(Split.Server.value('.', 'VARCHAR(100)')) AS SERVER_NAME
FROM Cte
CROSS apply Servers.nodes('/S') Split(Server)) Servers
ORDER BY SERVER_NAME;
我知道Oracle 11g专门支持XML,但我无法找到解决这个问题的方法。非常感谢任何帮助。
如果$(AppServers)
替换为foo,bar;baz,wibble
,则上面的查询会插入以下内容。
+-------------+-------------+---------------------+-------------------+
| INSTANCE_ID | SERVER_NAME | INSTANCE_IDENTIFIER | IDENTIFIER_PREFIX |
+-------------+-------------+---------------------+-------------------+
| 0 | BAR | NULL | 0 |
| 1 | BAZ | NULL | 0 |
| 2 | FOO | NULL | 0 |
| 3 | WIBBLE | NULL | 0 |
+-------------+-------------+---------------------+-------------------+
XML代码就是将分隔(通过逗号或半冒号)字符串拆分为行。然后将值设置为大写并删除重复项,然后按字母顺序排序以获取Instance_Id。
答案 0 :(得分:0)
经过一番研究,我设法复制最终结果(不是这样),如下所示:
DECLARE
L_INPUT VARCHAR2(4000) := 'foo,bar,baz,wibble';
L_COUNT BINARY_INTEGER;
L_ARRAY DBMS_UTILITY.LNAME_ARRAY;
BEGIN
DBMS_UTILITY.COMMA_TO_TABLE(LIST => REGEXP_REPLACE(L_INPUT, '(^|,)', '\1x'), TABLEN => L_COUNT, TAB => L_ARRAY);
DBMS_OUTPUT.PUT_LINE(L_COUNT);
FOR I IN 1 .. L_COUNT
LOOP
DBMS_OUTPUT.PUT_LINE('Element ' || TO_CHAR(I) || ' of array contains: ' || SUBSTR(L_ARRAY(I), 2));
INSERT INTO INSTANCE VALUES (I, SUBSTR(L_ARRAY(I), 2), NULL, 0);
COMMIT;
END LOOP;
END;
一个问题是我不知道如何让它接受逗号,分号或更多字符作为分隔符(例如,Le pipe sign&#39; |&#39;)
答案 1 :(得分:0)
来自dbforums.com的@LKBrwn_DBA为此创建了一个解决方案:
CREATE OR REPLACE TYPE Csvparserreturn AS TABLE OF VARCHAR2 ( 4000 );
/
CREATE OR REPLACE FUNCTION Csvparser ( P_Dat IN CLOB, P_Hdr IN VARCHAR2 )
RETURN Csvparserreturn
AS
L_Debug CHAR ( 1 ) := 'F';
L_Hdr VARCHAR2 ( 4000 );
L_Dat CLOB;
L_Wrk CLOB;
L_Recsep CHAR ( 1 ) := CHR ( 9 );
O_Hdr VARCHAR2 ( 4000 );
O_Dat CLOB;
O_Data_Tab Csvparserreturn := Csvparserreturn ( );
TYPE Text_Array IS TABLE OF VARCHAR2 ( 4000 )
INDEX BY PLS_INTEGER;
L_Hdr_Array Text_Array;
L_Dat_Array Text_Array;
L_Fld_Array Text_Array;
L_Elm_Array Text_Array;
L_Val_Array Text_Array;
L_Hdr_Count PLS_INTEGER;
L_Dat_Count PLS_INTEGER;
L_Fld_Count PLS_INTEGER;
I PLS_INTEGER;
J PLS_INTEGER;
K PLS_INTEGER;
L PLS_INTEGER;
N PLS_INTEGER;
PROCEDURE Print_Line ( P_Text VARCHAR2 )
IS
BEGIN
IF L_Debug = 'T'
THEN
DBMS_OUTPUT.Put_Line ( P_Text );
END IF;
END;
FUNCTION Parse_Csv ( P_Text CLOB, P_Delim VARCHAR2 DEFAULT ',' )
RETURN Text_Array
IS
Wk_Array Text_Array;
BEGIN
N := 1;
L := 1;
K := 1;
WHILE 1 = 1
LOOP
L := INSTR ( SUBSTR ( P_Text || P_Delim, K + 1 )
, P_Delim );
EXIT WHEN K >= LENGTH ( P_Text );
Wk_Array ( N ) := SUBSTR ( P_Text, K, L );
N := N + 1;
K := K + L + 1;
END LOOP;
RETURN Wk_Array;
END;
BEGIN
L_Hdr := P_Hdr;
L_Dat := P_Dat;
L_Hdr_Array := Parse_Csv ( L_Hdr );
L_Hdr_Count := L_Hdr_Array.COUNT;
Print_Line ( 'Hdr#' || L_Hdr_Count );
O_Hdr := '';
FOR I IN 1 .. L_Hdr_Count
LOOP
O_Hdr := O_Hdr || L_Hdr_Array ( I ) || L_Recsep;
Print_Line ( 'Elm#' || I || ': ' || L_Hdr_Array ( I ) );
END LOOP;
L_Wrk := SUBSTR ( L_Dat, 2, LENGTH ( L_Dat ) - 2 );
SELECT REPLACE ( L_Wrk, '),(', L_Recsep ) || L_Recsep INTO L_Wrk FROM DUAL;
Print_Line ( 'Dat: ' || L_Wrk );
L_Dat_Array := Parse_Csv ( L_Wrk, L_Recsep );
L_Dat_Count := L_Dat_Array.COUNT;
O_Data_Tab.EXTEND;
O_Data_Tab ( 1 ) := O_Hdr;
FOR I IN 1 .. L_Dat_Count
LOOP
L_Fld_Array := Parse_Csv ( L_Dat_Array ( I ) );
L_Fld_Count := L_Fld_Array.COUNT;
Print_Line ( 'Rec#' || I || ': ' || L_Dat_Array ( I ) || ' Flds:' || L_Fld_Count );
O_Dat := '';
FOR J IN 1 .. L_Hdr_Count
LOOP
K := 0;
FOR N IN 1 .. L_Fld_Count
LOOP
IF L_Hdr_Array ( J ) =
SUBSTR ( L_Fld_Array ( N )
, 1, LENGTH ( L_Hdr_Array ( J ) ) )
THEN
K := N;
CONTINUE;
END IF;
END LOOP;
IF K > 0
THEN
L := INSTR ( L_Fld_Array ( K ), '=' );
L_Elm_Array ( J ) := SUBSTR ( L_Fld_Array ( K ), 1, L - 1 );
L_Val_Array ( J ) := SUBSTR ( L_Fld_Array ( K ), L + 1 );
ELSE
L_Elm_Array ( J ) := '#N/A';
L_Val_Array ( J ) := '#N/A';
END IF;
Print_Line ( 'Element ' || TO_CHAR ( J ) || '.' || L_Hdr_Array ( J ) || '=' || L_Val_Array ( J ) );
O_Dat := O_Dat || L_Val_Array ( J ) || L_Recsep;
END LOOP;
Print_Line ( 'Out#' || TO_CHAR ( I ) || '=' || O_Dat );
O_Data_Tab.EXTEND;
O_Data_Tab ( I + 1 ) := O_Dat;
END LOOP;
RETURN O_Data_Tab;
END;
/
以下是用法:
DECLARE
Out_Data Csvparserreturn := Csvparserreturn ( );
X_Hdr VARCHAR2 ( 4000 ) := 'Directory,ID,Location,UserName,Password,Selector';
X_Dat CLOB := '(Directory=Voice Active Directory A,ID=VT-AD1,Location=Canada,UserName=admin,Password=passw0rd,Selector=AD1),(Directory=Voice Active Directory B,ID=VT-AD2,Location=https://beta-proxy.voice.com/VTadp/Proxy/[/url],UserName=admin,Password=passw0rd,Selector=AD2),(Directory=Voice Active Directory C,ID=VT-AD3,Location=https://final-proxy.voice.com/VTadp/Proxy/,UserName=admin,Password=passw0rd)';
BEGIN
Out_Data := Csvparser ( X_Dat, X_Hdr );
FOR I IN Out_Data.FIRST .. Out_Data.LAST
LOOP
DBMS_OUTPUT.Put_Line ( 'Rec# ' || TO_CHAR ( I, 'FM000.' ) || Out_Data ( I ) );
END LOOP;
END;
/