2015-02-23 26 views
12

Cần hàm phân tách sẽ lấy hai tham số, chuỗi để phân tách và dấu tách để tách chuỗi và trả về một bảng có cột Id và dữ liệu. trả về một bảng với các cột Id và dữ liệu. Id cột sẽ chứa chuỗi và cột dữ liệu sẽ chứa dữ liệu của chuỗi. Ví dụ:Tách hàm giá trị bằng dấu phẩy với chuỗi tự động

SELECT*FROM Split('A,B,C,D',',') 

quả nên được ở bên dưới định dạng:

|Id | Data 
-- ---- 
|1 | A | 
|2 | B | 
|3 | C | 
|4 | D | 
+2

Xem [** Chia chuỗi phân cách bằng dấu phẩy đơn thành các hàng trong Oracle **] (https://lalitkumarb.com/2014/12/02/split-comma-delimited-string-into-rows-in-oracle/) –

+0

Cố định liên kết trên, vui lòng xem [** Chia chuỗi phân cách bằng dấu phẩy đơn thành các hàng trong Oracle **] (https://lalitkumarb.wordpress.com/2014/12/02/split-comma-delimited-string-into- hàng-in-oracle /) –

Trả lời

13

Đây là cách bạn có thể tạo ra một bảng như:

SELECT LEVEL AS id, REGEXP_SUBSTR('A,B,C,D', '[^,]+', 1, LEVEL) AS data 
    FROM dual 
CONNECT BY REGEXP_SUBSTR('A,B,C,D', '[^,]+', 1, LEVEL) IS NOT NULL; 

Với một chút tinh chỉnh (ví dụ, thay thế , trong [^,] với một biến), bạn có thể viết một hàm như vậy để trả về một bảng.

4

Nếu bạn cần một chức năng, hãy thử điều này.
Đầu tiên chúng ta sẽ tạo một kiểu:

CREATE OR REPLACE TYPE T_TABLE IS OBJECT 
(
    Field1 int 
    , Field2 VARCHAR(25) 
); 
CREATE TYPE T_TABLE_COLL IS TABLE OF T_TABLE; 
/

Sau đó, chúng tôi sẽ tạo ra các chức năng:

CREATE OR REPLACE FUNCTION TEST_RETURN_TABLE 
RETURN T_TABLE_COLL 
    IS 
     l_res_coll T_TABLE_COLL; 
     l_index number; 
    BEGIN 
     l_res_coll := T_TABLE_COLL(); 
     FOR i IN (
     WITH TAB AS 
      (SELECT '1001' ID, 'A,B,C,D,E,F' STR FROM DUAL 
      UNION 
      SELECT '1002' ID, 'D,E,F' STR FROM DUAL 
      UNION 
      SELECT '1003' ID, 'C,E,G' STR FROM DUAL 
     ) 
     SELECT id, 
      SUBSTR(STR, instr(STR, ',', 1, lvl) + 1, instr(STR, ',', 1, lvl + 1) - instr(STR, ',', 1, lvl) - 1) name 
     FROM 
      (SELECT ',' || STR || ',' AS STR, id FROM TAB 
     ), 
      (SELECT level AS lvl FROM dual CONNECT BY level <= 100 
     ) 
     WHERE lvl <= LENGTH(STR) - LENGTH(REPLACE(STR, ',')) - 1 
     ORDER BY ID, NAME) 
     LOOP 
     IF i.ID = 1001 THEN 
      l_res_coll.extend; 
      l_index := l_res_coll.count; 
      l_res_coll(l_index):= T_TABLE(i.ID, i.name); 
     END IF; 
     END LOOP; 
     RETURN l_res_coll; 
    END; 
    /

Bây giờ chúng ta có thể chọn từ nó:

select * from table(TEST_RETURN_TABLE()); 

Output:

SQL> select * from table(TEST_RETURN_TABLE()); 

    FIELD1 FIELD2 
---------- ------------------------- 
     1001 A 
     1001 B 
     1001 C 
     1001 D 
     1001 E 
     1001 F 

6 rows selected. 

Rõ ràng là bạn cần phải thay thế bit WITH TAB AS... với nơi bạn sẽ nhận được dữ liệu thực tế của mình. CreditCredit

+0

và cả hai loại ur và chức năng hiển thị lỗi biên dịch –

10

Có nhiều tùy chọn. Xem Split single comma delimited string into rows in Oracle

Bạn chỉ cần thêm CẤP trong danh sách lựa chọn như một cột, để có được những chuỗi số để mỗi hàng trả lại. Hoặc, ROWNUM cũng sẽ đủ.

Sử dụng bất kỳ SQL nào dưới đây, bạn có thể đưa chúng vào một FUNCTION.

INSTR trong CONNECT BY khoản:

 
SQL> WITH DATA AS 
    2 (SELECT 'word1, word2, word3, word4, word5, word6' str FROM dual 
    3 ) 
    4 SELECT trim(regexp_substr(str, '[^,]+', 1, LEVEL)) str 
    5 FROM DATA 
    6 CONNECT BY instr(str, ',', 1, LEVEL - 1) > 0 
    7/

STR 
---------------------------------------- 
word1 
word2 
word3 
word4 
word5 
word6 

6 rows selected. 

SQL> 

REGEXP_SUBSTR trong CONNECT BY khoản:

 
SQL> WITH DATA AS 
    2 (SELECT 'word1, word2, word3, word4, word5, word6' str FROM dual 
    3 ) 
    4 SELECT trim(regexp_substr(str, '[^,]+', 1, LEVEL)) str 
    5 FROM DATA 
    6 CONNECT BY regexp_substr(str , '[^,]+', 1, LEVEL) IS NOT NULL 
    7/

STR 
---------------------------------------- 
word1 
word2 
word3 
word4 
word5 
word6 

6 rows selected. 

SQL> 

REGEXP_COUNT trong CONNECT BY khoản:

 
SQL> WITH DATA AS 
    2  (SELECT 'word1, word2, word3, word4, word5, word6' str FROM dual 
    3  ) 
    4  SELECT trim(regexp_substr(str, '[^,]+', 1, LEVEL)) str 
    5  FROM DATA 
    6  CONNECT BY LEVEL 

Sử dụng XMLTABLE

 
SQL> WITH DATA AS 
    2 (SELECT 'word1, word2, word3, word4, word5, word6' str FROM dual 
    3 ) 
    4 SELECT trim(COLUMN_VALUE) str 
    5 FROM DATA, xmltable(('"' || REPLACE(str, ',', '","') || '"')) 
    6/
STR 
------------------------------------------------------------------------ 
word1 
word2 
word3 
word4 
word5 
word6 

6 rows selected. 

SQL> 

Sử dụng MODEL khoản:

 
SQL> WITH t AS 
    2 (
    3   SELECT 'word1, word2, word3, word4, word5, word6' str 
    4   FROM dual) , 
    5 model_param AS 
    6 (
    7   SELECT str AS orig_str , 
    8    ',' 
    9      || str 
10      || ','         AS mod_str , 
11    1            AS start_pos , 
12    Length(str)         AS end_pos , 
13    (Length(str) - Length(Replace(str, ','))) + 1 AS element_count , 
14    0            AS element_no , 
15    ROWNUM          AS rn 
16   FROM t) 
17 SELECT trim(Substr(mod_str, start_pos, end_pos-start_pos)) str 
18 FROM  (
19     SELECT * 
20     FROM model_param MODEL PARTITION BY (rn, orig_str, mod_str) 
21     DIMENSION BY (element_no) 
22     MEASURES (start_pos, end_pos, element_count) 
23     RULES ITERATE (2000) 
24     UNTIL (ITERATION_NUMBER+1 = element_count[0]) 
25     (start_pos[ITERATION_NUMBER+1] = instr(cv(mod_str), ',', 1, cv(element_no)) + 1, 
26     end_pos[iteration_number+1] = instr(cv(mod_str), ',', 1, cv(element_no) + 1))) 
27 WHERE element_no != 0 
28 ORDER BY mod_str , 
29   element_no 
30/

STR 
------------------------------------------ 
word1 
word2 
word3 
word4 
word5 
word6 

6 rows selected. 

SQL> 

Bạn cũng có thể sử dụng DBMS_UTILITY gói được cung cấp bởi Oracle. Nó cung cấp các chương trình con tiện ích khác nhau. Một tiện ích hữu ích như vậy là quy trình COMMA_TO_TABLE, chuyển đổi danh sách tên được phân tách bằng dấu phẩy thành một bảng tên PL/SQL.

đọc DBMS_UTILITY.COMMA_TO_TABLE

5

Oracle cài đặt:

CREATE OR REPLACE FUNCTION split_String(
    i_str IN VARCHAR2, 
    i_delim IN VARCHAR2 DEFAULT ',' 
) RETURN SYS.ODCIVARCHAR2LIST DETERMINISTIC 
AS 
    p_result  SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST(); 
    p_start  NUMBER(5) := 1; 
    p_end   NUMBER(5); 
    c_len CONSTANT NUMBER(5) := LENGTH(i_str); 
    c_ld CONSTANT NUMBER(5) := LENGTH(i_delim); 
BEGIN 
    IF c_len > 0 THEN 
    p_end := INSTR(i_str, i_delim, p_start); 
    WHILE p_end > 0 LOOP 
     p_result.EXTEND; 
     p_result(p_result.COUNT) := SUBSTR(i_str, p_start, p_end - p_start); 
     p_start := p_end + c_ld; 
     p_end := INSTR(i_str, i_delim, p_start); 
    END LOOP; 
    IF p_start <= c_len + 1 THEN 
     p_result.EXTEND; 
     p_result(p_result.COUNT) := SUBSTR(i_str, p_start, c_len - p_start + 1); 
    END IF; 
    END IF; 
    RETURN p_result; 
END; 
/

Query

SELECT ROWNUM AS ID, 
     COLUMN_VALUE AS Data 
FROM TABLE(split_String('A,B,C,D')); 

Output:

ID DATA 
-- ---- 
1 A 
2 B 
3 C 
4 D 
-3

Hãy thử như dưới đây

select 
    split.field(column_name,1,',','"') name1, 
    split.field(column_name,2,',','"') name2 
from table_name 
+0

Đây là Oracle, không phải Sql Server. Xem các thẻ. –

1

Sử dụng chức năng này 'Tách':

CREATE OR REPLACE FUNCTION Split (p_str varchar2) return sys_refcursor is 
v_res sys_refcursor; 

begin 
    open v_res for 
    WITH TAB AS 
    (SELECT p_str STR FROM DUAL) 
    select substr(STR, instr(STR, ',', 1, lvl) + 1, instr(STR, ',', 1, lvl + 1) - instr(STR, ',', 1, lvl) - 1) name 
    from 
    (select ',' || STR || ',' as STR from TAB), 
    (select level as lvl from dual connect by level <= 100) 
    where lvl <= length(STR) - length(replace(STR, ',')) - 1; 

    return v_res; 
    end; 

Bạn không thể sử dụng chức năng này trong lựa chọn công bố như bạn mô tả trong câu hỏi, nhưng tôi hy vọng bạn sẽ tìm thấy nó vẫn hữu ích.

EDIT: Dưới đây là các bước bạn cần thực hiện. 1. Tạo Object: tạo hoặc thay thế loại empy_type như đối tượng (giá trị varchar2 (512)) 2. Tạo Type: tạo hoặc thay thế loại t_empty_type như bảng empy_type 3. Tạo Chức Năng:

CREATE OR REPLACE FUNCTION Split (p_str varchar2) return sms.t_empty_type is 
v_emptype t_empty_type := t_empty_type(); 
v_cnt  number := 0; 
v_res sys_refcursor; 
v_value nvarchar2(128); 
begin 
    open v_res for 
    WITH TAB AS 
    (SELECT p_str STR FROM DUAL) 
    select substr(STR, instr(STR, ',', 1, lvl) + 1, instr(STR, ',', 1, lvl +  1) - instr(STR, ',', 1, lvl) - 1) name 
    from 
    (select ',' || STR || ',' as STR from TAB), 
    (select level as lvl from dual connect by level <= 100) 
    where lvl <= length(STR) - length(replace(STR, ',')) - 1; 


    loop 
    fetch v_res into v_value; 
     exit when v_res%NOTFOUND; 
     v_emptype.extend; 
     v_cnt := v_cnt + 1; 
    v_emptype(v_cnt) := empty_type(v_value); 
    end loop; 
    close v_res; 

    return v_emptype; 
end; 

Sau đó chỉ cần gọi như sau:

SELECT * FROM (TABLE(split('a,b,c,d,g'))) 
0

Hàm này trả về phần thứ n của chuỗi đầu vào MYSTRING. Tham số đầu vào thứ hai là dấu phân cách., SEPARATOR_OF_SUBSTR và tham số thứ ba là Phần thứ N được yêu cầu.

Lưu ý: MYSTRING phải kết thúc bằng dấu phân cách.

create or replace FUNCTION PK_GET_NTH_PART(MYSTRING VARCHAR2,SEPARATOR_OF_SUBSTR VARCHAR2,NTH_PART NUMBER) 
RETURN VARCHAR2 
IS 
NTH_SUBSTR VARCHAR2(500); 
POS1 NUMBER(4); 
POS2 NUMBER(4); 
BEGIN 
IF NTH_PART=1 THEN 
SELECT REGEXP_INSTR(MYSTRING,SEPARATOR_OF_SUBSTR, 1, 1) INTO POS1 FROM DUAL; 
SELECT SUBSTR(MYSTRING,0,POS1-1) INTO NTH_SUBSTR FROM DUAL; 
ELSE 
SELECT REGEXP_INSTR(MYSTRING,SEPARATOR_OF_SUBSTR, 1, NTH_PART-1) INTO POS1 FROM DUAL; 
SELECT REGEXP_INSTR(MYSTRING,SEPARATOR_OF_SUBSTR, 1, NTH_PART) INTO POS2 FROM DUAL; 
SELECT SUBSTR(MYSTRING,POS1+1,(POS2-POS1-1)) INTO NTH_SUBSTR FROM DUAL; 
END IF; 
RETURN NTH_SUBSTR; 
END; 

Hope this helps một số cơ thể, bạn có thể sử dụng chức năng này như thế này trong một vòng lặp để có được tất cả các giá trị tách ra:

SELECT REGEXP_COUNT(MYSTRING, '~', 1, 'i') INTO NO_OF_RECORDS FROM DUAL; 
WHILE NO_OF_RECORDS>0 
LOOP 
    PK_RECORD :=PK_GET_NTH_PART(MYSTRING,'~',NO_OF_RECORDS); 
    -- do some thing 
    NO_OF_RECORDS :=NO_OF_RECORDS-1; 
END LOOP; 

Đây NO_OF_RECORDS, PK_RECORD là các biến temp.

Hy vọng điều này sẽ hữu ích.

Các vấn đề liên quan