我正在研究MSSQL,尝试将一个字符串列拆分为多个列。字符串列的数字用分号分隔,如:
190230943204;190234443204;
但是,有些行的数字比其他行多,所以在数据库中可以有
190230943204;190234443204;
121340944534;340212343204;134530943204
我见过一些解决方案,可以将一列拆分为特定数量的列,但不是可变列。具有较少数据的列(由逗号分隔的2个字符串系列而不是3个)将在第三位具有空值。
想法?如果我必须澄清任何事情,请告诉我。
答案 0 :(得分:3)
将这些数据拆分成单独的列是一个非常好的开始(昏迷分离的值是异端)。但是,“可变数量的属性”通常应建模为one-to-many relationship。
CREATE TABLE main_entity (
id INT PRIMARY KEY,
other_fields INT
);
CREATE TABLE entity_properties (
main_entity_id INT PRIMARY KEY,
property_value INT,
FOREIGN KEY (main_entity_id) REFERENCES main_entity(id)
);
entity_properties.main_entity_id
是foreign key到main_entity.id
。
恭喜,您走在正确的道路上,这称为normalisation。您即将到达First Normal Form.
但是,Beweare,这些属性应具有明显相似的性质(即所有电话号码或地址等)。不要陷入黑暗面(a.k.a。Entity-Attribute-Value anti-pattern),并试图把所有属性都扔到同一个表中。如果您可以识别多种类型的属性,请将每种类型存储在单独的表中。答案 1 :(得分:1)
如果这些都是固定长度的字符串(如问题所示),那么你可以相当简单地完成工作(至少相对于其他解决方案):
select substring(col, 1+13*(n-1), 12) as val
from t join
(select 1 as n union all select union all select 3
) n
on len(t.col) <= 13*n.n
如果所有条目的大小相同(如果它们的大小不同,则不是那么容易),这是一个有用的黑客攻击。但是,请考虑数据结构,因为分号(或逗号)分隔列表不是一个非常好的数据结构。
答案 2 :(得分:1)
如果我是你,我会创建一个简单的函数来划分用&#39;;&#39;分隔的值。像这样:
IF EXISTS (SELECT * FROM sysobjects WHERE id = object_id(N'fn_Split_List') AND xtype IN (N'FN', N'IF', N'TF'))
BEGIN
DROP FUNCTION [dbo].[fn_Split_List]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[fn_Split_List](@List NVARCHAR(512))
RETURNS @ResultRowset TABLE ( [Value] NVARCHAR(128) PRIMARY KEY)
AS
BEGIN
DECLARE @XML xml = N'<r><![CDATA[' + REPLACE(@List, ';', ']]></r><r><![CDATA[') + ']]></r>'
INSERT INTO @ResultRowset ([Value])
SELECT DISTINCT RTRIM(LTRIM(Tbl.Col.value('.', 'NVARCHAR(128)')))
FROM @xml.nodes('//r') Tbl(Col)
RETURN
END
GO
简单地用这种方式调用:
SET NOCOUNT ON
GO
DECLARE @RawData TABLE( [Value] NVARCHAR(256))
INSERT INTO @RawData ([Value] )
VALUES ('1111111;22222222')
,('3333333;113113131')
,('776767676')
,('89332131;313131312;54545353')
SELECT SL.[Value]
FROM @RawData AS RD
CROSS APPLY [fn_Split_List] ([Value]) as SL
SET NOCOUNT OFF
GO
结果如下:
Value
1111111
22222222
113113131
3333333
776767676
313131312
54545353
89332131
无论如何,函数中的逻辑并不复杂,因此您可以轻松地将其放在任何需要的位置。
注意:使用&#39;;&#39;分隔的值的数量没有限制,但如果需要,可以设置为NVARCHAR(MAX)的函数有长度限制。< / p>
编辑:
正如我所看到的,您的示例中有一些行会导致函数返回空字符串。例如:
number;number;
将返回:
number
number
'' (empty string)
要清除它们,只需将以下where子句添加到上面的语句中,如下所示:
SELECT SL.[Value]
FROM @RawData AS RD
CROSS APPLY [fn_Split_List] ([Value]) as SL
WHERE LEN(SL.[Value]) > 0