基于父ID将子数据分成多个记录

时间:2017-12-21 08:16:50

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

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

父表

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

3 个答案:

答案 0 :(得分:2)

使用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

答案 1 :(得分:1)

使用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    |
+----------+--------+--------+--------+

答案 2 :(得分:1)

主要重写原始答案,您只需要一个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,您可以模拟&#34; 预期结果&#34;中的列名称。同样。

相关问题