sql >> Base de Datos >  >> RDS >> Sqlserver

SQL Server:fusión de varias filas de datos en una sola fila

Esto funcionará, pero dado que no hay una columna de identidad o fecha y hora, no hay forma de encontrar qué fila de actualización es más nueva. Entonces, si hay más actualizaciones en la misma columna, solo tomo la primera alfabéticamente/numéricamente (MIN).

WITH CTE AS 
(
    SELECT ID, REF, MIN(Title) Title, MIN(Surname) Surname, MIN(Forename) Forename, MIN(DOB) DOB, MIN(Add1) Add1, MIN(Postcode) Postcode
    FROM Table1
    GROUP BY id, REF
)
SELECT 
    d.REF
  , d.ID
  , COALESCE(T.Title, d.TItle) AS Title
  , COALESCE(T.Surname, d.Surname) AS Surname
  , COALESCE(T.Forename, d.Forename) AS Forename
  , COALESCE(T.DOB, d.DOB) AS DOB
  , COALESCE(T.Add1, d.Add1) AS Add1
  , COALESCE(T.Postcode, d.Postcode) AS Postcode
FROM CTE d 
INNER JOIN CTE t ON d.ID = t.ID AND d.REF = 'D' AND t.REF = 't'

DEMO DE SQLFiddle

Si se puede agregar la columna de identidad, podemos simplemente reescribir la parte CTE para que sea más precisa.

EDITAR:

Si tenemos una columna de identidad y CTE se reescribe para volverse recursivo, en realidad se puede descartar toda otra parte de la consulta.

WITH CTE_RN AS 
(
    --Assigning row_Numbers based on identity - it has to be done since identity can always have gaps which would break the recursion
    SELECT *, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY IDNT DESC) RN FROM dbo.Table2
)
,RCTE AS 
(
    SELECT  ID ,
            Title ,
            Surname ,
            Forename ,
            DOB ,
            Add1 ,
            Postcode ,
            RN FROM CTE_RN WHERE RN = 1 -- taking the last row for each ID
    UNION ALL
    SELECT r.ID,
        COALESCE(r.TItle,p.TItle), --Coalesce will hold prev value if exist or use next one
        COALESCE(r.Surname,p.Surname),
        COALESCE(r.Forename,p.Forename),
        COALESCE(r.DOB,p.DOB),
        COALESCE(r.Add1,p.Add1),
        COALESCE(r.Postcode,p.Postcode),
        p.RN
    FROM RCTE r
    INNER JOIN CTE_RN p ON r.ID = p.ID AND r.RN + 1 = p.RN --joining the previous row for each id
)
,CTE_Group AS 
(
    --rcte now holds both merged and unmerged rows, merged is max(rn)
    SELECT ID, MAX(RN) RN FROM RCTE
    GROUP BY ID  
)
SELECT r.* FROM RCTE r
INNER JOIN CTE_Group g ON r.ID = g.ID AND r.RN = g.RN

DEMO DE SQLFiddle