2017-07-24 35 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