根据位置和分隔符拆分字符串

Split String based on position and delimiters

我需要帮助。 关于 CHARINDEX、PATINDEX、SUBSTRING、LEFT 和 RIGHT 的 SQL 问题。

我有一些字符串需要根据位置和分隔符进行拆分。使用它的一部分作为列名,另一部分作为数据。并根据行 ID 对其进行分组。然后根据需要对值求和。

示例数据、ID、字符串

1    20:4:10:1:20:3:
2    20:1:
3    10:3:
4    30:4:40:1:50:3:

所需的结果是

id  10  20  30  40  50
1   1   7
2       1
3   3
4           4   1   3

数据:

CREATE TABLE #Split (ID int, SplitString varchar(450))
Insert into #Split (ID, SplitString) values 
(1, '20:4:10:1:20:3:'),
(2, '20:1:'),
(3, '10:3:'),
(4, '30:4:40:1:50:3:')

select * From #Split
DROP TABLE #Split

如有任何帮助,我们将不胜感激!

数据也可以是这样的:

CREATE TABLE #Split (ID int, String1 varchar(10),  String1Quantity int, String2 varchar(10), String2Quantity int, String3 VARCHAR(10), String3Quantity int, String4 varchar(10), String4Quantity int, String5 varchar(10), String5Quantity int)

Insert into #Split (ID, String1, String1Quantity, String2, String2Quantity, String3, String3Quantity, String4, String4Quantity, String5, String5Quantity) values 
(1,'20',4,'10',1,'20',3, null, null, null, null),
(2,'20',1,null,null,null,null, null, null, null, null),
(3,'10',3,null,null,null,null, null, null, null, null),
(4,'30',4,'40',1,'50',3, null, null, null, null)

select * From #Split


DROP TABLE #Split

我想出了一个不太优雅的解决后一个数据的方法,有没有更好的方法来做到这一点?

CREATE TABLE #Split (ID int, String1 varchar(10),  String1Quantity int, String2 varchar(10), String2Quantity int, String3 VARCHAR(10), String3Quantity int, String4 varchar(10), String4Quantity int, String5 varchar(10), String5Quantity int)

Insert into #Split (ID, String1, String1Quantity, String2, String2Quantity, String3, String3Quantity, String4, String4Quantity, String5, String5Quantity) values 
(1,'20',4,'10',1,'20',3, '20', 10, '20', 3),
(2,'20',1,'10',3,null,null, null, null, null, null),
(3,'10',3,'10',3,null,null, null, null, null, null),
(4,'30',4,'40',1,'50',3, '40', 8, '10', 1)

select 
    ID,
    CASE 
        WHEN String1 = '10' and String2 = '10' and String3 = '10' and String4 = '10' and String5 = '10' THEN SUM(String1Quantity+String2Quantity+String3Quantity+String4Quantity+String5Quantity)
        WHEN String1 = '10' and String2 = '10' and String3 = '10' and String4 = '10' THEN SUM(String1Quantity+String2Quantity+String3Quantity+String4Quantity)
        WHEN String1 = '10' and String2 = '10' and String3 = '10' and String5 = '10' THEN SUM(String1Quantity+String2Quantity+String3Quantity+String5Quantity)
        WHEN String1 = '10' and String3 = '10' and String4 = '10' and String5 = '10' THEN SUM(String1Quantity+String3Quantity+String3Quantity+String4Quantity)
        WHEN String2 = '10' and String3 = '10' and String4 = '10' and String5 = '10' THEN SUM(String2Quantity+String3Quantity+String4Quantity+String5Quantity)
        WHEN String1 = '10' and String2 = '10' and String3 = '10' THEN SUM(String1Quantity+String2Quantity+String3Quantity)
        WHEN String1 = '10' and String2 = '10' and String4 = '10' THEN SUM(String1Quantity+String2Quantity+String4Quantity)
        WHEN String1 = '10' and String2 = '10' and String5 = '10' THEN SUM(String1Quantity+String2Quantity+String5Quantity)
        WHEN String1 = '10' and String3 = '10' and String4 = '10' THEN SUM(String1Quantity+String3Quantity+String4Quantity)
        WHEN String1 = '10' and String3 = '10' and String5 = '10' THEN SUM(String1Quantity+String3Quantity+String5Quantity)
        WHEN String1 = '10' and String4 = '10' and String5 = '10' THEN SUM(String1Quantity+String4Quantity+String5Quantity)
        WHEN String2 = '10' and String3 = '10' and String4 = '10' THEN SUM(String2Quantity+String3Quantity+String4Quantity)
        WHEN String2 = '10' and String3 = '10' and String5 = '10' THEN SUM(String2Quantity+String3Quantity+String5Quantity)
        WHEN String2 = '10' and String4 = '10' and String5 = '10' THEN SUM(String2Quantity+String4Quantity+String5Quantity)
        WHEN String3 = '10' and String4 = '10' and String5 = '10' THEN SUM(String3Quantity+String4Quantity+String5Quantity)
        WHEN String3 = '10' and String5 = '10' THEN SUM(String3Quantity+String5Quantity)
        WHEN String3 = '10' and String4 = '10' THEN SUM(String3Quantity+String4Quantity)
        WHEN String2 = '10' and String5 = '10' THEN SUM(String2Quantity+String5Quantity)
        WHEN String2 = '10' and String4 = '10' THEN SUM(String2Quantity+String4Quantity)
        WHEN String2 = '10' and String3 = '10' THEN SUM(String2Quantity+String3Quantity)
        WHEN String1 = '10' and String5 = '10' THEN SUM(String1Quantity+String5Quantity)
        WHEN String1 = '10' and String4 = '10' THEN SUM(String1Quantity+String4Quantity)
        WHEN String1 = '10' and String3 = '10' THEN SUM(String1Quantity+String3Quantity)
        WHEN String1 = '10' and String2 = '10' THEN SUM(String1Quantity+String2Quantity)
        WHEN String5 = '10' THEN SUM(String5Quantity)
        WHEN String4 = '10' THEN SUM(String4Quantity)
        WHEN String3 = '10' THEN SUM(String3Quantity)
        WHEN String2 = '10' THEN SUM(String2Quantity) 
        WHEN String1 = '10' THEN SUM(String1Quantity) 
    END AS '10',

    CASE 
        WHEN String1 = '20' and String2 = '20' and String3 = '20' and String4 = '20' and String5 = '20' THEN SUM(String1Quantity+String2Quantity+String3Quantity+String4Quantity+String5Quantity)
        WHEN String1 = '20' and String2 = '20' and String3 = '20' and String4 = '20' THEN SUM(String1Quantity+String2Quantity+String3Quantity+String4Quantity)
        WHEN String1 = '20' and String2 = '20' and String3 = '20' and String5 = '20' THEN SUM(String1Quantity+String2Quantity+String3Quantity+String5Quantity)
        WHEN String1 = '20' and String3 = '20' and String4 = '20' and String5 = '20' THEN SUM(String1Quantity+String3Quantity+String3Quantity+String4Quantity)
        WHEN String2 = '20' and String3 = '20' and String4 = '20' and String5 = '20' THEN SUM(String2Quantity+String3Quantity+String4Quantity+String5Quantity)
        WHEN String1 = '20' and String2 = '20' and String3 = '20' THEN SUM(String1Quantity+String2Quantity+String3Quantity)
        WHEN String1 = '20' and String2 = '20' and String4 = '20' THEN SUM(String1Quantity+String2Quantity+String4Quantity)
        WHEN String1 = '20' and String2 = '20' and String5 = '20' THEN SUM(String1Quantity+String2Quantity+String5Quantity)
        WHEN String1 = '20' and String3 = '20' and String4 = '20' THEN SUM(String1Quantity+String3Quantity+String4Quantity)
        WHEN String1 = '20' and String3 = '20' and String5 = '20' THEN SUM(String1Quantity+String3Quantity+String5Quantity)
        WHEN String1 = '20' and String4 = '20' and String5 = '20' THEN SUM(String1Quantity+String4Quantity+String5Quantity)
        WHEN String2 = '20' and String3 = '20' and String4 = '20' THEN SUM(String2Quantity+String3Quantity+String4Quantity)
        WHEN String2 = '20' and String3 = '20' and String5 = '20' THEN SUM(String2Quantity+String3Quantity+String5Quantity)
        WHEN String2 = '20' and String4 = '20' and String5 = '20' THEN SUM(String2Quantity+String4Quantity+String5Quantity)
        WHEN String3 = '20' and String4 = '20' and String5 = '20' THEN SUM(String3Quantity+String4Quantity+String5Quantity)
        WHEN String3 = '20' and String5 = '20' THEN SUM(String3Quantity+String5Quantity)
        WHEN String3 = '20' and String4 = '20' THEN SUM(String3Quantity+String4Quantity)
        WHEN String2 = '20' and String5 = '20' THEN SUM(String2Quantity+String5Quantity)
        WHEN String2 = '20' and String4 = '20' THEN SUM(String2Quantity+String4Quantity)
        WHEN String2 = '20' and String3 = '20' THEN SUM(String2Quantity+String3Quantity)
        WHEN String1 = '20' and String5 = '20' THEN SUM(String1Quantity+String5Quantity)
        WHEN String1 = '20' and String4 = '20' THEN SUM(String1Quantity+String4Quantity)
        WHEN String1 = '20' and String3 = '20' THEN SUM(String1Quantity+String3Quantity)
        WHEN String1 = '20' and String2 = '20' THEN SUM(String1Quantity+String2Quantity)
        WHEN String5 = '20' THEN SUM(String5Quantity)
        WHEN String4 = '20' THEN SUM(String4Quantity)
        WHEN String3 = '20' THEN SUM(String3Quantity)
        WHEN String2 = '20' THEN SUM(String2Quantity) 
        WHEN String1 = '20' THEN SUM(String1Quantity) 
    END AS '20',

    CASE 
        WHEN String1 = '30' and String2 = '30' and String3 = '30' and String4 = '30' and String5 = '30' THEN SUM(String1Quantity+String2Quantity+String3Quantity+String4Quantity+String5Quantity)
        WHEN String1 = '30' and String2 = '30' and String3 = '30' and String4 = '30' THEN SUM(String1Quantity+String2Quantity+String3Quantity+String4Quantity)
        WHEN String1 = '30' and String2 = '30' and String3 = '30' and String5 = '30' THEN SUM(String1Quantity+String2Quantity+String3Quantity+String5Quantity)
        WHEN String1 = '30' and String3 = '30' and String4 = '30' and String5 = '30' THEN SUM(String1Quantity+String3Quantity+String3Quantity+String4Quantity)
        WHEN String2 = '30' and String3 = '30' and String4 = '30' and String5 = '30' THEN SUM(String2Quantity+String3Quantity+String4Quantity+String5Quantity)
        WHEN String1 = '30' and String2 = '30' and String3 = '30' THEN SUM(String1Quantity+String2Quantity+String3Quantity)
        WHEN String1 = '30' and String2 = '30' and String4 = '30' THEN SUM(String1Quantity+String2Quantity+String4Quantity)
        WHEN String1 = '30' and String2 = '30' and String5 = '30' THEN SUM(String1Quantity+String2Quantity+String5Quantity)
        WHEN String1 = '30' and String3 = '30' and String4 = '30' THEN SUM(String1Quantity+String3Quantity+String4Quantity)
        WHEN String1 = '30' and String3 = '30' and String5 = '30' THEN SUM(String1Quantity+String3Quantity+String5Quantity)
        WHEN String1 = '30' and String4 = '30' and String5 = '30' THEN SUM(String1Quantity+String4Quantity+String5Quantity)
        WHEN String2 = '30' and String3 = '30' and String4 = '30' THEN SUM(String2Quantity+String3Quantity+String4Quantity)
        WHEN String2 = '30' and String3 = '30' and String5 = '30' THEN SUM(String2Quantity+String3Quantity+String5Quantity)
        WHEN String2 = '30' and String4 = '30' and String5 = '30' THEN SUM(String2Quantity+String4Quantity+String5Quantity)
        WHEN String3 = '30' and String4 = '30' and String5 = '30' THEN SUM(String3Quantity+String4Quantity+String5Quantity)
        WHEN String3 = '30' and String5 = '30' THEN SUM(String3Quantity+String5Quantity)
        WHEN String3 = '30' and String4 = '30' THEN SUM(String3Quantity+String4Quantity)
        WHEN String2 = '30' and String5 = '30' THEN SUM(String2Quantity+String5Quantity)
        WHEN String2 = '30' and String4 = '30' THEN SUM(String2Quantity+String4Quantity)
        WHEN String2 = '30' and String3 = '30' THEN SUM(String2Quantity+String3Quantity)
        WHEN String1 = '30' and String5 = '30' THEN SUM(String1Quantity+String5Quantity)
        WHEN String1 = '30' and String4 = '30' THEN SUM(String1Quantity+String4Quantity)
        WHEN String1 = '30' and String3 = '30' THEN SUM(String1Quantity+String3Quantity)
        WHEN String1 = '30' and String2 = '30' THEN SUM(String1Quantity+String2Quantity)
        WHEN String5 = '30' THEN SUM(String5Quantity)
        WHEN String4 = '30' THEN SUM(String4Quantity)
        WHEN String3 = '30' THEN SUM(String3Quantity)
        WHEN String2 = '30' THEN SUM(String2Quantity) 
        WHEN String1 = '30' THEN SUM(String1Quantity) 
    END AS '30',

    CASE 
        WHEN String1 = '40' and String2 = '40' and String3 = '40' and String4 = '40' and String5 = '40' THEN SUM(String1Quantity+String2Quantity+String3Quantity+String4Quantity+String5Quantity)
        WHEN String1 = '40' and String2 = '40' and String3 = '40' and String4 = '40' THEN SUM(String1Quantity+String2Quantity+String3Quantity+String4Quantity)
        WHEN String1 = '40' and String2 = '40' and String3 = '40' and String5 = '40' THEN SUM(String1Quantity+String2Quantity+String3Quantity+String5Quantity)
        WHEN String1 = '40' and String3 = '40' and String4 = '40' and String5 = '40' THEN SUM(String1Quantity+String3Quantity+String3Quantity+String4Quantity)
        WHEN String2 = '40' and String3 = '40' and String4 = '40' and String5 = '40' THEN SUM(String2Quantity+String3Quantity+String4Quantity+String5Quantity)
        WHEN String1 = '40' and String2 = '40' and String3 = '40' THEN SUM(String1Quantity+String2Quantity+String3Quantity)
        WHEN String1 = '40' and String2 = '40' and String4 = '40' THEN SUM(String1Quantity+String2Quantity+String4Quantity)
        WHEN String1 = '40' and String2 = '40' and String5 = '40' THEN SUM(String1Quantity+String2Quantity+String5Quantity)
        WHEN String1 = '40' and String3 = '40' and String4 = '40' THEN SUM(String1Quantity+String3Quantity+String4Quantity)
        WHEN String1 = '40' and String3 = '40' and String5 = '40' THEN SUM(String1Quantity+String3Quantity+String5Quantity)
        WHEN String1 = '40' and String4 = '40' and String5 = '40' THEN SUM(String1Quantity+String4Quantity+String5Quantity)
        WHEN String2 = '40' and String3 = '40' and String4 = '40' THEN SUM(String2Quantity+String3Quantity+String4Quantity)
        WHEN String2 = '40' and String3 = '40' and String5 = '40' THEN SUM(String2Quantity+String3Quantity+String5Quantity)
        WHEN String2 = '40' and String4 = '40' and String5 = '40' THEN SUM(String2Quantity+String4Quantity+String5Quantity)
        WHEN String3 = '40' and String4 = '40' and String5 = '40' THEN SUM(String3Quantity+String4Quantity+String5Quantity)
        WHEN String3 = '40' and String5 = '40' THEN SUM(String3Quantity+String5Quantity)
        WHEN String3 = '40' and String4 = '40' THEN SUM(String3Quantity+String4Quantity)
        WHEN String2 = '40' and String5 = '40' THEN SUM(String2Quantity+String5Quantity)
        WHEN String2 = '40' and String4 = '40' THEN SUM(String2Quantity+String4Quantity)
        WHEN String2 = '40' and String3 = '40' THEN SUM(String2Quantity+String3Quantity)
        WHEN String1 = '40' and String5 = '40' THEN SUM(String1Quantity+String5Quantity)
        WHEN String1 = '40' and String4 = '40' THEN SUM(String1Quantity+String4Quantity)
        WHEN String1 = '40' and String3 = '40' THEN SUM(String1Quantity+String3Quantity)
        WHEN String1 = '40' and String2 = '40' THEN SUM(String1Quantity+String2Quantity)
        WHEN String5 = '40' THEN SUM(String5Quantity)
        WHEN String4 = '40' THEN SUM(String4Quantity)
        WHEN String3 = '40' THEN SUM(String3Quantity)
        WHEN String2 = '40' THEN SUM(String2Quantity) 
        WHEN String1 = '40' THEN SUM(String1Quantity) 
    END AS '40',

    CASE 
        WHEN String1 = '50' and String2 = '50' and String3 = '50' and String4 = '50' and String5 = '50' THEN SUM(String1Quantity+String2Quantity+String3Quantity+String4Quantity+String5Quantity)
        WHEN String1 = '50' and String2 = '50' and String3 = '50' and String4 = '50' THEN SUM(String1Quantity+String2Quantity+String3Quantity+String4Quantity)
        WHEN String1 = '50' and String2 = '50' and String3 = '50' and String5 = '50' THEN SUM(String1Quantity+String2Quantity+String3Quantity+String5Quantity)
        WHEN String1 = '50' and String3 = '50' and String4 = '50' and String5 = '50' THEN SUM(String1Quantity+String3Quantity+String3Quantity+String4Quantity)
        WHEN String2 = '50' and String3 = '50' and String4 = '50' and String5 = '50' THEN SUM(String2Quantity+String3Quantity+String4Quantity+String5Quantity)
        WHEN String1 = '50' and String2 = '50' and String3 = '50' THEN SUM(String1Quantity+String2Quantity+String3Quantity)
        WHEN String1 = '50' and String2 = '50' and String4 = '50' THEN SUM(String1Quantity+String2Quantity+String4Quantity)
        WHEN String1 = '50' and String2 = '50' and String5 = '50' THEN SUM(String1Quantity+String2Quantity+String5Quantity)
        WHEN String1 = '50' and String3 = '50' and String4 = '50' THEN SUM(String1Quantity+String3Quantity+String4Quantity)
        WHEN String1 = '50' and String3 = '50' and String5 = '50' THEN SUM(String1Quantity+String3Quantity+String5Quantity)
        WHEN String1 = '50' and String4 = '50' and String5 = '50' THEN SUM(String1Quantity+String4Quantity+String5Quantity)
        WHEN String2 = '50' and String3 = '50' and String4 = '50' THEN SUM(String2Quantity+String3Quantity+String4Quantity)
        WHEN String2 = '50' and String3 = '50' and String5 = '50' THEN SUM(String2Quantity+String3Quantity+String5Quantity)
        WHEN String2 = '50' and String4 = '50' and String5 = '50' THEN SUM(String2Quantity+String4Quantity+String5Quantity)
        WHEN String3 = '50' and String4 = '50' and String5 = '50' THEN SUM(String3Quantity+String4Quantity+String5Quantity)
        WHEN String3 = '50' and String5 = '50' THEN SUM(String3Quantity+String5Quantity)
        WHEN String3 = '50' and String4 = '50' THEN SUM(String3Quantity+String4Quantity)
        WHEN String2 = '50' and String5 = '50' THEN SUM(String2Quantity+String5Quantity)
        WHEN String2 = '50' and String4 = '50' THEN SUM(String2Quantity+String4Quantity)
        WHEN String2 = '50' and String3 = '50' THEN SUM(String2Quantity+String3Quantity)
        WHEN String1 = '50' and String5 = '50' THEN SUM(String1Quantity+String5Quantity)
        WHEN String1 = '50' and String4 = '50' THEN SUM(String1Quantity+String4Quantity)
        WHEN String1 = '50' and String3 = '50' THEN SUM(String1Quantity+String3Quantity)
        WHEN String1 = '50' and String2 = '50' THEN SUM(String1Quantity+String2Quantity)
        WHEN String5 = '50' THEN SUM(String5Quantity)
        WHEN String4 = '50' THEN SUM(String4Quantity)
        WHEN String3 = '50' THEN SUM(String3Quantity)
        WHEN String2 = '50' THEN SUM(String2Quantity) 
        WHEN String1 = '50' THEN SUM(String1Quantity) 
    END AS '50'

From #Split
Group by Id, String1, String2, String3, string4, String5

drop table #Split

首先,正如我在评论中所写:解决此问题的方法是修复损坏的数据模型。有关详细信息,请阅读 Is storing a delimited list in a database column really that bad?,您会在其中看到很多原因,为什么这个问题的答案是 绝对是!

话虽这么说,我知道很多时候,由于许多不同的原因,更改数据库结构不是一种选择,即使这可以解决很多问题.

现在,根据您的字符串操作函数,我假设您正在使用 SQL-Server(请注意,对于每个 sql 问题,您应该始终指定 rdbms 和版本,或者如果您确实需要跨数据库解决方案,请使用

因此,根据您的假设,您最好的选择可能是使用 Jeff Moden's DelimitedSplit8K UDF 将字符串分解为 table.
此函数将 return 一个包含两列的 table - 一列用于子字符串,一列用于它在源字符串中的索引 - 这正是您开始构建您想要的结果所需要的。

因此,基于该函数、几个常见的 table 表达式、数据透视表和条件聚合,我提出了以下解决方案:

WITH CTE1 AS
(
    SELECT  Id,
            CAST(IIF(ItemNumber % 2 = 0, Item, NULL) as int) As Data, 
            IIF(ItemNumber % 2 = 1, Item, NULL) As Name, 
            IIF(ItemNumber % 2 = 0, ItemNumber - 1, ItemNumber) As PairNumber
    FROM  #Split
    CROSS APPLY dbo.DelimitedSplit8K(SplitString, ':')
    WHERE Item IS NOT NULL
    AND Item <> ''
), CTE2 AS
(
    SELECT Id, PairNumber, MAX(Data) As Data, MAX(Name) As Name
    FROM CTE1
    GROUP BY Id, PairNumber
)

, CTEPivot AS
(
    SELECT Id, [10], [20], [30], [40], [50]
    FROM 
    (
    SELECT Id, SUM(Data) As Data, Name
    FROM CTE2 
    GROUP BY Id, Name
    ) D
    PIVOT  
    (  
    AVG(Data) 
    FOR Name IN ([10], [20], [30], [40], [50])  
    ) AS PivotTable
)

SELECT  Id, 
        MAX([10]) As [10], 
        MAX([20]) As [20], 
        MAX([30]) As [30], 
        MAX([40]) As [40], 
        MAX([50]) As [50] 
FROM CTEPivot
GROUP BY Id;  

结果:

+----+----+----+----+----+----+
| Id | 10 | 20 | 30 | 40 | 50 |
+----+----+----+----+----+----+
| 1  | 1  | 7  |    |    |    |
+----+----+----+----+----+----+
| 2  |    | 1  |    |    |    |
+----+----+----+----+----+----+
| 3  | 3  |    |    |    |    |
+----+----+----+----+----+----+
| 4  |    |    | 4  | 1  | 3  |
+----+----+----+----+----+----+

You can see a live demo on rextester.