我想通过拆分它们的源来获取一些数据进入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
。
答案 0 :(得分: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
编辑:使用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;
答案 1 :(得分:0)
马丁,
我知道你想在一个SQL语句中使用它,但如果你创建一个函数,那么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
上面的功能我从这个问题中找到了,但我为你的场景做了一些改动。 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
我希望这会有所帮助。