2017-07-24 40 views
2

表名:crm_mrdetailsOracle查詢 - 加入用逗號分隔的數據

id | mr_name | me_email  | mr_mobile | mr_doctor| 
----------------------------------------------------- 
1 | John |[email protected] | 1234555555 | ,1,2,3 | 

表名:crm_mr_doctor

id | dr_name  | specialization| 
---------------------------------- 
1 | Abhishek | cordiologist | 
2 | Krishnan | Physician  | 
3 | Krishnan | Nurse   | 

mrdetails.mr_doctor連接值是mr_doctor.id外鍵。我需要加入他們來產生這樣的輸出:

id | mr_name | me_email  |Doctor_Specialization| 
------------------------------------------------- 
1 | John |[email protected] |cordiologist,Physician,Nurse| 

我是Oracle的新手,我使用Oracle 12C。任何幫助非常感謝。

+0

如何連接兩個表格,我提供的示例,連接必須在同一列上完成。 –

+0

你不能在這裏交叉連接,它不是我的模型,有人創建了我們需要使用的模型。加入應該發生在Mr_Doctor和ID –

+0

您用來與數據庫交互的前端是SQL Developer,其最新版本是4.3(我認爲)。 12c是您的Oracle數據庫的一個不同的軟件產品。 SQL Developer與你的問題無關;數據庫版本是。我編輯了你的標籤,我將編輯這個問題來反映這一點。 – mathguy

回答

0

請根據您的要求更改列名稱。

CREATE OR REPLACE Function ReplaceSpec 
    (String_Inside IN Varchar2) 
    Return Varchar2 Is 

     outputString Varchar2(5000); 
     tempOutputString crm_doc.specialization%TYPE; 

    Begin 

     FOR i in 1..(LENGTH(String_Inside)-LENGTH(REPLACE(String_Inside,',',''))+1) 
     LOOP 

      Select specialization into tempOutputString From crm_doc 
      Where id = PARSING_STRING(String_Inside,i); 

      If i != 1 Then 
       outputString := outputString || ','; 
      end if; 
      outputString := outputString || tempOutputString; 

     END LOOP; 

     Return outputString; 


    End; 
/

Parsing_String函數幫助拆分逗號分隔值。

CREATE OR REPLACE Function PARSING_STRING 
(String_Inside IN Varchar2, Position_No IN Number) 
Return Varchar2 Is 
    OurEnd Number; Beginn Number; 
Begin 

If Position_No < 1 Then 
Return Null; 
End If; 

OurEnd := Instr(String_Inside, ',', 1, Position_No); 

If OurEnd = 0 Then 
    OurEnd := Length(String_Inside) + 1; 
End If; 

If Position_No = 1 Then 
    Beginn := 1; 
Else 
    Beginn := Instr(String_Inside, ',', 1, Position_No-1) + 1; 
End If; 

Return Substr(String_Inside, Beginn, OurEnd-Beginn); 

End; 
/

請注意,我只給出了一個基本函數來獲得您的輸出。您可能需要添加一些例外等

Eg. When the doc_id [mr_doctor] is empty, what to do. 

使用

select t1.*,ReplaceSpec(doc_id) from crm_details t1 

如果您mr_doctor數據總是用逗號使用開始:

Select t1.*,ReplaceSpec(Substr(doc_id,2)) from crm_details t1 
+0

很多工作來重新創建輪子[LISTAGG](https://docs.oracle.com/cd/E11882_01/server.112/e41084/ functions089.htm#SQLRF30030) –

+0

@JorgeCampos我無法想象只有LISTAGG和單個查詢可以完成所需全部工作的工作流程。我可能是錯的! – pOrinG

+0

我只讀訪問,我無法創建任何表/ procudures /函數,將數據提取到SQL並報告它 –

1

該解決方案使用正則表達式來拆分mr_doctor列轉換成ID然後加入到mr_doctor表中; specialization列連接在一起以產生所需的輸出。

select mrdet.id, 
     mrdet.mr_name, 
     mrdet.me_email, 
     listagg(mrdoc.specialization, ',') 
        within group (order by mrdoc.specialization) as doctor_specialization 
from mr_details mrdet 
    join (
     select distinct id, 
       regexp_substr(mr_doctor, '(,?)([0-9]+)(,?)', 1, level, null, 2) as dr_id 
     from mr_details 
     connect by level <= regexp_count(mr_doctor, '(,?)([0-9]+)') 
     ) as mrids 
    on mrids.id = mrdet.id 
    join mr_doctor mrdoc 
     on mrids.dr_id = mr_doc.id 
group by mrdet.id, 
     mrdet.mr_name, 
     mrdet.me_email 
/

儘管數據模型很脆弱,但此解決方案仍具有相當的彈性。如果字符串中包含太多逗號或空格,它將返回結果。它會忽略字母或其他不是數字的值。如果提取的號碼與mr_doctor表中的ID不匹配,則不會投擲。顯然這些結果是不可信的,但這是輕快數據模型價格的一部分。

能否請你解釋下:(,?)([0-9]+)(,?)

的模式匹配零個或一個逗號其次一個或多個數字其次零或一個逗號。也許匹配模式中的(,?)不是絕對必要的。但是,如果沒有它們,該字符串2 3 4將匹配與此字符串2,3,4相同的三個ID。也許這是正確的,但事實並非如此。當外鍵存儲在CSV列中而不是通過適當的約束強制執行時,「正確」的含義甚至意味着什麼?

+1

Hi @APC,你能解釋一下嗎:'(,?)([0-9] +)(,?)'你在SUBSTR中使用過。我無法繞過它。第一部分'(,?)'表示最初出現0個或更多問號,最後表示0個或更多出現問號,但如果我們在兩種情況下都考慮0並嘗試匹配數字,那麼99 ,應分別考慮9和9!現在我把注意力放在'[0-9 +]'範圍內的+,意思是1次或更多次出現。即使最後一個參數爲2,我似乎也有點困惑。我是regexp_substr的新手! – pOrinG

+0

@pOrinG - 好問題。我擴大了我的答案。問題是,我在使用正則表達式進行數據清理方面遇到了不好的經驗,所以我傾向於冗長並且過多地指定匹配。許多正則表達從業者喜歡簡潔和優雅。雙方都有爭論。 – APC

+0

感謝您的解釋。 – pOrinG

1

您必須將mr_doctor列中的數據拆分成行,連接表crm_mrdoctor,然後使用listagg()。 如何分割數據?Splitting string into multiple rows in Oracle

select t.id, max(mr_name) mr_name, 
     listagg(specialization, ', ') within group (order by rn) specs 
    from (
    select id, mr_name, levels.column_value rn, 
      trim(regexp_substr(mr_doctor, '[^,]+', 1, levels.column_value)) as did 
     from crm_mrdetails t, 
      table(cast(multiset(select level 
           from dual 
           connect by level <= 
            length(regexp_replace(t.mr_doctor, '[^,]+')) + 1) 
         as sys.odcinumberlist)) levels) t 
    left join crm_mr_doctor d on t.did = d.id 
    group by t.id 

演示和結果:

with crm_mrdetails (id, mr_name, mr_doctor) as (
    select 1, 'John', ',1,2,3' from dual union all 
    select 2, 'Anne', ',4,2,6,5' from dual union all 
    select 3, 'Dave', ',4'  from dual), 
crm_mr_doctor (id, dr_name, specialization) as (
    select 1, 'Abhishek', 'cordiologist' from dual union all 
    select 2, 'Krishnan', 'Physician' from dual union all 
    select 3, 'Krishnan', 'Nurse'  from dual union all 
    select 4, 'Krishnan', 'Onkologist' from dual union all 
    select 5, 'Krishnan', 'Surgeon'  from dual union all 
    select 6, 'Krishnan', 'Nurse'  from dual 
    ) 
select t.id, max(mr_name) mr_name, 
     listagg(specialization, ', ') within group (order by rn) specs 
    from (
    select id, mr_name, levels.column_value rn, 
      trim(regexp_substr(mr_doctor, '[^,]+', 1, levels.column_value)) as did 
     from crm_mrdetails t, 
      table(cast(multiset(select level 
           from dual 
           connect by level <= 
            length(regexp_replace(t.mr_doctor, '[^,]+')) + 1) 
         as sys.odcinumberlist)) levels) t 
    left join crm_mr_doctor d on t.did = d.id 
    group by t.id 

輸出:

ID MR_NAME SPECS 
------ ------- ------------------------------------- 
    1 John cordiologist, Physician, Nurse 
    2 Anne Onkologist, Physician, Nurse, Surgeon 
    3 Dave Onkologist 
+0

謝謝你們,真棒工作:) :) –

0

這件怎麼樣?我沒有測試過,所以可能會有語法錯誤。

select id,mr_name,me_email,listagg(specialization,',') within group (order by specialization) as Doctor_Specialization 
from 
(select dtls.id,dtls.mr_name,dtls.me_email,dr.specialization 
from crm_mrdetails dtls, 
crm_mr_doctor dr 
where INSTR(','||dtls.mr_doctor||',' , ','||dr.id||',') > 0 
) group by id,mr_name,me_email; 
+0

考慮在某些時候這樣做,然後;-) – GhostCat