2014-08-28 7 views
0

Я хотел бы получить некоторые данные в представлении mssql, разделив их источники. У меня есть несколько столбцов, где номера телефонов хранятся как значения, разделенные запятой (каждый из них содержит контакт с телефоном). Я стараюсь работать с каждым «телефонным контактом», поэтому я хотел бы видеть их в строках каждый. А также каждая строка должна содержать порядок контакта от расщепления.Разделить запятую значение из столбца таблицы в строки, используя mssql?

Источник:

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

Как вы можете видеть, разделенные запятыми значения полный беспорядок, но сплитер является , (запятая).

Wanted результат:

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 пожалуйста.

+1

Вы не сможете это сделать в одном выражении select. –

+0

ТипOfContact есть. Второй столбец - SalesManagers, за которым следуют операторы и секретари. –

+0

@Sean Lange Я не понимаю, что вы подразумеваете под своим вторым комментарием ... – procma

ответ

1

Пожалуйста, попробуйте следующее (это так красиво, как структуры данных) - оптимизирован для работы с 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); 

ВЫВОД

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 

EDIT: Оптимизированный запрос с использованием UN PIVOT (оригинал ниже):

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; 
+0

Я думаю, что можно использовать UNPIVOT для оптимизации этого запроса. – wdosanjos

0

Martin,

Я знаю, что вы хотите это в одном SQL Statement, но если создать функцию, то 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)[email protected]) 
      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, но внес некоторые изменения в ваш сценарий. How to split a comma-separated value to rows

Затем 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  

Я надеюсь, что это помогает.

+0

Thanx @ Ed Mendez, вы пробовали работу? Это лучше или хуже, чем один-select, написанный выше by @wdosanjos? – procma