跨不同行的值 - 将它们组合成 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
查询说明:
- 正在创建一个
rownumber
以便我们可以参考上一行来获取 frequency
CTE
的第一部分将获取 NON NULL
频率,第二部分将获取 NULL
频率
- 将两者与前面的 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)
我在 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 |
查询说明:
- 正在创建一个
rownumber
以便我们可以参考上一行来获取frequency
CTE
的第一部分将获取NON NULL
频率,第二部分将获取NULL
频率- 将两者与前面的 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)