2017-01-03 4 views
0

Я пытаюсь разобрать некоторые значения, разделенные запятыми, из столбца в SQL Server 2012, сохраняя данные из столбцов слева и справа.SQL Server 2012 Comma Parsing

Я видел похожие решения, но ни один из них не был тем, что я ищу.

У меня есть это:

FirstName LastName userid Regions   ViewCosts HelpReviewCosts 
--------------------------------------------------------------------- 
Darron  Peters  ya00003 All    y   y 
John  Davies  ya30982 NA, EM, AP, LA  n   n 

Я пытаюсь разобрать регионов колонки, так что я могу получить это:

FirstName LastName userid Regions   ViewCosts HelpReviewCosts 
--------------------------------------------------------------------- 
Darron  Peters  ya00003 All    y   y 
John  Davies  ya30982 NA     n   n 
John  Davies  ya30982 EM     n   n 
John  Davies  ya30982 AP     n   n 
John  Davies  ya30982 LA     n   n 
+1

Возможный дубликат [SQL Server разделить CSV на несколько строк] (http://stackoverflow.com/questions/9811161/sql-server-split-csv-in-multiple-rows) – GurV

+4

Почему бы вам не исправить проблему с дизайном? Используйте таблицу * отдельно *, которая связывает людей с регионами. То, что вы показываете здесь, разбивает даже первую нормальную форму. Если у вас есть это, для получения данных в требуемой форме требуется простой JOIN –

+0

Если вы контролируете схему базы данных, вы должны нормализовать данные, а не хранить список CSV. –

ответ

2

Есть тысячи примеров о том, как разделить/разбора строк. Ниже приведены два образца: один с UDF, а другой без него. Оба используют CROSS ОТНОСИТЬСЯ

С UDF

Declare @Yourtable table (FirstName varchar(25) ,LastName varchar(25),userid varchar(25), Regions varchar(50), ViewCosts varchar(25), HelpReviewCosts varchar(25)) 
Insert Into @Yourtable values 
('Darron','Peters','ya00003','All','y','y'), 
('John','Davies','ya30982','NA, EM, AP, LA','n','n') 

Select A.FirstName 
     ,A.LastName  
     ,A.userid 
     ,Regions =B.RetVal 
     ,A.ViewCosts 
     ,A.HelpReviewCosts 
From @Yourtable A 
Cross Apply [dbo].[udf-Str-Parse](A.Regions,',') B 

Without A UDF

Select A.FirstName 
     ,A.LastName  
     ,A.userid 
     ,Regions =B.RetVal 
     ,A.ViewCosts 
     ,A.HelpReviewCosts 
From @Yourtable A 
Cross Apply ( 
       Select RetSeq = Row_Number() over (Order By (Select null)) 
         ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)'))) 
       From (Select x = Cast('<x>'+ replace((Select A.Regions as [*] For XML Path('')),',','</x><x>')+'</x>' as xml).query('.')) as A 
       Cross Apply x.nodes('x') AS B(i) 
    ) B 

Оба Возвращения

enter image description here

ОДС при необходимости

CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@Delimiter varchar(10)) 
Returns Table 
As 
Return ( 
    Select RetSeq = Row_Number() over (Order By (Select null)) 
      ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)'))) 
    From (Select x = Cast('<x>'+ replace((Select @String as [*] For XML Path('')),@Delimiter,'</x><x>')+'</x>' as xml).query('.')) as A 
    Cross Apply x.nodes('x') AS B(i) 
); 
--Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',') 
--Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ') 
--Select * from [dbo].[udf-Str-Parse]('this,is,<test>,for,< & >',',') 
0

Я предлагаю вам использовать функцию STRING_SPLIT

WITH 
CTE_Sample AS 
(
    SELECT 'All'   AS txt 
    UNION ALL 
    SELECT 'NA, EM, AP, LA' AS txt 
) 

SELECT 
    txt, 
    value 
    FROM CTE_Sample 
    CROSS APPLY STRING_SPLIT(txt, ','); 
0

Если вы не хотите «UDF 'и' string_split ', тогда вы можете использовать этот запрос. подходит для больших строк с запятыми, а также намного быстрее по сравнению с другими ...

`CREATE TABLE TB (Number INT) 
DECLARE @I INT=0 
WHILE @I<1000 
BEGIN 
INSERT INTO TB VALUES (@I) 
SET @[email protected]+1 
END 
SELECT 
    FirstName 
    ,LastName 
    ,userid 
    ,S_DATA 
    ,ViewCosts 
    ,HelpReviewCosts 
FROM (
    SELECT 
      FirstName 
      ,LastName 
      ,userid 
      ,CASE WHEN LEN(LIST2)>0 THEN LTRIM(RTRIM(SUBSTRING(LIST2, NUMBER+1, CHARINDEX(',', LIST2, NUMBER+1)-NUMBER - 1))) 
        ELSE NULL 
      END AS S_DATA 
      ,ViewCosts 
      ,HelpReviewCosts 
      ,NUMBER 
    FROM(
     SELECT FirstName 
       ,LastName 
       ,userid 
       ,','+Regions+',' LIST2 
       ,ViewCosts 
       ,HelpReviewCosts 
       FROM Tb1 
     )DT 
     LEFT OUTER JOIN TB N ON (N.NUMBER < LEN(DT.LIST2)) OR (N.NUMBER=1 AND DT.LIST2 IS NULL) 
     WHERE SUBSTRING(LIST2, NUMBER, 1) = ',' OR LIST2 IS NULL 
    ) DT2 
    WHERE S_DATA<>'' 

this is my Output