【问题标题】:Breaking Child Data Into Multiple records based on Parent ID根据父 ID 将子数据拆分为多个记录
【发布时间】:2017-12-31 22:06:41
【问题描述】:

我有一个要求,我需要将子数据分成多条记录。下面,我试图通过一些示例日期让您理解 因为我不应该发布原始数据。在每个 ParentId 的以下数据中,我们可能有多个子记录。所以,现在 我们需要在单独的列中显示每条记录,其中包含 3 个子数据及其对应的父 ID,如下面的预期输出所示。 即使我们得到了游标,我们也尝试过,但它正在消磨执行时间,而且我们也考虑过使用 pivot 并且看起来它变得非常复杂,我不确定它是否可以工作。 任何帮助或方法将不胜感激。在此先感谢。

父表

SELECT * into  #Parent FROM (
SELECT 1 PARENTID,'A' PARENTNAME
UNION ALL
SELECT 2,'B'
UNION ALL
SELECT 3,'C'
UNION ALL
SELECT 4,'D'
) AS A

子表

SELECT * INTO #Child from (
SELECT 10 as CHILDID,1 as PARENTID ,'DEF' AS CHILDNAME
union all
SELECT 11 , 1,'EFG'
UNION ALL
SELECT 12,1,'GHI'
UNION ALL
SELECT 13,1,'JKL'
UNION ALL
SELECT 14,1,'MNO'
UNION ALL
SELECT 15,1,'PQR'
UNION ALL
SELECT 20,2,'ACE'
UNION ALL
SELECT 30,3,'STU'
UNION ALL
SELECT 31,3,'VWX'
UNION ALL
SELECT 32,3,'WXY'
UNION ALL
SELECT 33,3,'XYZ'
)as a

SELECT * FROM #Parent
SELECT * FROM #CHILD

预期结果:

PARENTID Child1Name Child2Name Child3Name
1            DEF      EFG        GHI
1            JKL      MNO        PQR
2            ACE      NULL       NULL
3            STU      VWX        WXY
3            XYZ      NULL       NULL

【问题讨论】:

    标签: sql sql-server sql-server-2008


    【解决方案1】:

    使用row_number()函数生成两个row_numbers,不需要游标

    SELECT 
        p.PARENTID,
        coalesce(max(case when c.rn1=1 then c.ChildName end), max(case when c.rn1%3=1 then c.ChildName end)) [Child1Name],
        coalesce(max(case when c.rn1=2 then c.ChildName end), max(case when c.rn1%3=2 then c.ChildName end)) [Child2Name],
        coalesce(max(case when c.rn1=3 then c.ChildName end), max(case when c.rn1%3=0 then c.ChildName end)) [Child3Name]
        FROM Parent p 
    join
    (SELECT *, (row_number() over (partition by PARENTID order by childid)-1)/3 rn,
               row_number() over (partition by PARENTID order by childid) rn1 FROM CHILD) c on c.PARENTID = p.PARENTID
    group by p.PARENTID, c.rn 
    order by p.PARENTID
    

    结果:

    PARENTID Child1Name Child2Name Child3Name
    1            DEF      EFG        GHI
    1            JKL      MNO        PQR
    2            ACE      NULL       NULL
    3            STU      VWX        WXY
    3            XYZ      NULL       NULL
    

    【讨论】:

      【解决方案2】:

      使用NTILE & ROW_NUMBER将它们分成3个记录组

      SELECT PARENTID,CHILD1, CHILD2,CHILD3 FROM (
      SELECT 'CHILD'+CASE WHEN grp='0' THEN '3' ELSE grp END CHILDS
      ,CAST(NTILE(2) OVER(PARTITION BY PARENTID ORDER BY CHILDID) AS VARCHAR(10))
      +'-' +CAST(PARENTID AS VARCHAR(10)) as PARENTID_2
      ,  PARENTID, CHILDNAME FROM (
      SELECT  CAST(ROW_NUMBER() OVER (PARTITION BY PARENTID ORDER BY CHILDID)%3 AS VARCHAR(10)) 
       AS grp
      ,* FROM #CHILD 
      )A
      )B
      PIVOT
      (
          MAX(CHILDNAME) FOR CHILDS IN([CHILD1],[CHILD2],[CHILD3])
      )PV
      

      结果:

      +----------+--------+--------+--------+
      | PARENTID | CHILD1 | CHILD2 | CHILD3 |
      +----------+--------+--------+--------+
      |        1 | DEF    | EFG    | GHI    |
      |        1 | JKL    | MNO    | PQR    |
      |        2 | ACE    | NULL   | NULL   |
      |        3 | STU    | VWX    | NULL   |
      |        3 | XYZ    | NULL   | WXY    |
      +----------+--------+--------+--------+
      

      【讨论】:

      • 请修改“result”部分,它与 OP Mahesh 和 Yogesh 的有点不同。
      • 是的.. 见过。为此,我对你们俩都投了赞成票。 @KtX2SkD
      【解决方案3】:

      对原答案的重大改写,你只需要一个PIVOT,两个ROW_NUMBER,仅此而已:

      SELECT PARENTID, [0], [1], [2]
      FROM (
          SELECT
              PARENTID
            , CHILDNAME
            , ParentBreaker = (ROW_NUMBER() OVER(PARTITION BY PARENTID ORDER BY CHILDID) - 1) / 3 + 1 -- You want this to facilitate splitting every 3 child records.
            , Child#Name = (ROW_NUMBER() OVER(PARTITION BY PARENTID ORDER BY CHILDID) - 1) % 3
          FROM #Child 
      ) AS RowNumbered
      PIVOT (
          MAX(CHILDNAME)
          FOR Child#Name IN ([0], [1], [2])
      ) AS T
      ORDER BY PARENTID
      

      通过快速CONCATChild#Name +1,您可能也可以模拟“预期结果”中的列名。

      【讨论】:

      • 在原始答案中,#CHILD_2#FINAL_RESULT 显然是相同的,如果是这样的话,就会发现逻辑中的严重冗余。
      猜你喜欢
      • 1970-01-01
      • 2017-09-05
      • 1970-01-01
      • 1970-01-01
      • 2019-11-03
      • 2020-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多