我有一个这样的表:
ID FullName ID_Total Balance
100000 kkkk 100020|100003|100080|100050 NULL
100001 llll 100080|100050|100005 NULL
100002 qqqq 100004|100031 NULL
100003 wwww 1025.02
100004 rrrr 298.63
100005 tttt 548.25
100006 yyyy 659.20
100010 uuuu 100003...100005|100050...100080 NULL
100020 iiii 3687.05
100030 oooo 100004...100006 NULL
100031 pppp 945.36
100040 aaaa 100006|100031...100080|100003 NULL
100050 ssss 1064.98
100080 ffff 569.65
这是我正在使用的查询,仅当ID_Total保持相同时,该查询才有效:
;WITH CTE AS( SELECT ID, FullName,
--SEPARATE ID_Total into Columns
SUBSTRING(REPLACE(REPLACE(ID_Total,'.',''),'|',''),1,6) TL1,
SUBSTRING(REPLACE(REPLACE(ID_Total,'.',''),'|',''),7,6) TL2,
SUBSTRING(REPLACE(REPLACE(ID_Total,'.',''),'|',''),13,6) TL3,
SUBSTRING(REPLACE(REPLACE(ID_Total,'.',''),'|',''),19,6) TL4,
SUBSTRING(REPLACE(REPLACE(ID_Total,'.',''),'|',''),25,6) TL5,
SUBSTRING(REPLACE(REPLACE(ID_Total,'.',''),'|',''),31,6) TL6,
SUBSTRING(REPLACE(REPLACE(ID_Total,'.',''),'|',''),37,6) TL7,
SUBSTRING(REPLACE(REPLACE(ID_Total,'.',''),'|',''),43,6) TL8,
SUBSTRING(REPLACE(REPLACE(ID_Total,'.',''),'|',''),49,6) TL9,
SUBSTRING(REPLACE(REPLACE(ID_Total,'.',''),'|',''),55,6) TL10,
ID_Total, Balance
FROM TABLE1
)
SELECT ID, FullName, ID_Total,
(CASE WHEN Balance IS NULL THEN
CASE
--Code to sum balances corresponding to kkkk FullName
WHEN X.TL1 != '' AND X.TL2 != '' AND X.TL3 != '' AND X.TL4 != ''
THEN
(
SELECT SUM(Balance)
FROM CTE
WHERE ID = X.TL1 OR ID= X.TL2 OR ID=X.TL3 OR ID= X.TL4 --OR IN THIS CASE IS TO SUM Values with |
)
--Code to sum balances corresponding to llll FullName
WHEN X.TL1 != '' AND X.TL2 != '' AND X.TL3 != ''
THEN
(
SELECT SUM(Balance)
FROM CTE
WHERE ID = X.TL1 OR ID = X.TL2 OR ID= X.TL3
)
--Code to sum balances corresponding to qqqq FullName
WHEN X.TL1 != '' AND X.TL2 != ''
THEN
(
SELECT SUM(Balance)
FROM CTE
WHERE ID = X.TL1 OR ID = X.TL2
)
--Code to sum balances corresponding to uuuu FullName
WHEN X.TL1 != '' AND X.TL2 != '' AND X.TL3 != '' AND X.TL4 != '' AND LEN(ID_Total) = 31
THEN
(
SELECT SUM(Balance)
FROM CTE
WHERE ID >= X.TL1 AND ID <= X.TL2 OR ID >= X.TL3 AND ID <= X.TL4
)
--Code to sum balances corresponding to oooo FullName
WHEN X.TL1 != '' AND X.TL2 != '' AND LEN(ID_Total) = 15
THEN
(
SELECT SUM(Balance)
FROM CTE
WHERE ID >= X.TL1 AND ID <= X.TL2
)
--Code to sum balances corresponding to aaaa FullName
WHEN X.TL1 != '' AND X.TL2 != '' AND X.TL3 != '' AND X.TL4 != '' AND LEN(ID_Total) = 29
THEN
(
SELECT SUM(Balance)
FROM CTE
WHERE ID = X.TL1 OR ID >= X.TL2 AND ID <= X.TL3 OR ID = X.TL4
)
END
ELSE Balance
END) AS Balances
FROM CTE X
WHERE ID IN (
100000,100001,100002,100003,100004,100005,100006,
100010,100020,100030,100031,100040,100050,100080
)
ORDER BY ID
所需的输出:
ID FullName ID_Total Balance
100000 kkkk 100020|100003|100080|100050 6346.7
100001 llll 100080|100050|100005 2182.88
100002 qqqq 100004|100031 1243.99
100003 wwww 1025.02
100004 rrrr 298.63
100005 tttt 548.25
100006 yyyy 659.20
100010 uuuu 100003...100005|100050...100080 3506.26
100020 iiii 3687.05
100030 oooo 100004...100006 1506.08
100031 pppp 945.36
100040 aaaa 100006|100031...100080|100003 4264.21
100050 ssss 1064.98
100080 ffff 569.65
我正在尝试按照ID_Total列中提供的顺序对余额进行求和,其中 | 表示具有下一个值的和,而 ... 是范围例如100001 ... 100004 ,这表示余额将基于从100001 100002 100003到100004开始的所有ID的总和来计算。
我在上面提供的查询工作正常,但是当ID_total的模式更改顺序时出现了问题,因此每次ID_Total更改时,我都必须修改查询以使其与新的ID_Total模式对齐,因此我正在尝试以获得一种动态地对余额进行求和或根据ID_Total使用一段时间的方式。
注意: 不管什么公式,其ID总是用|分隔。它表示下一个ID的总和,当...表示范围。
2注意: 有关如何更改ID_Total模式的一些示例为:
100001|200002|355520 to 100001|200002...450002
200008...200015|200020|300030...400000 to 200008...200015|200020|300030...400000|500008...500012
100001...200025 to 100001...200025|300092...300098
等...
任何帮助将不胜感激!
答案 0 :(得分:1)
具有两个助手功能。
示例
Select A.ID
,A.FullName
,A.ID_Total
,Balance= sum(B.balance)
From (
Select ID
,FullName
,ID_Total
,Pos1 = C.Pos1
,Pos2 = IsNull(C.Pos2,C.Pos1)
From @YourTable
Cross Apply [dbo].[tvf-Str-Parse](IsNull(NullIf(ID_Total,''),ID),'|') B
Cross Apply [dbo].[tvf-Str-Parse-Row](B.RetVal,'...') C
) A
Join @YourTable B on B.ID between A.Pos1 and A.Pos2
Group By A.ID
,A.FullName
,A.ID_Total
返回
感兴趣的功能
CREATE FUNCTION [dbo].[tvf-Str-Parse] (@String varchar(max),@Delimiter varchar(10))
Returns Table
As
Return (
Select RetSeq = row_number() over (order by 1/0)
,RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace((Select replace(@String,@Delimiter,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
);
和
CREATE FUNCTION [dbo].[tvf-Str-Parse-Row] (@String varchar(max),@Delimiter varchar(10))
Returns Table
As
Return (
Select Pos1 = ltrim(rtrim(xDim.value('/x[1]','varchar(max)')))
,Pos2 = ltrim(rtrim(xDim.value('/x[2]','varchar(max)')))
,Pos3 = ltrim(rtrim(xDim.value('/x[3]','varchar(max)')))
,Pos4 = ltrim(rtrim(xDim.value('/x[4]','varchar(max)')))
,Pos5 = ltrim(rtrim(xDim.value('/x[5]','varchar(max)')))
,Pos6 = ltrim(rtrim(xDim.value('/x[6]','varchar(max)')))
,Pos7 = ltrim(rtrim(xDim.value('/x[7]','varchar(max)')))
,Pos8 = ltrim(rtrim(xDim.value('/x[8]','varchar(max)')))
,Pos9 = ltrim(rtrim(xDim.value('/x[9]','varchar(max)')))
From ( values (cast('<x>' + replace((Select replace(@String,@Delimiter,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml))) as A(xDim)
)
编辑-只是为了好玩
如果您不想要这些功能,这是另一个选择