簡體   English   中英

使用MSSQL將表格列中的逗號分隔值拆分為行?

[英]Split comma separated value from table column into rows using mssql?

我想通過分割它們的源將一些數據放入mssql視圖。 我有一些列,其中電話號碼存儲為逗號分隔的值(每個都包含電話聯系人)。 我不想與每個“電話聯系人”一起工作,所以我希望每行都看到他們。 並且每行還必須包含來自拆分的聯系順序。

資源:

Department   | SaleMngrs   | Operators      | Secretary
----------------------------------------------------------
'Technics'   | '123,456,77'| '+122,Line 1'  | '77889,112'
'Development'| '123,3366'  | null           | 'Lines 7-8'

如您所見,逗號分隔的值是一團糟,但分隔符為, (逗號)。

想要的結果:

Department   | TypeOfContact  | Contact    | ContactOrder
------------------------------------------------------
'Technics'   | 'SalesManagers'| '123'      | 1
'Technics'   | 'SalesManagers'| '456'      | 2
'Technics'   | 'SalesManagers'| '77'       | 3
'Technics'   | 'Operators'    | '+122'     | 1
'Technics'   | 'Operators'    | 'Line 1'   | 2
'Technics'   | 'Secretary'    | '77889'    | 1
'Technics'   | 'Secretary'    | '112'      | 2
'Development'| 'SalesManagers'| '123'      | 1
'Development'| 'SalesManagers'| '3366'     | 2
'Development'| 'Secretary'    | 'Lines 7-8'| 1

不需要UDF或SP。 SELECT

請嘗試以下操作(它與數據結構一樣漂亮)-使用UNPIVOT優化:

set nocount on

declare @source table (Department varchar(50), SaleMngrs varchar(50), Operators varchar(50), Secretary varchar(50));

insert into @source values ('Technics'   , '123,456,77', '+122,Line 1'  , '77889,112');
insert into @source values ('Development', '123,3366'  , null           , 'Lines 7-8');

;WITH cte (Department, TypeOfContact, Contact)
AS
(
   SELECT Department, TypeOfContact, cast('<Contact><c>' + replace(Contact,',','</c><c>') + '</c></Contact>' as xml) AS Contact
     FROM (SELECT Department, SaleMngrs AS SalesManagers, Operators, Secretary FROM @source) p
     UNPIVOT (Contact FOR TypeOfContact IN (SalesManagers, Operators, Secretary)) AS unpvt
)
Select Department
     , TypeOfContact
     , Contact.c.value('.','varchar(20)') AS Contact
     , ROW_NUMBER() OVER (PARTITION BY Department, TypeOfContact ORDER BY Department, TypeOfContact) AS ContactOrder
FROM cte CROSS APPLY Contact.nodes('/Contact/c') as Contact(c);

OUTPUT

Department   TypeOfContact Contact              ContactOrder
------------ ------------- -------------------- --------------------
Development  SalesManagers 123                  1
Development  SalesManagers 3366                 2
Development  Secretary     Lines 7-8            1
Technics     Operators     +122                 1
Technics     Operators     Line 1               2
Technics     SalesManagers 123                  1
Technics     SalesManagers 456                  2
Technics     SalesManagers 77                   3
Technics     Secretary     112                  1
Technics     Secretary     77889                2

編輯:使用UNPIVOT(以下原始信息)的優化查詢:

set nocount on

declare @source table (Department varchar(50), SaleMngrs varchar(50), Operators varchar(50), Secretary varchar(50));

insert into @source values ('Technics'   , '123,456,77', '+122,Line 1'  , '77889,112');
insert into @source values ('Development', '123,3366'  , null           , 'Lines 7-8');

;WITH cte (Department, SalesMngrs, Operators, Secretary)
AS
(
   select Department
        , cast('<SaleMngrs><c>' + replace(SaleMngrs,',','</c><c>') + '</c></SaleMngrs>' as xml) AS SalesMngrs
        , cast('<Operators><c>' + replace(Operators,',','</c><c>') + '</c></Operators>' as xml) AS Operators
        , cast('<Secretary><c>' + replace(Secretary,',','</c><c>') + '</c></Secretary>' as xml) AS Secretary
     from @source
)
Select Department
     , TypeOfContact
     , Contact
     , ROW_NUMBER() OVER (PARTITION BY Department, TypeOfContact ORDER BY Department, TypeOfContact) AS ContactOrder
FROM (
   Select Department, 'SalesManagers' AS TypeOfContact, SaleMngrs.c.value('.','varchar(20)') as Contact
   from cte CROSS APPLY SalesMngrs.nodes('/SaleMngrs/c') as SaleMngrs(c)
   union
   Select Department, 'Operators', Operators.c.value('.','varchar(20)')
   from cte CROSS APPLY Operators.nodes('/Operators/c') as Operators(c)
   union
   Select Department, 'Secretary', Secretary.c.value('.','varchar(20)')
   from cte CROSS APPLY Secretary.nodes('/Secretary/c') as Secretary(c)
) AS q;

馬丁,

我知道您希望在一個SQL語句中實現此功能,但是如果您創建一個Function,那么SQL不會那么簡單。

ALTER FUNCTION dbo.Split (  @InputString  VARCHAR(8000),  @Delimiter VARCHAR(50))  
RETURNS @Items TABLE ( Item VARCHAR(8000), Rowid INT)  
AS  
BEGIN  
      IF @Delimiter = ' '  
      BEGIN  
            SET @Delimiter = ','  
            SET @InputString = REPLACE(@InputString, ' ', @Delimiter)  
      END  

      IF (@Delimiter IS NULL OR @Delimiter = '')  
            SET @Delimiter = ','  

      DECLARE @Item                 VARCHAR(8000)  
      DECLARE @ItemList       VARCHAR(8000)  
      DECLARE @DelimIndex     INT  
      declare @rowseq         INT

      SET @rowseq = 0

      SET @ItemList = @InputString  
      SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)  
      WHILE (@DelimIndex != 0)  
      BEGIN  
            SET @Item = SUBSTRING(@ItemList, 0, @DelimIndex)
            SET @rowseq = @rowseq + 1  
            INSERT INTO @Items VALUES (@Item, @rowseq)  

            -- Set @ItemList = @ItemList minus one less item  
            SET @ItemList = SUBSTRING(@ItemList, @DelimIndex+1, LEN(@ItemList)-@DelimIndex)  
            SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)  
      END -- End WHILE  

      IF @Item IS NOT NULL -- At least one delimiter was encountered in @InputString  
      BEGIN  
            SET @Item = @ItemList  
            SET @rowseq = @rowseq + 1
            INSERT INTO @Items VALUES (@Item, @rowseq)  
      END  

      -- No delimiters were encountered in @InputString, so just return @InputString  
      ELSE INSERT INTO @Items VALUES (@InputString, 1)  

      RETURN  

END

我從這個SO問題中發現了上述功能,但是我針對您的情況對其進行了一些更改。 如何將逗號分隔的值拆分為行

然后您的SQL將...

SELECT department, 'SalesManager' as TypeOfContract, s.Item as Contact , s.rowId 
FROM <YOUR TABLE> t 
     CROSS APPLY 
       (SELECT * FROM dbo.Split(t.SalesMngrs, ',') where item is not null) S
UNION ALL 
SELECT department, 'Operators' as TypeOfContract, s.Item as Contact , s.rowId  
FROM <YOUR TABLE> t

     CROSS APPLY 
       (SELECT * FROM dbo.Split(t.Operators, ',') where item is not null ) S   
UNION ALL
SELECT department, 'Secretary' as TypeOfContract, s.Item as Contact , s.rowId  
FROM <YOUR TABLE> t 
     CROSS APPLY 
       (SELECT * FROM dbo.Split(t.Secretary, ',') where item is not null) S      

我希望這有幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM