MS SQL:从拆分字符串中选择并保留原始订单

时间:2014-06-06 07:35:26

标签: sql sql-server

我从Split查询中选择了这个简单的。

SELECT [id] 
FROM [user] WHERE [id] IN (
    SELECT items FROM dbo.Split('8004, 7943, 2658, 6223, 7826', ',')
)

问题是,用户表上的select语句命令ID递增,但我想保留ID在Split字符串函数中出现的原始顺序。

这是我的分割功能代码:

ALTER FUNCTION [dbo].[Split](@String VARCHAR(8000), @Delimiter CHAR(1))       
RETURNS @temptable TABLE (items VARCHAR(8000))       
 AS       
 BEGIN       
 DECLARE @idx INT       
 DECLARE @slice VARCHAR(8000)       

 SELECT @idx = 1       
     IF len(@String)<1 OR @String IS NULL  RETURN       

 WHILE @idx!= 0       
 BEGIN       
     SET @idx = charindex(@Delimiter,@String)       
     IF @idx!=0       
         SET @slice = LEFT(@String,@idx - 1)       
     ELSE       
         SET @slice = @String       

     IF(LEN(@slice)>0)  
         INSERT INTO @temptable(Items) VALUES(@slice)       

     SET @String = RIGHT(@String,len(@String) - @idx)       
     IF LEN(@String) = 0 BREAK       
 END   
 RETURN       
 END

所以,我目前得到的结果是:

2658
6223
7826
7943
8004

我需要的是:

8004
7943
2658
6223
7826

有关如何实现这一目标的任何想法?

谢谢!

2 个答案:

答案 0 :(得分:0)

将函数重写为:

Create FUNCTION [dbo].[Split](@String VARCHAR(8000), @Delimiter CHAR(1))       
RETURNS @temptable TABLE (items VARCHAR(8000), rownum int)       
 AS       
 BEGIN       
 DECLARE @idx INT       
 DECLARE @slice VARCHAR(8000)       

 SELECT @idx = 1       
     IF len(@String)<1 OR @String IS NULL  RETURN       

 WHILE @idx!= 0       
 BEGIN       
     SET @idx = charindex(@Delimiter,@String)       
     IF @idx!=0       
         SET @slice = LEFT(@String,@idx - 1)       
     ELSE       
         SET @slice = @String       

     IF(LEN(@slice)>0)  
         INSERT INTO @temptable(Items) VALUES(@slice)       

     SET @String = RIGHT(@String,len(@String) - @idx)       
     IF LEN(@String) = 0 BREAK 

     --Added Rownumber here:
     ;With CTE as
     (
         Select Row_number() over (Order By (select 1)) as rownum
         ,Items
         FROM  @temptable
      )      
     Update T
     set T.rownum = CTE.rownum
     From @temptable T
     JOIN CTE ON T.Items = CTE.Items
 END   
 RETURN       
 END
 Go

然后查询为:

SELECT U.[id] 
FROM [test_user] U
Join (SELECT items,rownum FROM dbo.Split('8004, 7943, 2658, 6223, 7826', ',')) 
as T on T.items = U.id
order by T.rownum asc

点击此处Demo

答案 1 :(得分:0)

只需从包含订单的dbo.Split例程返回附加字段(&#34; N&#34;例如)

N   Value
1   8004
2   7943
3   2658

功能可能看起来像

CREATE FUNCTION [dbo].[Split](@String VARCHAR(8000), @Delimiter CHAR(1))       
RETURNS @temptable TABLE (N int, items VARCHAR(8000))       
 AS       
 BEGIN       
 DECLARE @idx INT       
 DECLARE @slice VARCHAR(8000)
 DECLARE @N int SET @N = 1

 SELECT @idx = 1       
     IF len(@String)<1 OR @String IS NULL  RETURN       

 WHILE @idx!= 0       
 BEGIN       
     SET @idx = charindex(@Delimiter,@String)       
     IF @idx!=0       
         SET @slice = LEFT(@String,@idx - 1)       
     ELSE       
         SET @slice = @String       

     IF(LEN(@slice)>0) BEGIN  
         INSERT INTO @temptable(N, Items) VALUES(@N, @slice)       
         SET @N = @N + 1
     END

     SET @String = RIGHT(@String,len(@String) - @idx)       
     IF LEN(@String) = 0 BREAK       
 END   
 RETURN       
 END
 GO

或者您可能希望用CTE版本替换拆分例程:

CREATE FUNCTION dbo.Split (@String varchar(8000), @Delimiter char(1))
RETURNS TABLE
AS
RETURN (
    WITH Splitter AS (
      SELECT
        CHARINDEX(@Delimiter, @String) AS Pos,
        0 AS LastPos,
        1 AS N
      UNION ALL SELECT
        CHARINDEX(@Delimiter, @String, Pos + 1),
        Pos,
        N + 1
      FROM
        Splitter
      WHERE
        Pos > 0
    )
    SELECT
        N,
        LTRIM(RTRIM(SUBSTRING(@String, LastPos + 1, CASE WHEN Pos = 0 then 80000 ELSE Pos - LastPos - 1 END))) AS items
    FROM
        Splitter
  )
GO

然后用

替换您的查询
SELECT
    *
FROM
    [user]
    INNER JOIN dbo.Split() AS [split] ON ([user].[id] = [split].[items])
ORDER BY
    [split].[N] ASC

更改dbo.Split更好,因为它不会影响现有代码,但会为您提供可重复使用的解决方案。