ओरेकल में कई पंक्तियों में स्ट्रिंग को विभाजित करना


104

मुझे पता है कि यह कुछ हद तक PHP और MYSQL के साथ उत्तर दिया गया है, लेकिन मैं सोच रहा था कि क्या कोई मुझे Oracle 10g (अधिमानतः) और 11g में कई पंक्तियों में एक स्ट्रिंग (अल्पविराम सीमांकित) को विभाजित करने का सबसे सरल दृष्टिकोण सिखा सकता है।

तालिका इस प्रकार है:

Name | Project | Error 
108    test      Err1, Err2, Err3
109    test2     Err1

मैं निम्नलिखित बनाना चाहता हूं:

Name | Project | Error
108    Test      Err1
108    Test      Err2 
108    Test      Err3 
109    Test2     Err1

मैंने स्टैक के चारों ओर कुछ संभावित समाधान देखे हैं, हालांकि वे केवल एक कॉलम के लिए जिम्मेदार होते हैं (अल्पविराम द्वारा सीमांकित स्ट्रिंग)। किसी भी तरह की सहायता का स्वागत किया जाएगा।


2
उदाहरण के लिए REGEXP, XMLTABLEऔर MODELक्लॉज का उपयोग करते हुए , Oracle SQL
ललित कुमार बी

जवाबों:


121

यह एक बेहतर तरीका हो सकता है (regexp के साथ भी और इससे कनेक्ट करें):

with temp as
(
    select 108 Name, 'test' Project, 'Err1, Err2, Err3' Error  from dual
    union all
    select 109, 'test2', 'Err1' from dual
)
select distinct
  t.name, t.project,
  trim(regexp_substr(t.error, '[^,]+', 1, levels.column_value))  as error
from 
  temp t,
  table(cast(multiset(select level from dual connect by  level <= length (regexp_replace(t.error, '[^,]+'))  + 1) as sys.OdciNumberList)) levels
order by name

संपादित करें : यहाँ क्वेरी का स्पष्टीकरण एक सरल (जैसा कि, "गहराई में नहीं है") है।

  1. length (regexp_replace(t.error, '[^,]+')) + 1regexp_replaceकिसी भी चीज को मिटाने के लिए उपयोग करता है जो कि इस मामले में सीमांकक (अल्पविराम) नहीं है और length +1कितने तत्व (त्रुटियां) हैं।
  2. 1 से लेकर कुल त्रुटियों की बढ़ती संख्या के साथ स्तंभ बनाने के लिए select level from dual connect by level <= (...)एक पदानुक्रमित क्वेरी का उपयोग करता है ।

    पूर्वावलोकन:

    select level, length (regexp_replace('Err1, Err2, Err3', '[^,]+'))  + 1 as max 
    from dual connect by level <= length (regexp_replace('Err1, Err2, Err3', '[^,]+'))  + 1
    
  3. table(cast(multiset(.....) as sys.OdciNumberList)) oracle प्रकारों की कुछ कास्टिंग करता है।
    • cast(multiset(.....)) as sys.OdciNumberListरूपांतरण एकाधिक संग्रहों (मूल डेटा सेट में प्रत्येक पंक्ति के लिए एक संग्रह) नंबर की एक एकल संग्रह, OdciNumberList में।
    • table()समारोह एक resultset में एक संग्रह बदल देती है।
  4. FROMबिना किसी जुड़ाव के, अपने डेटासेट और मल्टीसेट के बीच एक क्रॉस जॉइन बनाता है । नतीजतन, 4 मैचों के साथ सेट किए गए डेटा में एक पंक्ति 4 बार दोहराएगी (कॉलम में बढ़ती संख्या के साथ "column_valp")।

    पूर्वावलोकन:

    select * from 
    temp t,
    table(cast(multiset(select level from dual connect by  level <= length (regexp_replace(t.error, '[^,]+'))  + 1) as sys.OdciNumberList)) levels
    
  5. trim(regexp_substr(t.error, '[^,]+', 1, levels.column_value))के column_valueलिए nth_appearance / ocurrence पैरामीटर के रूप में उपयोग करता है regexp_substr
  6. आप t.name, t.projectआसान दृश्य के लिए अपने डेटा सेट ( उदाहरण के रूप में) से कुछ अन्य कॉलम जोड़ सकते हैं ।

Oracle डॉक्स के लिए कुछ संदर्भ:


7
सावधान रहें! '[^,]+'स्ट्रिंग को पार्स करने के लिए प्रारूप का रीगेक्स सूची में एक अशक्त तत्व होने पर सही आइटम वापस नहीं करता है। अधिक जानकारी के लिए यहां देखें: stackoverflow.com/questions/31464275/…
Gary_W

13
11g के बाद से आप regexp_count(t.error, ',')इसके बजाय उपयोग कर सकते हैं length (regexp_replace(t.error, '[^,]+')), जिससे एक और प्रदर्शन में सुधार हो सकता है
antefan Oravec

1
"सामान्य" कनेक्ट के साथ 485 सेकंड। इस तरह 0.296 सेकंड। आपने धमाल मचाया! अब मुझे केवल यह समझना है कि यह कैसे काम करता है। :-)
बॉब जार्विस -

@BusJarvis ने यह समझाने के लिए एक संपादन जोड़ा कि वह क्या करता है। वर्तनी / व्याकरण सुधार का स्वागत है।
नेफ्रियो

"स्वीकृत उत्तर में खराब प्रदर्शन है" - इस विषय में स्वीकृत उत्तर क्या है? कृपया अन्य पोस्ट को संदर्भित करने के लिए लिंक का उपयोग करें।
0xdb

28

नियमित अभिव्यक्ति एक अद्भुत बात है :)

with temp as  (
       select 108 Name, 'test' Project, 'Err1, Err2, Err3' Error  from dual
       union all
       select 109, 'test2', 'Err1' from dual
     )

SELECT distinct Name, Project, trim(regexp_substr(str, '[^,]+', 1, level)) str
  FROM (SELECT Name, Project, Error str FROM temp) t
CONNECT BY instr(str, ',', 1, level - 1) > 0
order by Name

1
नमस्ते क्या आप मुझे स्पष्ट कर सकते हैं कि उपरोक्त क्वेरी डुप्लिकेट पंक्तियाँ क्यों देती है यदि मैंने क्वेरी में अलग कीवर्ड का उपयोग नहीं किया है
Jagadeesh G

2
वह क्वेरी @JagadeeshG के कारण अनुपयोगी है, विशेष रूप से विशाल तालिकाओं पर।
माइकल-ओ

3
बहुत धीमी गति से, नीचे एक बेहतर जवाब है
मोरेफॉफी

धीमापन का कारण यह है कि Names का हर संयोजन जुड़ा हुआ है, जिसे यदि आप हटाते हैं तो देखा जा सकता है distinct। दुर्भाग्य से क्लॉज के कारणों and Name = prior Nameको जोड़ना । connect byORA-01436: CONNECT BY loop in user data
मिक्स

आप (या जो भी प्राथमिक कुंजी हो सकती है) ORA-01436को जोड़कर त्रुटि से बच सकते हैंAND name = PRIOR name AND PRIOR SYS_GUID() IS NOT NULL
डेविड फेबर

28

नीचे दो के बीच एक बड़ा अंतर है:

  • एक सीमांकित स्ट्रिंग को विभाजित करना
  • एक तालिका में कई पंक्तियों के लिए सीमांकित स्ट्रिंग्स को विभाजित करना।

यदि आप पंक्तियों को प्रतिबंधित नहीं करते हैं, तो कनेक्ट बाइ क्लॉज कई पंक्तियों का उत्पादन करेगा और वांछित आउटपुट नहीं देगा।

रेगुलर एक्सप्रेशंस के अलावा , कुछ अन्य विकल्प उपयोग कर रहे हैं:

  • XMLTable
  • मॉडल खंड

सेट अप

SQL> CREATE TABLE t (
  2    ID          NUMBER GENERATED ALWAYS AS IDENTITY,
  3    text        VARCHAR2(100)
  4  );

Table created.

SQL>
SQL> INSERT INTO t (text) VALUES ('word1, word2, word3');

1 row created.

SQL> INSERT INTO t (text) VALUES ('word4, word5, word6');

1 row created.

SQL> INSERT INTO t (text) VALUES ('word7, word8, word9');

1 row created.

SQL> COMMIT;

Commit complete.

SQL>
SQL> SELECT * FROM t;

        ID TEXT
---------- ----------------------------------------------
         1 word1, word2, word3
         2 word4, word5, word6
         3 word7, word8, word9

SQL>

XMLTABLE का उपयोग करना :

SQL> SELECT id,
  2         trim(COLUMN_VALUE) text
  3  FROM t,
  4    xmltable(('"'
  5    || REPLACE(text, ',', '","')
  6    || '"'))
  7  /

        ID TEXT
---------- ------------------------
         1 word1
         1 word2
         1 word3
         2 word4
         2 word5
         2 word6
         3 word7
         3 word8
         3 word9

9 rows selected.

SQL>

मॉडल खंड का उपयोग :

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

        ID TEXT
---------- --------------------------------------------------
         1 word1
         1 word2
         1 word3
         2 word4
         2 word5
         2 word6
         3 word7
         3 word8
         3 word9

9 rows selected.

SQL>

1
क्या आप अधिक विस्तृत कर सकते हैं, क्यों होना है ('"' || REPLACE(text, ',', '","') || '"')और कोष्ठक को हटाया नहीं जा सकता है? Oracle डॉक्स ([ docs.oracle.com/database/121/SQLRF/functions268.htm ) मेरे लिए स्पष्ट नहीं हैं। क्या यह है XQuery_string?
बेतलिस्ता

@ बिटलिस्टा यह एक XQuery अभिव्यक्ति है।
ललित कुमार B

किसी कारण से XMLTABLE समाधान लगातार मिश्रित लंबाई वाली पंक्तियों के लिए अंतिम प्रविष्टि का उत्पादन करने में विफल रहता है। उदाहरण के लिए। row1: 3 शब्द; row2: 2 शब्द, row3: 1 शब्द; row4: 2 शब्द, row5: 1 शब्द - अंतिम शब्द का उत्पादन नहीं करेगा। पंक्तियों का आदेश देना कोई मायने नहीं रखता।
ग्नूडीफ

7

उसी के कुछ और उदाहरण:

SELECT trim(regexp_substr('Err1, Err2, Err3', '[^,]+', 1, LEVEL)) str_2_tab
  FROM dual
CONNECT BY LEVEL <= regexp_count('Err1, Err2, Err3', ',')+1
/

SELECT trim(regexp_substr('Err1, Err2, Err3', '[^,]+', 1, LEVEL)) str_2_tab
  FROM dual
CONNECT BY LEVEL <= length('Err1, Err2, Err3') - length(REPLACE('Err1, Err2, Err3', ',', ''))+1
/

इसके अलावा, DBMS_UTILITY.comma_to_table और table_to_comma का उपयोग कर सकते हैं: http://www.oracle-base.com/articles/9i/useful-procedures-and-functions-9i.php##MSMS_UTILITY.comma_to_table


ध्यान रखें कि comma_to_table()केवल टोकन के साथ काम करता है जो ओरेकल के डेटाबेस ऑब्जेक्ट नामकरण सम्मेलनों में फिट होता है। यह '123,456,789'उदाहरण के लिए एक स्ट्रिंग पर चोट करेगा ।
एपीसी

7

मैं PIPELINED टेबल फ़ंक्शन का उपयोग करके एक अलग दृष्टिकोण का प्रस्ताव करना चाहूंगा। यह XMLTABLE की तकनीक से कुछ मिलता-जुलता है, सिवाय इसके कि आप चरित्र स्ट्रिंग को विभाजित करने के लिए अपने स्वयं के कस्टम फ़ंक्शन प्रदान कर रहे हैं:

-- Create a collection type to hold the results
CREATE OR REPLACE TYPE typ_str2tbl_nst AS TABLE OF VARCHAR2(30);
/

-- Split the string according to the specified delimiter
CREATE OR REPLACE FUNCTION str2tbl (
  p_string    VARCHAR2,
  p_delimiter CHAR DEFAULT ',' 
)
RETURN typ_str2tbl_nst PIPELINED
AS
  l_tmp VARCHAR2(32000) := p_string || p_delimiter;
  l_pos NUMBER;
BEGIN
  LOOP
    l_pos := INSTR( l_tmp, p_delimiter );
    EXIT WHEN NVL( l_pos, 0 ) = 0;
    PIPE ROW ( RTRIM( LTRIM( SUBSTR( l_tmp, 1, l_pos-1) ) ) );
    l_tmp := SUBSTR( l_tmp, l_pos+1 );
  END LOOP;
END str2tbl;
/

-- The problem solution
SELECT name, 
       project, 
       TRIM(COLUMN_VALUE) error
  FROM t, TABLE(str2tbl(error));

परिणाम:

      NAME PROJECT    ERROR
---------- ---------- --------------------
       108 test       Err1
       108 test       Err2
       108 test       Err3
       109 test2      Err1

इस तरह के दृष्टिकोण के साथ समस्या यह है कि अक्सर ऑप्टिमाइज़र को टेबल फ़ंक्शन की कार्डिनैलिटी का पता नहीं चलेगा और उसे एक अनुमान लगाना होगा। यह आपकी निष्पादन योजनाओं के लिए हानिकारक हो सकता है, इसलिए यह समाधान ऑप्टिमाइज़र के लिए निष्पादन आँकड़े प्रदान करने के लिए बढ़ाया जा सकता है।

आप इस क्वेरी को ऊपर दिए गए प्रश्न पर एक EXPLAIN PLAN चलाकर देख सकते हैं:

Execution Plan
----------------------------------------------------------
Plan hash value: 2402555806

----------------------------------------------------------------------------------------------
| Id  | Operation                          | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |         | 16336 |   366K|    59   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                      |         | 16336 |   366K|    59   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL                | T       |     2 |    42 |     3   (0)| 00:00:01 |
|   3 |   COLLECTION ITERATOR PICKLER FETCH| STR2TBL |  8168 | 16336 |    28   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------

भले ही संग्रह में केवल 3 मान हों, लेकिन अनुकूलक ने इसके लिए 8168 पंक्तियों (डिफ़ॉल्ट मान) का अनुमान लगाया है। यह पहली बार में अप्रासंगिक लग सकता है, लेकिन यह ऑप्टिमाइज़र के लिए उप-इष्टतम योजना के लिए निर्णय लेने के लिए पर्याप्त हो सकता है।

समाधान संग्रह के लिए आँकड़े प्रदान करने के लिए अनुकूलक एक्सटेंशन का उपयोग करना है:

-- Create the optimizer interface to the str2tbl function
CREATE OR REPLACE TYPE typ_str2tbl_stats AS OBJECT (
  dummy NUMBER,

  STATIC FUNCTION ODCIGetInterfaces ( p_interfaces OUT SYS.ODCIObjectList )
  RETURN NUMBER,

  STATIC FUNCTION ODCIStatsTableFunction ( p_function  IN  SYS.ODCIFuncInfo,
                                           p_stats     OUT SYS.ODCITabFuncStats,
                                           p_args      IN  SYS.ODCIArgDescList,
                                           p_string    IN  VARCHAR2,
                                           p_delimiter IN  CHAR DEFAULT ',' )
  RETURN NUMBER
);
/

-- Optimizer interface implementation
CREATE OR REPLACE TYPE BODY typ_str2tbl_stats
AS
  STATIC FUNCTION ODCIGetInterfaces ( p_interfaces OUT SYS.ODCIObjectList )
  RETURN NUMBER
  AS
  BEGIN
    p_interfaces := SYS.ODCIObjectList ( SYS.ODCIObject ('SYS', 'ODCISTATS2') );
    RETURN ODCIConst.SUCCESS;
  END ODCIGetInterfaces;

  -- This function is responsible for returning the cardinality estimate
  STATIC FUNCTION ODCIStatsTableFunction ( p_function  IN  SYS.ODCIFuncInfo,
                                           p_stats     OUT SYS.ODCITabFuncStats,
                                           p_args      IN  SYS.ODCIArgDescList,
                                           p_string    IN  VARCHAR2,
                                           p_delimiter IN  CHAR DEFAULT ',' )
  RETURN NUMBER
  AS
  BEGIN
    -- I'm using basically half the string lenght as an estimator for its cardinality
    p_stats := SYS.ODCITabFuncStats( CEIL( LENGTH( p_string ) / 2 ) );
    RETURN ODCIConst.SUCCESS;
  END ODCIStatsTableFunction;

END;
/

-- Associate our optimizer extension with the PIPELINED function   
ASSOCIATE STATISTICS WITH FUNCTIONS str2tbl USING typ_str2tbl_stats;

परिणामी निष्पादन योजना का परीक्षण:

Execution Plan
----------------------------------------------------------
Plan hash value: 2402555806

----------------------------------------------------------------------------------------------
| Id  | Operation                          | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |         |     1 |    23 |    59   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                      |         |     1 |    23 |    59   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL                | T       |     2 |    42 |     3   (0)| 00:00:01 |
|   3 |   COLLECTION ITERATOR PICKLER FETCH| STR2TBL |     1 |     2 |    28   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------

जैसा कि आप देख सकते हैं कि ऊपर की योजना पर कार्डिनैलिटी 8196 अनुमानित मूल्य नहीं है। यह अभी भी सही नहीं है क्योंकि हम एक स्ट्रिंग शाब्दिक के बजाय फ़ंक्शन के लिए एक कॉलम पास कर रहे हैं।

फ़ंक्शन कोड में कुछ बदलाव इस विशेष मामले में एक करीबी अनुमान देने के लिए आवश्यक होगा, लेकिन मुझे लगता है कि समग्र अवधारणा यहां बहुत स्पष्ट है।

इस उत्तर में प्रयुक्त str2tbl फ़ंक्शन मूल रूप से टॉम कायटे द्वारा विकसित किया गया था: https://asktom.oracle.com/pls/asktom/f?p=100:11 विस्तार ::::P11_QUESTION_ID:110634348061

इस प्रकार के लेखों को पढ़कर वस्तुगत प्रकारों के साथ जुड़ने की अवधारणा का पता लगाया जा सकता है: http://www.oracle-developer.net/display.php?id=427

यहाँ वर्णित तकनीक 10g + में काम करती है।


4

REGEXP_COUNT को Oracle 11i तक जोड़ा नहीं गया था। यहाँ एक Oracle 10g समाधान है, जिसे Art के समाधान से अपनाया गया है।

SELECT trim(regexp_substr('Err1, Err2, Err3', '[^,]+', 1, LEVEL)) str_2_tab
  FROM dual
CONNECT BY LEVEL <=
  LENGTH('Err1, Err2, Err3')
    - LENGTH(REPLACE('Err1, Err2, Err3', ',', ''))
    + 1;

मैं इसके लिए एक फ़िल्टर कैसे जोड़ सकता हूं, जो मुझे केवल नाम = '108' के साथ फ़िल्टर करना चाहता है। मैंने क्लॉज़ के बाद एक जगह जोड़ने की कोशिश की, लेकिन डुप्लिकेट के साथ समाप्त हो गया।
DRTauli

4

Oracle 12c से शुरू आप उपयोग कर सकते हैं JSON_TABLEऔर JSON_ARRAY:

CREATE TABLE tab(Name, Project, Error) AS
SELECT 108,'test' ,'Err1, Err2, Err3' FROM dual UNION 
SELECT 109,'test2','Err1'             FROM dual;

और क्वेरी:

SELECT *
FROM tab t
OUTER APPLY (SELECT TRIM(p) AS p
            FROM JSON_TABLE(REPLACE(JSON_ARRAY(t.Error), ',', '","'),
           '$[*]' COLUMNS (p VARCHAR2(4000) PATH '$'))) s;

आउटपुट:

┌──────┬─────────┬──────────────────┬──────┐
 Name  Project       Error         P   
├──────┼─────────┼──────────────────┼──────┤
  108  test     Err1, Err2, Err3  Err1 
  108  test     Err1, Err2, Err3  Err2 
  108  test     Err1, Err2, Err3  Err3 
  109  test2    Err1              Err1 
└──────┴─────────┴──────────────────┴──────┘

db <> फिडेल डेमो


1
मैं मानता हूं कि यह एक चतुर चाल है, लेकिन स्पष्ट रूप से यह मुझे पहेली होगा अगर मैं एक कोड बेस में आया।
एपीसी

@APC यह एसक्यूएल के साथ क्या संभव है का सिर्फ शो है। अगर मुझे अपने कोडबेस में इस तरह के कोड का उपयोग करना है तो मैं निश्चित रूप से इसे किसी फ़ंक्शन में
लपेटूंगा

बेशक। यह सिर्फ इतना है कि यह धागा ओरेकल के साथ स्ट्रिंग टोकन के लिए अधिक लोकप्रिय हिट में से एक है, इसलिए मुझे लगता है कि हमें निर्दोष की रक्षा के लिए और अधिक विदेशी समाधानों में कैवेट को शामिल करना चाहिए :)
APC

3

यहाँ XMLTABLE का उपयोग करके एक वैकल्पिक कार्यान्वयन है जो विभिन्न डेटा प्रकारों के लिए कास्टिंग करने की अनुमति देता है:

select 
  xmltab.txt
from xmltable(
  'for $text in tokenize("a,b,c", ",") return $text'
  columns 
    txt varchar2(4000) path '.'
) xmltab
;

... या यदि आपके सीमांकित तार किसी तालिका की एक या अधिक पंक्तियों में संग्रहीत हैं:

select 
  xmltab.txt
from (
  select 'a;b;c' inpt from dual union all
  select 'd;e;f' from dual
) base
inner join xmltable(
  'for $text in tokenize($input, ";") return $text'
  passing base.inpt as "input"
  columns 
    txt varchar2(4000) path '.'
) xmltab
  on 1=1
;

मुझे लगता है कि यह समाधान Oracle 11.2.0.3 और बाद के संस्करणों के लिए काम करता है।
एपीसी

2

मैं एक और तरीका जोड़ना चाहूंगा। यह एक पुनरावर्ती क्वेरी का उपयोग करता है, ऐसा कुछ जो मैंने अन्य उत्तरों में नहीं देखा है। यह 11gR2 के बाद से Oracle द्वारा समर्थित है।

with cte0 as (
    select phone_number x
    from hr.employees
), cte1(xstr,xrest,xremoved) as (
        select x, x, null
        from cte0
    union all        
        select xstr,
            case when instr(xrest,'.') = 0 then null else substr(xrest,instr(xrest,'.')+1) end,
            case when instr(xrest,'.') = 0 then xrest else substr(xrest,1,instr(xrest,'.') - 1) end
        from cte1
        where xrest is not null
)
select xstr, xremoved from cte1  
where xremoved is not null
order by xstr

यह बंटवारे के चरित्र के साथ काफी लचीला है। बस इसे INSTRकॉल में बदलें ।


2

द्वारा कनेक्ट या regexp का उपयोग किए बिना :

    with mytable as (
      select 108 name, 'test' project, 'Err1,Err2,Err3' error from dual
      union all
      select 109, 'test2', 'Err1' from dual
    )
    ,x as (
      select name
      ,project
      ,','||error||',' error
      from mytable
    )
    ,iter as (SELECT rownum AS pos
        FROM all_objects
    )
    select x.name,x.project
    ,SUBSTR(x.error
      ,INSTR(x.error, ',', 1, iter.pos) + 1
      ,INSTR(x.error, ',', 1, iter.pos + 1)-INSTR(x.error, ',', 1, iter.pos)-1
    ) error
    from x, iter
    where iter.pos < = (LENGTH(x.error) - LENGTH(REPLACE(x.error, ','))) - 1;

1

मुझे एक ही समस्या थी, और xmltable ने मेरी मदद की:

सेलेक्ट आईडी, ट्रिम (COLUMN_VALUE) टेक्स्ट FROM t, xmltable (("" "REPLACE (पाठ, ',', '', '') '' ''))


0

Oracle 11g और बाद में, आप पुनरावर्ती उप-क्वेरी और सरल स्ट्रिंग फ़ंक्शंस का उपयोग कर सकते हैं (जो नियमित अभिव्यक्तियों की तुलना में तेज़ हो सकता है और सहसंबद्ध श्रेणीबद्ध उप-प्रश्न)

Oracle सेटअप :

CREATE TABLE table_name ( name, project, error ) as
 select 108, 'test',  'Err1, Err2, Err3' from dual union all
 select 109, 'test2', 'Err1'             from dual;

प्रश्न :

WITH table_name_error_bounds ( name, project, error, start_pos, end_pos ) AS (
  SELECT name,
         project,
         error,
         1,
         INSTR( error, ', ', 1 )
  FROM   table_name
UNION ALL
  SELECT name,
         project,
         error,
         end_pos + 2,
         INSTR( error, ', ', end_pos + 2 )
  FROM   table_name_error_bounds
  WHERE  end_pos > 0
)
SELECT name,
       project,
       CASE end_pos
       WHEN 0
       THEN SUBSTR( error, start_pos )
       ELSE SUBSTR( error, start_pos, end_pos - start_pos )
       END AS error
FROM   table_name_error_bounds

आउटपुट :

NAME | परियोजना | त्रुटि
---: | : ------ | : ----
 108 | परीक्षण | Err1
 109 | test2 | Err1
 108 | परीक्षण | Err2
 108 | परीक्षण | Err3

db <> फिडल यहां


-1

मैंने DBMS_UTILITY.comma_to _table फ़ंक्शन का उपयोग किया था, वास्तव में इसके कोड को निम्नानुसार काम करना

declare
l_tablen  BINARY_INTEGER;
l_tab     DBMS_UTILITY.uncl_array;
cursor cur is select * from qwer;
rec cur%rowtype;
begin
open cur;
loop
fetch cur into rec;
exit when cur%notfound;
DBMS_UTILITY.comma_to_table (
     list   => rec.val,
     tablen => l_tablen,
     tab    => l_tab);
FOR i IN 1 .. l_tablen LOOP
    DBMS_OUTPUT.put_line(i || ' : ' || l_tab(i));
END LOOP;
end loop;
close cur;
end; 

मैंने अपनी तालिका और स्तंभ नामों का उपयोग किया था


5
ध्यान रखें कि comma_to_table()केवल टोकन के साथ काम करता है जो ओरेकल के डेटाबेस ऑब्जेक्ट नामकरण सम्मेलनों में फिट होता है। यह '123,456,789'उदाहरण के लिए एक स्ट्रिंग पर चोट करेगा ।
एपीसी

क्या हम अस्थायी तालिकाओं का उपयोग करके लागू कर सकते हैं?
स्मार्ट 003

1
उम्म, अन्य सभी व्यावहारिक समाधानों को देखते हुए हम अस्थायी तालिकाओं का उपयोग क्यों करना चाहेंगे जो डेटा को भौतिक बनाने के एक बड़े पैमाने पर ओवरहेड के साथ आते हैं?
एपीसी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.