我有订阅表,订阅号实际上是一个存储在一列中的值。我们有以下样本值
SC 5-1395-174-25P
SC 1-2134-123-ABC C1-2
SC 12-5245-1247-14&P
SC ABCD-2525-120
因此我们需要将其拆分为单独的列。所以上面四个应该按照以下方式分割
**Col1** **Col2** **Col3** **Col4** **Col5** **Col6** **Col7**
**SC** **5** **1395** **174** **25P**
**SC** **1** **2134** **123** **ABC** **C1** **2**
**SC** **12** **5245** **1247** **14&P**
**SC** **ABCD** **2525** **120**
答案 0 :(得分:5)
这是一种在线方法
示例强>
Declare @YourTable table (SomeCol varchar(max))
Insert Into @YourTable values
('SC 5-1395-174-25P'),
('SC 1-2134-123-ABC C1-2'),
('SC 12-5245-1247-14&P'),
('SC ABCD-2525-120')
Select B.*
From @YourTable A
Cross Apply (
Select Pos1 = ltrim(rtrim(xDim.value('/x[1]','varchar(max)')))
,Pos2 = ltrim(rtrim(xDim.value('/x[2]','varchar(max)')))
,Pos3 = ltrim(rtrim(xDim.value('/x[3]','varchar(max)')))
,Pos4 = ltrim(rtrim(xDim.value('/x[4]','varchar(max)')))
,Pos5 = ltrim(rtrim(xDim.value('/x[5]','varchar(max)')))
,Pos6 = ltrim(rtrim(xDim.value('/x[6]','varchar(max)')))
,Pos7 = ltrim(rtrim(xDim.value('/x[7]','varchar(max)')))
From (Select Cast('<x>' + replace((Select replace(replace(A.SomeCol,' ','-'),'-','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml) as xDim) as A
) B
<强>返回强>
修改
1)创建表
CREATE TABLE MyNewPubTable (PUB_FORM_NUM NVARCHAR(50) , COL1 NVARCHAR(10) , COL2 NVARCHAR(10) , COL3 NVARCHAR(10) , COL4 NVARCHAR(10) , COL5 NVARCHAR(10) , COL6 NVARCHAR(10) , COL7 NVARCHAR(10))
2)执行查询
Declare @YourTable table (PUB_FORM_NUM varchar(max))
Insert Into @YourTable values
('SC 5-1395-174-25P'),
('SC 1-2134-123-ABC C1-2'),
('SC 12-5245-1247-14&P'),
('SC ABCD-2525-120')
Insert Into MyNewPubTable
Select A.PUB_FORM_NUM
,B.*
From @YourTable A
Cross Apply (
Select Pos1 = ltrim(rtrim(xDim.value('/x[1]','varchar(max)')))
,Pos2 = ltrim(rtrim(xDim.value('/x[2]','varchar(max)')))
,Pos3 = ltrim(rtrim(xDim.value('/x[3]','varchar(max)')))
,Pos4 = ltrim(rtrim(xDim.value('/x[4]','varchar(max)')))
,Pos5 = ltrim(rtrim(xDim.value('/x[5]','varchar(max)')))
,Pos6 = ltrim(rtrim(xDim.value('/x[6]','varchar(max)')))
,Pos7 = ltrim(rtrim(xDim.value('/x[7]','varchar(max)')))
From (Select Cast('<x>' + replace((Select replace(replace(A.PUB_FORM_NUM,' ','-'),'-','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml) as xDim) as A
) B
3)查看结果
Select * From MyNewPubTable
修改2
或者您可以动态创建表格
Declare @YourTable table (PUB_FORM_NUM varchar(max))
Insert Into @YourTable values
('SC 5-1395-174-25P'),
('SC 1-2134-123-ABC C1-2'),
('SC 12-5245-1247-14&P'),
('SC ABCD-2525-120')
Select A.PUB_FORM_NUM
,B.*
Into MyNewPubTable
From @YourTable A
Cross Apply (
Select Pos1 = ltrim(rtrim(xDim.value('/x[1]','varchar(max)')))
,Pos2 = ltrim(rtrim(xDim.value('/x[2]','varchar(max)')))
,Pos3 = ltrim(rtrim(xDim.value('/x[3]','varchar(max)')))
,Pos4 = ltrim(rtrim(xDim.value('/x[4]','varchar(max)')))
,Pos5 = ltrim(rtrim(xDim.value('/x[5]','varchar(max)')))
,Pos6 = ltrim(rtrim(xDim.value('/x[6]','varchar(max)')))
,Pos7 = ltrim(rtrim(xDim.value('/x[7]','varchar(max)')))
From (Select Cast('<x>' + replace((Select replace(replace(A.PUB_FORM_NUM,' ','-'),'-','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml) as xDim) as A
) B
Select * From MyNewPubTable
答案 1 :(得分:2)
在SQL Server 2016+中,您可以使用string_split()
。
在2016年之前的SQL Server中,使用Jeff Moden的CSV Splitter表值函数:
select
id, Col1 = [1], Col2 = [2], Col3 = [3], Col4 = [4], Col5 = [5], Col6 = [6], Col7 = [7]
from t
cross apply dbo.DelimitedSplit8k(replace(col,'-',' '),' ') s
pivot (max(Item) for ItemNumber in ([1], [2], [3], [4], [5], [6], [7])) p
order by id
rextester演示:http://rextester.com/PZYAF36892
返回:
+----+------+------+------+------+------+------+------+
| id | Col1 | Col2 | Col3 | Col4 | Col5 | Col6 | Col7 |
+----+------+------+------+------+------+------+------+
| 1 | SC | 5 | 1395 | 174 | 25P | NULL | NULL |
| 2 | SC | 1 | 2134 | 123 | ABC | C1 | 2 |
| 3 | SC | 12 | 5245 | 1247 | 14&P | NULL | NULL |
| 4 | SC | ABCD | 2525 | 120 | NULL | NULL | NULL |
+----+------+------+------+------+------+------+------+
拆分字符串参考:
答案 2 :(得分:1)
更新:包含最终查询
由于数据存在于表中,您可以使用索引视图来分割值。什么?!?!是的,我要告诉你的是比DelimitedSplit8K,string_split或任何CLR更快。以下是我们如何实现这一目标。
<强> 1。创建/填充您的表格和真实的Tally Table(又名“数字表格”)
(请注意,“cte tally / numbers表”不适用于此)。
USE tempdb
GO
-- 1. Create/Populate your table and a real Tally Table
IF OBJECT_ID('dbo.yourView') IS NOT NULL DROP VIEW dbo.yourView;
IF OBJECT_ID('dbo.tally') IS NOT NULL DROP TABLE dbo.tally;
CREATE TABLE dbo.tally
(
N int NOT NULL,
CONSTRAINT pk_tally PRIMARY KEY CLUSTERED(N) ,
CONSTRAINT uq_tally UNIQUE NONCLUSTERED(N)
);
GO
IF OBJECT_ID('dbo.yourTable') IS NOT NULL DROP TABLE dbo.yourTable;
CREATE TABLE dbo.yourTable
(
SomeId int identity NOT NULL,
SomeCol varchar(8000),
CONSTRAINT pk_yourTable PRIMARY KEY (SomeId)
);
GO
INSERT dbo.tally
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT 1))-1
FROM sys.all_columns a, sys.all_columns b;
INSERT dbo.YourTable VALUES
('SC 5-1395-174-25P'),
('SC 1-2134-123-ABC C1-2'),
('SC 12-5245-1247-14&P'),
('SC ABCD-2525-120');
GO
<强> 2。使用dbo.tally创建一个用于分割值的索引视图
CREATE VIEW dbo.yourView
WITH SCHEMABINDING AS
SELECT
SomeId,
SomeCol,
position = N+1,
Item =
SUBSTRING
(
REPLACE(REPLACE(somecol, '-', '|'), ' ', '|'),
N+1,
ISNULL(NULLIF(CHARINDEX('|',REPLACE(REPLACE(somecol,'-','|'),' ','|'),N+1),0)-(N+1),8000)
)
FROM dbo.YourTable
CROSS JOIN dbo.tally
WHERE N <= LEN(SomeCol) -- Use this predicate first to ensure we get a nonclustered index seek
AND (N=0 OR SUBSTRING(REPLACE(REPLACE(somecol,'-','|'),' ','|'),N,1) = '|');
GO
CREATE UNIQUE CLUSTERED INDEX uq_cl_yourView ON dbo.yourView(SomeId, position);
GO
让我们回顾一下到目前为止:
SELECT * FROM dbo.yourView;
SomeId SomeCol position item
----------- -------------------- ----------- -----
1 SC 5-1395-174-25P 1 SC
1 SC 5-1395-174-25P 4 5
1 SC 5-1395-174-25P 6 1395
1 SC 5-1395-174-25P 11 174
1 SC 5-1395-174-25P 15 25P
2 SC 1-2134-123-ABC C1 1 SC
2 SC 1-2134-123-ABC C1 4 1
2 SC 1-2134-123-ABC C1 6 2134
2 SC 1-2134-123-ABC C1 11 123
2 SC 1-2134-123-ABC C1 15 ABC
2 SC 1-2134-123-ABC C1 19 C1
2 SC 1-2134-123-ABC C1 22 2
3 SC 12-5245-1247-14&P 1 SC
3 SC 12-5245-1247-14&P 4 12
3 SC 12-5245-1247-14&P 7 5245
3 SC 12-5245-1247-14&P 12 1247
3 SC 12-5245-1247-14&P 17 14&P
4 SC ABCD-2525-120 1 SC
4 SC ABCD-2525-120 4 ABCD
4 SC ABCD-2525-120 9 2525
4 SC ABCD-2525-120 14 120
第3。使用Jeff Moden的“cross tab”方法进行“pivot”
WITH getItemNumber AS
(
SELECT
SomeId,
ItemNumber = ROW_NUMBER() OVER (PARTITION BY SomeId ORDER BY position),
Item
FROM dbo.yourView WITH (NOEXPAND)
)
SELECT
SomeId ,
pos1 = MAX(CASE ItemNumber WHEN 1 THEN item END),
pos2 = MAX(CASE ItemNumber WHEN 2 THEN item END),
pos3 = MAX(CASE ItemNumber WHEN 3 THEN item END),
pos4 = MAX(CASE ItemNumber WHEN 4 THEN item END),
pos5 = MAX(CASE ItemNumber WHEN 5 THEN item END),
pos6 = MAX(CASE ItemNumber WHEN 6 THEN item END),
pos7 = MAX(CASE ItemNumber WHEN 7 THEN item END)
FROM getItemNumber
GROUP BY SomeId;
**结果**
SomeId pos1 pos2 pos3 pos4 pos5 pos6 pos7
------- ------- ------ ------- ----- ------ ------ -----
1 SC 5 1395 174 25P NULL NULL
2 SC 1 2134 123 ABC C1 2
3 SC 12 5245 1247 14&P NULL NULL
4 SC ABCD 2525 120 NULL NULL NULL
<强> 4。审查执行计划时微笑
答案 3 :(得分:0)
试试吧
Declare @YourTable table (ID int,SomeCol varchar(500))
Insert Into @YourTable values
(1,'5-1395-174-25P'),
(2,'1-2134-123-ABC C1-2'),
(3,'SC 12-5245-1247-14&P'),
(4,'SC ABCD-2525-120*')
Select A.ID
,B.RetVal
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 replace(replace(A.SomeCol,' ','§§Split§§'),'-','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
) B
Where RetSeq=1
根据需要进行更改