跨不同行的值 - 将它们组合成 1 行

Values Across Different Rows - combine them into 1 row

我在 table 中得到以下结果,我需要得到的是频率列向下到适当的行,因此频率列中的 NULL 值被替换为适当的值。注意 CustomerCode 的不同值。

任何人都知道如何做到这一点,并在这样做时删除没有类型和类型数量的频率行?

CustomerCode    Frequency   Type    TypeAmount
C12345          Monthly     NULL    NULL
C12345          NULL        A1      5.00
C12345          NULL        A2      20.00
C12345          Fortnightly NULL    NULL
C12345          NULL        A1      5.00
C12345          NULL        A2      20.00
C56789          Fortnightly NULL    NULL
C56789          NULL        A1      50.00

期望的输出

CustomerCode    Frequency   Type    TypeAmount
C12345          Monthly     A1      5.00
C12345          Monthly     A2      20.00
C12345          Fortnightly A1      5.00
C12345          Fortnightly A2      20.00
C56789          Fortnightly A1      50.00

示例数据

Create Table #Data
(
    CustomerCode varchar(50),
    Frequency varchar(50) NULL,
    Type varchar(50) NULL,
    TypeAmount money NULL
)

insert into #Data
(
    CustomerCode,
    Frequency,
    Type,
    TypeAmount 
)
select
    'C12345',
    'Monthly',
    NULL,
    NULL
union all
select
    'C12345',
    NULL,
    'A1',
    '5.00'
union all
select
    'C12345',
    NULL,
    'A2',
    '20.00'
union all
select
    'C12345',
    'Fornightly',
    NULL,
    NULL
union all
select
    'C12345',
    NULL,
    'A1',
    '5.00'
union all
select
    'C12345',
    NULL,
    'A2',
    '20.00'
union all
select
    'C56789',
    'Fornightly',
    NULL,
    NULL
union all
select
    'C56789',
    NULL,
    'A1',
    '50.00'

select * from #Data

RECURSIVE CTE 应该可以解决问题:

With cte AS
(
SELECT customerCode, frequency, type, TypeAmount, rn
FROM 
    (
     SELECT *, ROW_NUMBER()OVER(PARTITION BY CustomerCode ORDER BY CustomerCode) AS rn
     FROM #data
    ) AS d
WHERE Frequency IS NOT NULL

UNION ALL

SELECT d2.customerCode, cte.frequency, d2.type, d2.TypeAmount, d2.rn
From 
     (
      SELECT *, ROW_NUMBER()OVER(PARTITION BY CustomerCode ORDER BY CustomerCode) AS rn
      FROM #data
     ) AS d2
INNER JOIN cte
  ON d2.rn=cte.rn+1
  AND d2.CustomerCode=cte.CustomerCode
WHERE d2.Frequency IS NULL
)

SELECT * 
FROM cte 
WHERE Type IS NOT NULL 
  AND TypeAmount IS NOT NULL
ORDER BY CustomerCode, rn;

结果:

customerCode frequency type TypeAmount rn
C12345 Monthly A1 5.0000 2
C12345 Monthly A2 20.0000 3
C12345 Fornightly A1 5.0000 5
C12345 Fornightly A2 20.0000 6
C56789 Fornightly A1 50.0000 2

查询说明:

  1. 正在创建一个 rownumber 以便我们可以参考上一行来获取 frequency
  2. CTE 的第一部分将获取 NON NULL 频率,第二部分将获取 NULL 频率
  3. 将两者与前面的 1 行合并以获得相应的 Frequency

请在此处查看 DEMO

;with cte1 as
(select CustomerCode,Frequency,ROW_NUMBER()over( order by 
customercode)rn,Type,TypeAmount from #Data a ),
cte2 as (   select * from cte1 where  Frequency is not null)
select row_number()over(order by 
cte2.rn)sno,cte1.CustomerCode,cte2.Frequency,cte1.Type,cte1.TypeAmount from cte1
inner join cte2 on cte1.CustomerCode=cte2.CustomerCode
where cte1.Type is not null
group by cte1.CustomerCode,cte2.Frequency,cte1.Type,cte1.TypeAmount,cte2.rn
order by 1

您的数据必须有某种已定义的顺序,否则您无法执行此查询。我通过将您的数据插入带有标识列的临时 table 来创建订单,供您参考。我假设您的源数据中定义了一些基本顺序。只需将其替换为我的代理键列 [ID]

DROP TABLE IF EXISTS #Data

Create Table #Data
(
    ID int Identity(1,1),
    CustomerCode varchar(50),
    Frequency varchar(50) NULL,
    Type varchar(50) NULL,
    TypeAmount money NULL
)

INSERT INTO #Data (CustomerCode,Frequency,[Type],TypeAmount )
VALUES ('C12345','Monthly',NULL,NULL)
,('C12345',NULL,'A1','5.00')
,('C12345',NULL,'A2','20.00')
,('C12345','Fornightly',NULL,NULL)
,('C12345',NULL,'A1','5.00')
,('C12345',NULL,'A2','20.00')
,('C56789','Fornightly',NULL,NULL)
,('C56789',NULL,'A1','50.00')

Select *
FROM #Data

SELECT A.ID
    ,B.Frequency
    ,A.Type
    ,A.TypeAmount
from #Data as A
Cross Apply 
(   /*Grab most recent preceding row that has frequency populated*/
    SELECT Top (1) DTA.Frequency
    From #Data AS DTA
    Where A.CustomerCode = DTA.CustomerCode
    AND DTA.ID < A.ID
    AND DTA.Frequency IS NOT NULL
    Order by DTA.ID DESC
) AS B
WHERE A.Frequency IS NULL

如果性能有问题,建议在执行 select:

之前创建一个像这样的索引
Create Index ix on #Data(CustomerCode,ID) Include (Frequency)