Sql 从单行中选择逗号分隔值的子查询

Sql 从单行中选择逗号分隔值的子查询,sql,sql-server,Sql,Sql Server,从Select查询中,我在单行中获得以下值,而不是在不同的行中: Id Statuses --- ------------- 1 Released,In Progress,Completed 现在我想写一个查询,以便获得所有处于状态的订单: Select * from Orders where Status in (Select Statusesfrom StatusTable) 采用这些拆分器之一。你可以自己写,但你会发现很多人都在研究这些: 这会将您的

从Select查询中,我在单行中获得以下值,而不是在不同的行中:

Id        Statuses
---     -------------
1       Released,In Progress,Completed
现在我想写一个查询,以便获得所有处于状态的订单:

Select * from Orders where Status in (Select Statusesfrom StatusTable)

采用这些拆分器之一。你可以自己写,但你会发现很多人都在研究这些:

这会将您的值拆分为一个具有单个列的表。在对其运行函数后,您可以加入它,如:

Select o.* from Orders o
inner join splitTable s on o.keyColumn = s.Column

采用这些拆分器之一。你可以自己写,但你会发现很多人都在研究这些:

这会将您的值拆分为一个具有单个列的表。在对其运行函数后,您可以加入它,如:

Select o.* from Orders o
inner join splitTable s on o.keyColumn = s.Column
经过大量讨论(如下所示)和测试,我修改了解析函数。新函数将解析250000个字符串,在400ms内生成1889108行

Declare @YourTable table (Id int,Statuses varchar(250))
Insert into @YourTable values 
(1,'Released,In Progress,Completed'),
(2,'Released,In Progress')

Select A.ID
      ,B.* 
from @YourTable A
Cross Apply (Select * from [dbo].[udf-Str-Parse-8K](A.Statuses,',')) B
Order By ID,Key_PS
返回

ID  Key_PS  Key_Value   Key_Pos
1   1       Released    1
1   2       In Progress 10
1   3       Completed   22
2   1       Released    1
2   2       In Progress 10
如果需要的话,UDF

CREATE FUNCTION [dbo].[udf-Str-Parse-8K](@String varchar(8000), @Delimiter varchar(50))
Returns Table 
As

--Usage: Select * from [dbo].[udf-Str-Parse-8K]('Dog,Cat,House,Car',',')
--       Select * from [dbo].[udf-Str-Parse-8K]('John||Cappelletti||was||here','||')
--       Select * from [dbo].[udf-Str-Parse-8K]('The quick brown fox',' ')

Return (
   with cte1(N)   As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
        cte2(N)   As (Select Top (IsNull(DataLength(@String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 a, cte1 b, cte1 c, cte1 d) A ),
        cte3(N)   As (Select 1 Union All Select t.N+DataLength(@Delimiter) From cte2 t Where Substring(@String,t.N,DataLength(@Delimiter)) = @Delimiter),
        cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(@Delimiter,@String,s.N),0)-S.N,8000) From cte3 S)

   Select Key_PS    = Row_Number() over (Order By A.N)
         ,Key_Value = Substring(@String, A.N, A.L) 
         ,Key_Pos   = A.N
   From   cte4 A
)
经过大量的讨论(如下所示)和测试,我修改了我的解析函数。新函数将解析250000个字符串,在400ms内生成1889108行

Declare @YourTable table (Id int,Statuses varchar(250))
Insert into @YourTable values 
(1,'Released,In Progress,Completed'),
(2,'Released,In Progress')

Select A.ID
      ,B.* 
from @YourTable A
Cross Apply (Select * from [dbo].[udf-Str-Parse-8K](A.Statuses,',')) B
Order By ID,Key_PS
返回

ID  Key_PS  Key_Value   Key_Pos
1   1       Released    1
1   2       In Progress 10
1   3       Completed   22
2   1       Released    1
2   2       In Progress 10
如果需要的话,UDF

CREATE FUNCTION [dbo].[udf-Str-Parse-8K](@String varchar(8000), @Delimiter varchar(50))
Returns Table 
As

--Usage: Select * from [dbo].[udf-Str-Parse-8K]('Dog,Cat,House,Car',',')
--       Select * from [dbo].[udf-Str-Parse-8K]('John||Cappelletti||was||here','||')
--       Select * from [dbo].[udf-Str-Parse-8K]('The quick brown fox',' ')

Return (
   with cte1(N)   As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
        cte2(N)   As (Select Top (IsNull(DataLength(@String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 a, cte1 b, cte1 c, cte1 d) A ),
        cte3(N)   As (Select 1 Union All Select t.N+DataLength(@Delimiter) From cte2 t Where Substring(@String,t.N,DataLength(@Delimiter)) = @Delimiter),
        cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(@Delimiter,@String,s.N),0)-S.N,8000) From cte3 S)

   Select Key_PS    = Row_Number() over (Order By A.N)
         ,Key_Value = Substring(@String, A.N, A.L) 
         ,Key_Pos   = A.N
   From   cte4 A
)
如果您使用的是SQL Server 2016,只需使用STRING_SPLIT()函数中的几个调整

     SELECT *
     FROM Orders 
      WHERE Status IN (SELECT Value FROM  StatusTable
                         CROSS APPLY STRING_SPLIT(Statuses,','))
如果您使用的是SQL Server 2016,请使用STRING_SPLIT()函数

     SELECT *
     FROM Orders 
      WHERE Status IN (SELECT Value FROM  StatusTable
                         CROSS APPLY STRING_SPLIT(Statuses,','))

StatusTable
中得到的是单个字符串,而不是值列表。请从两个表中上载一些示例数据。这样问题就更清楚了。使用动态sql或编写函数拆分这些值并以单列输出的形式返回。您是否有可能修复问题而不是处理坏数据?问题是因为在一列中存储多个值违反了1NF。现在,您正因为它而努力获取所需的数据。如果有可能,请修复数据,您的查询将非常简单。您从
StatusTable
获得的是单个字符串,不是值列表。请上载两个表中的一些示例数据。这样问题就更清楚了。使用动态sql或编写函数拆分这些值并以单列输出的形式返回。是否有可能解决问题而不是处理坏数据?问题是因为在一列中存储多个值违反了1NF。现在,您正因为它而努力获取所需的数据。如果可能的话,修复数据,查询就会简单。这是一个多语句表值函数。在中等数据集上,它们通常比标量函数更差。有许多内联表值函数比这更好@SeanLange是的,你说得对,但表演仍然令人尊敬。30000条记录145ms。我知道这是你写的,它很好,但一个合适的内联函数就在你的指尖……为什么一直发布一条速度不快的记录?@SeanLange每个运行10次(与上面提到的30K相同)。您的XML版本平均快24毫秒。唯一的一件事通常是需要行号。因此,从现在起,我将根据需要使用其中一种。谢谢你的链接和提示。当然不是我的XML版本,但很高兴你做了一些测试。当您有一百万行或者每行有更多的元素时,您才真正开始注意到差异。当其中一个或两个开始发生时,性能差异真正开始显现出来。在每行只有几个元素的小数据集上,差异可以忽略不计。这是一个多语句表值函数。在中等数据集上,它们通常比标量函数更差。有许多内联表值函数比这更好@SeanLange是的,你说得对,但表演仍然令人尊敬。30000条记录145ms。我知道这是你写的,它很好,但一个合适的内联函数就在你的指尖……为什么一直发布一条速度不快的记录?@SeanLange每个运行10次(与上面提到的30K相同)。您的XML版本平均快24毫秒。唯一的一件事通常是需要行号。因此,从现在起,我将根据需要使用其中一种。谢谢你的链接和提示。当然不是我的XML版本,但很高兴你做了一些测试。当您有一百万行或者每行有更多的元素时,您才真正开始注意到差异。当其中一个或两个开始发生时,性能差异真正开始显现出来。在每行只有几个元素的小数据集上,差异可以忽略不计。