【问题标题】:SQL to merge rows in Oracle用于合并 Oracle 中的行的 SQL
【发布时间】:2017-06-06 12:14:21
【问题描述】:

我想合并一些行。

首先,我的表和数据存在如下

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

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

实际上,有严格的规则来区分哪些是重复的(母亲、父亲、工作),哪些不是(朋友)

由于某些原因,我无法修改表的结构。 (我已将这个问题的内容从我的业务条款中更改并简化了情况来解释)

请提供任何建议再试一次

【问题讨论】:

  • 您是否尝试在 FRIEND 列上使用 max 将其从组中取出?
  • @JorgeCampos 是的,我试过了,但是行数应该是三,因为有三个朋友。
  • 那么您的解决方案将是您的实际查询的内部联接与像select ...... where TYPE_CD ='FRIEND' 这样的朋友的子查询,此联接将为您提供 3 个结果...试试看。哦,你的查询不需要那个 '1=1' (我知道这可能来自一个懒惰的程序员不想检查每个先前条件 =D 的应用程序)
  • @JorgeCampos 谢谢,我正在尝试您的建议。

标签: sql oracle merge rows


【解决方案1】:

假设 'MOTHER'、'FATHER' 和 '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' 行。

【讨论】:

    【解决方案2】:

    一个自联接的表就可以解决问题:

    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”是强制性的,并且当然,如果您使用过滤器,它可以被丢弃,例如:WHERE t1.type_cd = 'FATHER'

    【讨论】:

      【解决方案3】:

      只是为了提供另一种方法。

      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'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-20
        • 1970-01-01
        • 1970-01-01
        • 2011-02-20
        相关资源
        最近更新 更多