CTE /递归查询拆分分隔的字符串只返回一行?

时间:2015-09-24 21:37:23

标签: sql-server xml sql-server-2008 recursion

我已经应用了一个“借用”解决方案将分隔的字符串拆分成行(我在MSSQL 2008 R2中工作),但该解决方案特定于CTE /递归查询。这很好用,但只转换一行数据。我如何调整它以返回表中的所有行(或者,更好的是,能够包含where子句)?

我已经开始研究这两天,因为我对CTE /递归查询或XML没有太多经验......欢迎任何专业知识!谢谢!!

DECLARE @RowData varchar(2000)
DECLARE @SplitOn varchar(1)
DECLARE @ObjectID int

SELECT 
@ObjectID = ObjectID, @RowData = ObjectName, @SplitOn = ';' from Objects 

declare @xml as xml
SET @XML  = '<t><r>' +  Replace(@RowData , @spliton, '</r><r>') + '</r></t>'  

select @objectid as objectid, rtrim(ltrim(t.r.value('.', 'VARCHAR(8000)'))) as splitvalue
from @xml.nodes('/t/r') as t(r) 

2 个答案:

答案 0 :(得分:0)

我首先要创建一个表值函数来执行字符串拆分,就像在此处找到的那样:http://ole.michelsen.dk/blog/split-string-to-table-using-transact-sql.html

然后使用OUTER APPLY对表中的行使用它们。这是一个查询,因此您可以应用where子句。下面是一个函数创建示例,一个临时表,我填充了一些测试数据和select语句。

CREATE FUNCTION [dbo].[Split]
(
    @String NVARCHAR(4000),
    @Delimiter NCHAR(1)
)
RETURNS TABLE
AS
RETURN
(
    WITH Split(stpos,endpos)
    AS(
        SELECT 0 AS stpos, CHARINDEX(@Delimiter,@String) AS endpos
        UNION ALL
        SELECT endpos+1, CHARINDEX(@Delimiter,@String,endpos+1)
            FROM Split
            WHERE endpos > 0
    )
    SELECT 'Id' = ROW_NUMBER() OVER (ORDER BY (SELECT 1)),
        'Data' = SUBSTRING(@String,stpos,COALESCE(NULLIF(endpos,0),LEN(@String)+1)-stpos)
    FROM Split
)
GO

IF ( OBJECT_ID(N'tmpdb..#Object') IS NOT NULL ) DROP TABLE [#Object];

CREATE TABLE [#Object]
(
  [ObjectId] INT NOT NULL IDENTITY(1, 1)
, [Object] VARCHAR(1000) NOT NULL
);

INSERT INTO #Object
        ( [Object] )
VALUES  ( 'brad;bill;jerry'), ('Scott;MATT;DEAN'), ('larry;bob;john')

GO

SELECT  [tt].[ObjectId]
      , [s].[Data]
FROM    #Object AS [tt]
        OUTER APPLY dbo.Split([tt].[Object], ';') AS s
WHERE   tt.[ObjectId] < 3

只需用你的表替换临时表。希望有所帮助!

答案 1 :(得分:0)

您没有获得多行的原因是因为您以编程方式而不是以集合为中心的方式考虑集合。

SELECT @ObjectID ....获取一行......最后一行。

我建议您使用CROSS APPLY:

-- Data Setup
CREATE TABLE #Objects ( ObjectID INTEGER, ObjectName VARCHAR(2000) )
INSERT INTO #Objects ( ObjectID, ObjectName )
SELECT 1, 'foo;bar' UNION
SELECT 2, 'biz;baz;buz'

-- The Meat and Potatoes. You can add a WHERE to your inner or outer query
SELECT 
  ObjectID,
  RTRIM( LTRIM( t.r.value( '.', 'VARCHAR(8000)' ) ) ) AS splitvalue
FROM
  (
    SELECT
      ObjectID,
      CONVERT( XML, '<t><r>' + REPLACE( ObjectName, ';', '</r><r>' ) + '</r></t>' ) AS xml_part
    FROM
      #Objects
  ) AS xml_part_builder
  CROSS APPLY xml_part_builder.xml_part.nodes('/t/r') AS t(r)

-- CLEAN UP
DROP TABLE #Objects

如果有帮助,请告诉我。

干杯!