SQL Server按顺序加入

Lui*_*ese 7 sql sql-server join sql-server-2008

我在输入中有2个字符串,例如'1,5,6'和'2,89,9',具有相同数量的元素(3或加号).我想要的那两个字符串作为"纵坐标连接"

1   2
5   89
6   9
Run Code Online (Sandbox Code Playgroud)

我想要分配一个rownumber并在2个结果集之间建立一个连接

SELECT a.item, b.item  FROM 
  (
  SELECT  
  ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS rownumber,
  *  FROM dbo.Split('1,5,6',',')
  ) AS a
  INNER JOIN   
  (
  SELECT  
  ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS rownumber,
  *  FROM dbo.Split('2,89,9',',')
 ) AS b ON a.rownumber = b.rownumber 
Run Code Online (Sandbox Code Playgroud)

这是最好的做法吗?

Mat*_*lie 13

dbo.Split()返回数据集时,您所做的任何事情都不能绝对确定地分配您想要的row_number(基于它们在字符串中的顺序).SQL永远不会保证在没有ORDER BY实际与数据相关的情况下进行排序.

随着你的使用技巧,(SELECT 0)你可能经常得到正确的价值观.大概十分频繁.但这绝不 保证.偶尔你得到错误的订单.

您最好的选择是重新编码dbo.Split()以在解析字符串时分配row_number.只有这样才能100%确定row_number确实对应于项目在列表中的位置.

然后按照您的建议加入它们,并获得您想要的结果.


除此之外,这个想法对我来说似乎没问题.虽然您可能希望考虑FULL OUTER JOIN一个列表可能比另一个列表更长.


Ari*_*ion 7

你也可以这样做

考虑你的分裂函数,如下所示:

CREATE FUNCTION Split
(
  @delimited nvarchar(max),
  @delimiter nvarchar(100)
) RETURNS @t TABLE
(
  id int identity(1,1),
  val nvarchar(max)
)
AS
BEGIN
  declare @xml xml
  set @xml = N'<root><r>' + replace(@delimited,@delimiter,'</r><r>') + '</r></root>'

  insert into @t(val)
  select 
    r.value('.','varchar(5)') as item
  from @xml.nodes('//root/r') as records(r)

  RETURN
END
GO
Run Code Online (Sandbox Code Playgroud)

这对JOIN他们来说将是一项简单的任务.像这样:

SELECT
    *
FROM
    dbo.Split('1,5,6',',') AS a
    JOIN dbo.Split('2,89,9',',') AS b
        ON a.id=b.id
Run Code Online (Sandbox Code Playgroud)

这样做的好处是你不需要任何东西 ROW_NUMBER() OVER(ORDER BY SELECT 0)

编辑

与注释一样,使用递归拆分函数可以提高性能.也许是这样的:

CREATE FUNCTION dbo.Split (@s varchar(512),@sep char(1))
RETURNS table
AS
RETURN (
    WITH Pieces(pn, start, stop) AS (
      SELECT 1, 1, CHARINDEX(@sep, @s)
      UNION ALL
      SELECT pn + 1, stop + 1, CHARINDEX(@sep, @s, stop + 1)
      FROM Pieces
      WHERE stop > 0
    )
    SELECT pn,
      SUBSTRING(@s, start, CASE WHEN stop > 0 THEN stop-start ELSE 512 END) AS s
    FROM Pieces
  )
GO
Run Code Online (Sandbox Code Playgroud)

然后选择是这样的:

SELECT
    *
FROM
    dbo.Split('1,5,6',',') AS a
    JOIN dbo.Split('2,89,9',',') AS b
        ON a.pn=b.pn
Run Code Online (Sandbox Code Playgroud)