用于合并Oracle中的行的SQL

时间:2017-06-06 12:14:21

标签: sql oracle merge rows

我想合并一些行。

首先,我的表和数据如下所示

GRP     CRRO_NO  TYPE_CD  TYPE_ID
PERSON  1111     FATHER   Tom
PERSON  1111     MOTHER   Jennifer
PERSON  1111     JOB_     Teacher
PERSON  1111     FRIEND   Jimmy
PERSON  1111     FRIEND   Kim
PERSON  1111     FRIEND   Michael

我希望得到像

这样的结果
GRP     CRRO_NO   FATHER    MOTHER     JOB_      FRIEND
PERSON  1111      Tom       Jennifer   Teacher   Jimmy
PERSON  1111      Tom       Jennifer   Teacher   Kim
PERSON  1111      Tom       Jennifer   Teacher   Michael

有了这种情况,如何编写SQL?

我一直在尝试

SELECT  T1.GRP_CD GRP, T1.CRRO_NO CRRO
      , MAX(T1.MOTHER) MOTHER, MAX(T1.FATHER) FATHER, MAX(T1.JOB_) JOB, T1.FRIEND FRIEND     
  FROM (
        SELECT  DISTINCT
                GRP_CD
               ,CRRO_NO                        
               ,CASE WHEN TYPE_CD  = 'FATHER'  THEN TYPE_ID   ELSE '' END FATHER
               ,CASE WHEN TYPE_CD  = 'MOTHER'  THEN TYPE_ID   ELSE '' END MOTHER
               ,CASE WHEN TYPE_CD  = 'JOB_'    THEN TYPE_ID    ELSE '' END JOB_
               ,CASE WHEN TYPE_CD  = 'FRIEND'  THEN TYPE_ID   ELSE '' END FRIEND
         FROM    TMP     
        WHERE   1=1   AND     TRIM(CRRO_NO) = '1111'
       ) T1
  WHERE T1.CRRO_NO = '1111'
        GROUP BY T1.GRP_CD, T1.CRRO_NO, T1.FRIEND
;

然后,上面的sql结果是

GRP      CRRO_NO  MOTHER     FATHER    JOB       FRIEND   
PERSON   1111     Jennifer   Tom       Teacher   (null)
PERSON   1111     (null)     (null)    (null)    Jimmy
PERSON   1111     (null)     (null)    (null)    Kim
PERSON   1111     (null)     (null)    (null)    Michael

现在我知道为什么我的查询结果是错误的(不是我想要的),但我仍然无法找到方法。

实际上,有严格的规则来分类哪一个会被重复(母亲,父亲,工作),哪些不会(朋友)

由于某些原因,我无法修改表格的结构。 (我已根据业务条款更改了此问题的内容,并简化了解释的情况)

请提出任何建议再试一次

3 个答案:

答案 0 :(得分:1)

假设'母亲','父亲'和' JOB _'是唯一的type_cd值,你可以实现你的目标:

WITH sample_data AS (SELECT 'PERSON' grp, 1111 crro_no, 'FATHER' type_cd, 'Tom' type_id FROM dual UNION ALL
                     SELECT 'PERSON' grp, 1111 crro_no, 'MOTHER' type_cd, 'Jennifer' type_id FROM dual UNION ALL
                     SELECT 'PERSON' grp, 1111 crro_no, 'JOB_' type_cd, 'Teacher' type_id FROM dual UNION ALL
                     SELECT 'PERSON' grp, 1111 crro_no, 'FRIEND' type_cd, 'Jimmy' type_id FROM dual UNION ALL
                     SELECT 'PERSON' grp, 1111 crro_no, 'FRIEND' type_cd, 'Kim' type_id FROM dual UNION ALL
                     SELECT 'PERSON' grp, 1111 crro_no, 'FRIEND' type_cd, 'Michael' type_id FROM dual)
-- end of mimicking a table called "sample_data" with your data in it.
-- see the SQL below:
SELECT grp,
       crro_no,
       father,
       mother,
       job_,
       type_id friend
FROM   (SELECT grp,
               crro_no,
               type_cd,
               type_id,
               MAX(CASE WHEN type_cd = 'FATHER' THEN type_id END) OVER (PARTITION BY grp, crro_no) father,
               MAX(CASE WHEN type_cd = 'MOTHER' THEN type_id END) OVER (PARTITION BY grp, crro_no) mother,
               MAX(CASE WHEN type_cd = 'JOB_' THEN type_id END) OVER (PARTITION BY grp, crro_no) job_
        FROM   sample_data)
WHERE  type_cd = 'FRIEND';

GRP       CRRO_NO FATHER   MOTHER   JOB_     FRIEND
------ ---------- -------- -------- -------- --------
PERSON       1111 Tom      Jennifer Teacher  Michael
PERSON       1111 Tom      Jennifer Teacher  Jimmy
PERSON       1111 Tom      Jennifer Teacher  Kim

这可以通过使用MAX()分析函数在所有行的不同列中输出父,母和作业type_cd的type_id来实现。

然后,只需过滤行以显示type_cd =' FRIEND'行。

答案 1 :(得分:0)

自联接表可以解决问题:

select distinct t1.GRP, t1.CRRO_NO, t2.TYPE_ID as father, t3.TYPE_ID as mother, t4.TYPE_ID as JOB_, t5.TYPE_ID as FRIEND
from TMP t1
inner join TMP t2   on  t2.CRRO_NO = t1.CRRO_NO 
                    and t2.TYPE_CD = 'FATHER'
inner join TMP t3   on  t3.CRRO_NO = t1.CRRO_NO 
                    and t3.TYPE_CD = 'MOTHER'
inner join TMP t4   on  t4.CRRO_NO = t1.CRRO_NO 
                    and t4.TYPE_CD = 'JOB_'
inner join TMP t5   on  t5.CRRO_NO = t1.CRRO_NO 
                    and t5.TYPE_CD = 'FRIEND';

但请注意,由于您未指定过滤谓词(WHERE子句),因此表格TMP中的所有结果都将被处理,并且您将有重复的结果,因此使用了' distinct& #39;将是强制性的,当然如果您使用过滤器,例如:WHERE t1.type_cd = 'FATHER'

,则可以将其丢弃

答案 2 :(得分:0)

只是提供另一种方法。

with MFJQuery as (
select * from ( 
            select
                   A.GRP,
                   A.CRRO_NO,
                   A.TYPE_CD,
                   A.TYPE_ID
            from test_data A
            where A.TYPE_CD <> 'FRIEND')
pivot
(
    max(TYPE_ID)
    for TYPE_CD in ('MOTHER' as "MOTHER", 
                    'FATHER' as "FATHER", 
                    'JOB_' as "JOB")
))
select A.GRP, A.CRRO_NO, B.MOTHER, B.FATHER, B.JOB, A.TYPE_ID as FRIEND
from test_data A inner join
        MFJQuery B on A.GRP = B.GRP 
        and A.CRRO_NO = B.CRRO_NO
where
    A.TYPE_CD = 'FRIEND'