2016-01-25 11 views
6

मेरे पास एकाधिक विकल्प, एकाधिक उत्तर प्रश्न सहित प्रश्नावली प्रतिक्रिया का डेटाबेस तालिका (ओरेकल 11 जी) है। विकल्प कॉलम में प्रत्येक मान का चयन किया जा सकता है, और उत्तर कॉलम में उनके द्वारा चुने गए अंकों के संख्यात्मक मूल्य होते हैं।एसक्यूएल रेगेक्स - किसी अन्य फ़ील्ड से सबस्ट्रिंग के साथ बदलें

ID_NO  OPTIONS        ANSWERS 
1001  Apple Pie|Banana-Split|Cream Tea  1|2 
1002  Apple Pie|Banana-Split|Cream Tea  2|3 
1003  Apple Pie|Banana-Split|Cream Tea  1|2|3 

मैं एक प्रश्न है कि एक एकल स्ट्रिंग के रूप में जवाब के लिए पाठ रूप से जवाब डिकोड होगा, की जरूरत है।

ID_NO  ANSWERS  ANSWER_DECODE 
1001  1|2   Apple Pie|Banana-Split 
1002  2|3   Banana-Split|Cream Tea 
1003  1|2|3  Apple Pie|Banana-Split|Cream Tea 

मैं नियमित अभिव्यक्ति के साथ प्रयोग किया मूल्यों की जगह और सबस्ट्रिंग प्राप्त करने के लिए, लेकिन मैं एक तरह से ठीक से दो विलय करने के लिए बाहर काम नहीं कर सकता।

WITH feedback AS (
    SELECT 1001 id_no, 'Apple Pie|Banana-Split|Cream Tea' options, '1|2' answers FROM DUAL UNION 
    SELECT 1002 id_no, 'Apple Pie|Banana-Split|Cream Tea' options, '2|3' answers FROM DUAL UNION 
    SELECT 1003 id_no, 'Apple Pie|Banana-Split|Cream Tea' options, '1|2|3' answers FROM DUAL) 
SELECT 
    id_no, 
    options, 
    REGEXP_SUBSTR(options||'|', '(.)+?\|', 1, 2) second_option, 
    answers, 
    REGEXP_REPLACE(answers, '(\d)+', ' \1 ') answer_numbers, 
    REGEXP_REPLACE(answers, '(\d)+', REGEXP_SUBSTR(options||'|', '(.)+?\|', 1, To_Number('2'))) "???" 
FROM feedback 

मैं SQL में उत्तर मैन्युअल रूप से परिभाषित या डीकोड नहीं करना चाहता; अलग-अलग प्रश्नों (और विकल्पों की अलग-अलग संख्या) के साथ कई सर्वेक्षण हैं, इसलिए मुझे उम्मीद है कि एक ऐसा समाधान है जो गतिशील रूप से उन सभी के लिए काम करेगा।

मैंने विकल्पों और उत्तरों को LEVEL द्वारा अलग पंक्तियों में विभाजित करने का प्रयास किया है, और उन कोडों में फिर से जुड़ें जहां कोड मेल खाते हैं, लेकिन यह वास्तविक डेटासेट के साथ बहुत धीमी गति से चलता है (प्रतिक्रियाओं की 600 पंक्तियों के साथ 5-विकल्प प्रश्न)।

WITH feedback AS (
    SELECT 1001 id_no, 'Apple Pie|Banana-Split|Cream Tea' options, '1|2' answers FROM DUAL UNION 
    SELECT 1002 id_no, 'Apple Pie|Banana-Split|Cream Tea' options, '2|3' answers FROM DUAL UNION 
    SELECT 1003 id_no, 'Apple Pie|Banana-Split|Cream Tea' options, '1|2|3' answers FROM DUAL) 
SELECT 
    answer_rows.id_no, 
    ListAgg(option_rows.answer) WITHIN GROUP(ORDER BY option_rows.lvl) 
FROM 
    (SELECT DISTINCT 
    LEVEL lvl, 
    REGEXP_SUBSTR(options||'|', '(.)+?\|', 1, LEVEL) answer 
    FROM 
    (SELECT DISTINCT 
     options, 
     REGEXP_COUNT(options||'|', '(.)+?\|') num_choices 
    FROM 
     feedback) 
    CONNECT BY LEVEL <= num_choices 
) option_rows 
    LEFT OUTER JOIN 
    (SELECT DISTINCT 
    id_no, 
    to_number(REGEXP_SUBSTR(answers, '(\d)+', 1, LEVEL)) answer 
    FROM 
    (SELECT DISTINCT 
     id_no, 
     answers, 
     To_Number(REGEXP_SUBSTR(answers, '(\d)+$')) max_answer 
    FROM 
     feedback) 
    WHERE 
    to_number(REGEXP_SUBSTR(answers, '(\d)+', 1, LEVEL)) IS NOT NULL 
    CONNECT BY LEVEL <= max_answer 
) answer_rows 
    ON option_rows.lvl = answer_rows.answer 
GROUP BY 
    answer_rows.id_no 
ORDER BY 
    answer_rows.id_no 

अगर वहाँ एक समाधान सिर्फ Regex का उपयोग करके नहीं है, वहाँ स्तर की तुलना में एक अधिक कुशल तरीका मूल्यों विभाजित करने के लिए है? या क्या कोई और दृष्टिकोण है जो काम करेगा?

+0

प्रासंगिक: http://stackoverflow.com/questions/26407538/split-string-into-rows-oracle-sql – QuestionC

+0

फ़ंक्शन क्यों नहीं। सरल होना चाहिए। –

उत्तर

1

यह धीमी गति से, क्योंकि आप प्रत्येक पंक्ति को कई बार विस्तार कर रहे हैं है का मान निर्दिष्ट सरणी मूल्यों का उपयोग करें; आपके द्वारा उपयोग किए जा रहे कनेक्ट-क्लॉज क्लॉज सभी पंक्तियों को देख रहे हैं, इसलिए आप फिर से सॉर्ट करने के लिए बड़ी मात्रा में डेटा समाप्त कर रहे हैं - संभवतः आप वहां DISTINCT के साथ क्यों समाप्त हुए हैं।

आप कनेक्ट-दर, सबसे पहले तो ID_NO संरक्षित है, और एक दूसरे दो PRIOR खंड जोड़ सकते हैं एक पाश से बचने के लिए - किसी भी गैर नियतात्मक समारोह इस के लिए क्या करेंगे, मैं dbms_random.value उठाया है, लेकिन आप उपयोग कर सकते हैं sys_guid यदि आप चाहें, या कुछ और। आपको कई सबक्वायरीज़ की भी आवश्यकता नहीं है, आप इसे दो के साथ कर सकते हैं; या सीटीई जो के रूप में मुझे लगता है कि यह थोड़ा स्पष्ट है:

WITH feedback AS (
    SELECT 1001 id_no, 'Apple Pie|Banana-Split|Cream Tea' options, '1|2' answers FROM DUAL UNION 
    SELECT 1002 id_no, 'Apple Pie|Banana-Split|Cream Tea' options, '2|3' answers FROM DUAL UNION 
    SELECT 1003 id_no, 'Apple Pie|Banana-Split|Cream Tea' options, '1|2|3' answers FROM DUAL 
), 
option_rows AS (
    SELECT 
    id_no, 
    LEVEL answer, 
    REGEXP_SUBSTR(options, '[^|]+', 1, LEVEL) answer_text 
    FROM feedback 
    CONNECT BY LEVEL <= REGEXP_COUNT(options, '[^|]+') 
    AND id_no = PRIOR id_no 
    AND PRIOR dbms_random.value IS NOT NULL 
), 
answer_rows AS (
    SELECT 
    id_no, 
    REGEXP_SUBSTR(answers, '[^|]+', 1, LEVEL) answer 
    FROM feedback 
    CONNECT BY LEVEL <= REGEXP_COUNT(answers, '[^|]+') 
    AND PRIOR id_no = id_no 
    AND PRIOR dbms_random.value IS NOT NULL 
) 
SELECT 
    option_rows.id_no, 
    LISTAGG(option_rows.answer, '|') WITHIN GROUP (ORDER BY option_rows.answer) AS answers, 
    LISTAGG(option_rows.answer_text, '|') WITHIN GROUP (ORDER BY option_rows.answer) AS answer_decode 
FROM option_rows 
JOIN answer_rows 
ON option_rows.id_no = answer_rows.id_no 
AND option_rows.answer = answer_rows.answer 
GROUP BY option_rows.id_no 
ORDER BY option_rows.id_no; 

कौन सा हो जाता है:

 ID_NO ANSWERS ANSWER_DECODE       
---------- ---------- ---------------------------------------- 
     1001 1|2  Apple Pie|Banana-Split     
     1002 2|3  Banana-Split|Cream Tea     
     1003 1|2|3  Apple Pie|Banana-Split|Cream Tea 

मैं भी अपने regex पैटर्न बदल दिया है ताकि आप संलग्न या | पट्टी की जरूरत नहीं है।

0

मैंने माईएसक्यूएल में एक करीबी समाधान लिखा है (अभी ओरेकल स्थापित नहीं है) - लेकिन मैंने लिखा है कि क्वेरी को ओरेकल में काम करने के लिए क्या बदला जाना चाहिए।

इसके अलावा, मेरे कोड का सबसे ऊंचा हिस्सा ओरेकल में बहुत बेहतर दिखता है क्योंकि इसमें बहुत बेहतर INSTR फ़ंक्शन है।

विचार है कि संख्याओं की सूची (1 से 10 तक प्रति सर्वेक्षण तक 10 विकल्प का समर्थन करने के लिए) के साथ क्रॉस जॉइन करना है, और अलग-अलग पंक्तियों में विकल्प फ़ील्ड को तोड़ना ... (आप यह करते हैं संख्याओं और ओरेकल के INSTR फ़ंक्शन दोनों की सूची का उपयोग करके, टिप्पणियां देखें)।

वहां से आप उन पंक्तियों को फ़िल्टर करते हैं जिन्हें चयनित नहीं किया गया था और सबकुछ एक साथ वापस समूहित किया गया था।

-- I've used GROUP_CONCAT in MySQL, but in Oracle you'll have to use WM_CONCAT 
select ID_NO, ANSWERS, group_concat(broken_down_options,'|') `OPTIONS` 
from (
    select your_table.ID_NO, your_table.ANSWERS, 
      -- Luckily, you're using ORACLE so you can use an INSTR function that has the "occurrence" parameter 
      -- INSTR(string, substring, [position, [occurrence]]) 
      -- use the nums.num field as input for the occurrence parameter 
      -- and just put '1' under "position" 
      case when nums.num = 1 
       then substr(your_table.`OPTIONS`, 1, instr(your_table.`OPTIONS`, '|') - 1) 
       when nums.num = 2 
       then substr(substr(your_table.`OPTIONS`, instr(your_table.`OPTIONS`, '|') + 1), 1, instr(substr(your_table.`OPTIONS`, instr(your_table.`OPTIONS`, '|') + 1), '|') - 1) 
       else substr(your_table.`OPTIONS`, length(your_table.`OPTIONS`) - instr(reverse(your_table.`OPTIONS`), '|') + 2) end broken_down_options 
    from (select 1 num union all 
     select 2 num union all 
     select 3 num union all 
     select 4 num union all 
     select 5 num union all 
     select 6 num union all 
     select 7 num union all 
     select 8 num union all 
     select 9 num union all 
     select 10 num 
     ) nums 
     CROSS JOIN 
     (select 1001 ID_NO, 'Apple Pie|Banana-Split|Cream Tea' `OPTIONS`, '1|2' ANSWERS union 
     select 1002 ID_NO, 'Apple Pie|Banana-Split|Cream Tea' `OPTIONS`, '2|3' ANSWERS union 
     select 1003 ID_NO, 'Apple Pie|Banana-Split|Cream Tea' `OPTIONS`, '1|2|3' ANSWERS 
     ) your_table 
    -- for example: 2|3 matches 2 and 3 but not 1 
    where your_table.ANSWERS like concat(concat('%',nums.num),'%') 
) some_query 
group by ID_NO, ANSWERS 
0

एक संग्रहीत predure बनाएँ और कदम

  • अपने आकार की एक सरणी घोषित नीचे है।
  • पहली पंक्ति से option डेटा प्राप्त करें। पाइप के बीच मूल्य निकालने के लिए एक regex या level का उपयोग करें और फिर उन्हें सरणी में संग्रहित करें। नोट: यह केवल एक बार इटवेशन होगा। तो आपको हर पंक्ति के लिए इसे दोहराने की ज़रूरत नहीं है।
  • अब एक पाश में, प्रत्येक पंक्ति के लिए, answers का चयन करें और answers
1

इस कॉम्पैक्ट समाधान की जाँच करें:

with sample_data as 
(
    select 'ala|ma|kota' options, '1|2' answers from dual 
    union all 
    select 'apples|oranges|bacon', '1|2|3' from dual 
    union all 
    select 'a|b|c|d|e|f|h|i','1|3|4|5|8' from dual 
) 
select answers, options, 
regexp_replace(regexp_replace(options,'([^|]+)\|([^|]+)\|([^|]+)','\' || replace(answers,'|','|\')),'[|]+','|') answer_decode 
from sample_data; 

आउटपुट:

ANSWERS OPTIONS    ANSWER_DECODE 
--------- -------------------- --------------------------- 
1|2  ala|ma|kota   ala|ma 
1|2|3  apples|oranges|bacon apples|oranges|bacon 
1|3|4|5|8 a|b|c|d|e|f|h|i  a|c|d|f|h|i 
+0

सर्वेक्षण में 3 से अधिक संभावित उत्तर होने पर क्या होता है? – DougieHauser

+0

स्टाइल थोड़ा अतिरिक्त सफाई के साथ काम करता है - अनावश्यक विभाजक को हटा रहा है –

संबंधित मुद्दे