2015-09-24 1 views
0

Я применил «заимствованное» решение для разделения строки с разделителями на строки (я работаю в MSSQL 2008 R2), но это решение было специфичным для CTE/рекурсивных запросов. Это отлично работает, но только преобразует один ряд данных. Как мне настроить это, чтобы вернуть все строки в моей таблице (или, еще лучше, включить предложение where)?CTE/рекурсивный запрос для разделения строк с разделителями, возвращающих только одну строку?

Я испугался изучения этого в течение двух дней, и поскольку я не слишком опытен с 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) 
+1

Каковы ваши данные в таблице? –

ответ

0

Я хотел бы начать с созданием оцененной табличной функции, которая делает строку расщеплению как найденному здесь: http://ole.michelsen.dk/blog/split-string-to-table-using-transact-sql.html

затем использовать OUTER APPLY, чтобы использовать их против строк в таблице. Это запрос, поэтому вы можете применить предложение where. Ниже приведен пример создания функции, таблицы temp, заполненной некоторыми тестовыми данными и оператором 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 

Просто замените таблицу темповых таблиц (-ов). Надеюсь, это поможет!

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 

Позвольте мне знать, если это помогает.

Cheers!

+0

Большое спасибо за решение и объяснение. Я столкнулся с проблемами с XML, потому что у моих строк были пробелы, но помимо этого ваше решение отлично работало. @DB_Brad, я закончил с вашим решением (вызвав TVF в запрос), я ценю простоту функции, предложенной вами. Как я уже упоминал выше, я столкнулся с проблемами с XML, поэтому ваше решение отлично подходило. Спасибо! –

Смежные вопросы