一般的时候数据库设计中,有一对多或多对多的关系往往会设计一个表来存储这种关系的对应,但有时数据库结构我们是不能修改的,只能允许我们读取,现在假如有一下的数据表,需要我们来拆分字段char_array了。
![](https://images.cnblogs.com/cnblogs_com/weiweictgu/1.gif)
有一段有趣的SQL 代码可以很好的解决这个问题:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
创建辅助数据表
1
IF OBJECT_ID('dbo.Nums') IS NOT NULL
2
DROP TABLE dbo.Nums;
3
GO
4
CREATE TABLE dbo.Nums(n INT NOT NULL PRIMARY KEY);
5
DECLARE @max AS INT, @rc AS INT;
6
SET @max = 1000000;
7
SET @rc = 1;
8![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
9
INSERT INTO Nums VALUES(1);
10
WHILE @rc * 2 <= @max
11
BEGIN
12
INSERT INTO dbo.Nums SELECT n + @rc FROM dbo.Nums;
13
SET @rc = @rc * 2;
14
END
15![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
16
INSERT INTO dbo.Nums
17
SELECT n + @rc FROM dbo.Nums WHERE n + @rc <= @max;
18
GO
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
创建需要拆分的数据表
1
IF OBJECT_ID('dbo.Arrays') IS NOT NULL
2
DROP TABLE dbo.Arrays;
3
GO
4
-- http://weiweictgu.cnblogs.com
5
--come from sql server 2005 t-sql querying
6
CREATE TABLE dbo.Arrays
7
(
8
arrid VARCHAR(10) NOT NULL PRIMARY KEY,
9
array VARCHAR(8000) NOT NULL
10
)
11![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
12
INSERT INTO Arrays(arrid, array) VALUES('A', '20,22,25,25,14');
13
INSERT INTO Arrays(arrid, array) VALUES('B', '30,33,28');
14
INSERT INTO Arrays(arrid, array) VALUES('C', '12,10,8,12,12,13,12,14,10,9');
15
INSERT INTO Arrays(arrid, array) VALUES('D', '-4,-6,-4,-2');
16
GO
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
读取拆分符号','位置几个步骤
1
-- Solution to Separating Elements Problem, Step 1
2
SELECT arrid, array, n
3
FROM dbo.Arrays
4
JOIN dbo.Nums
5
ON n <= LEN(array)
6
AND SUBSTRING(array, n, 1) = ',';
7![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
8
-- Solution to Separating Elements Problem, Step 2
9
SELECT arrid, array, n
10
FROM dbo.Arrays
11
JOIN dbo.Nums
12
ON n <= LEN(array)
13
AND SUBSTRING(',' + array, n, 1) = ',';
14![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
15
-- Solution to Separating Elements Problem, Step 3
16
SELECT arrid,
17
SUBSTRING(array, n, CHARINDEX(',', array + ',', n) - n) AS element
18
FROM dbo.Arrays
19
JOIN dbo.Nums
20
ON n <= LEN(array)
21
AND SUBSTRING(',' + array, n, 1) = ',';
22![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
23
-- Solution to Separating Elements Problem, Step 4
24
SELECT arrid,
25
n - LEN(REPLACE(LEFT(array, n), ',', '')) + 1 AS pos,
26
CAST(SUBSTRING(array, n, CHARINDEX(',', array + ',', n) - n)
27
AS INT) AS element
28
FROM dbo.Arrays
29
JOIN dbo.Nums
30
ON n <= LEN(array)
31
AND SUBSTRING(',' + array, n, 1) = ',';
在SQL Server2005中没有必要再建立数字辅助表,可以使用递归CTE来拆分字段,但这种方法受限于
SQL Server2005的递归语法,在其他数据库中需要考虑其他的方式来实现。
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
SQL Server 2005递归实现方式
1
-- Solution based on Recursive CTEs
2
WITH SplitCTE AS
3
(
4
SELECT arrid, 1 AS pos, 1 AS startpos,
5
CHARINDEX(',', array + ',') - 1 AS endpos
6
FROM dbo.Arrays
7
WHERE LEN(array) > 0
8![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
9
UNION ALL
10![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
11
SELECT Prv.arrid, Prv.pos + 1, Prv.endpos + 2,
12
CHARINDEX(',', Cur.array + ',', Prv.endpos + 2) - 1
13
FROM SplitCTE AS Prv
14
JOIN dbo.Arrays AS Cur
15
ON Cur.arrid = Prv.arrid
16
AND CHARINDEX(',', Cur.array + ',', Prv.endpos + 2) > 0
17
)
18
SELECT A.arrid, pos,
19
CAST(SUBSTRING(array, startpos, endpos-startpos+1) AS INT) AS element
20
FROM dbo.Arrays AS A
21
JOIN SplitCTE AS S
22
ON S.arrid = A.arrid
23
ORDER BY arrid, pos;
通过上面的演示代码你应该已经明白怎么将一个字段的字符如何拆分开来了。
注:此代码摘选自《SQL Server 2005 技术内幕T—SQL查询》一书的源码,此文是该书里面的一个小的应用实例。