我有一个包含500k行的表,其中地址在一个字段中,由Char(13)+ Char(10)分隔。我已经在表格中添加了5个字段,希望将其分开。在大型表中将地址列拆分为多个
发现在线this split function,似乎表现良好,因为我不能使用parsename
由于有5个部分,.
也可能在现场。
这是一个表值函数,所以我将不得不循环行和更新记录,以前我会使用游标或sql while或可能甚至c#做到这一点,但我觉得他们必须是一个cte或设置为基础的答案。
我有一个包含500k行的表,其中地址在一个字段中,由Char(13)+ Char(10)分隔。我已经在表格中添加了5个字段,希望将其分开。在大型表中将地址列拆分为多个
发现在线this split function,似乎表现良好,因为我不能使用parsename
由于有5个部分,.
也可能在现场。
这是一个表值函数,所以我将不得不循环行和更新记录,以前我会使用游标或sql while或可能甚至c#做到这一点,但我觉得他们必须是一个cte或设置为基础的答案。
所以给出了一些源数据:
CREATE TABLE dbo.Addresses
(
AddressID INT IDENTITY(1,1),
[Address] VARCHAR(255),
Address1 VARCHAR(255),
Address2 VARCHAR(255),
Address3 VARCHAR(255),
Address4 VARCHAR(255),
Address5 VARCHAR(255)
);
INSERT dbo.Addresses([Address])
SELECT 'foo
bar'
UNION ALL SELECT 'add1
add2
add3
add4
add5';
我们来创建一个返回地址部分的函数:
CREATE FUNCTION dbo.SplitAddressOrdered
(
@AddressID INT,
@List VARCHAR(MAX),
@Delimiter VARCHAR(32)
)
RETURNS TABLE
AS
RETURN
(
SELECT
AddressID = @AddressID,
rn = ROW_NUMBER() OVER (ORDER BY Number),
AddressItem = Item
FROM (SELECT Number, Item = LTRIM(RTRIM(SUBSTRING(@List, Number,
CHARINDEX(@Delimiter, @List + @Delimiter, Number) - Number)))
FROM (SELECT ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.all_objects) AS n(Number)
WHERE Number <= CONVERT(INT, LEN(@List))
AND SUBSTRING(@Delimiter + @List, Number, LEN(@Delimiter)) = @Delimiter
) AS y
);
GO
现在你可以做到这一点(你将不得不运行查询5次):
DECLARE
@i INT = 1,
@sql NVARCHAR(MAX),
@src NVARCHAR(MAX) = N';WITH x AS
(
SELECT a.*, Original = s.AddressID, s.rn, s.AddressItem
FROM dbo.Addresses AS a
CROSS APPLY dbo.SplitAddressOrdered(a.AddressID, a.Address,
CHAR(13) + CHAR(10)) AS s WHERE rn = @i
)';
WHILE @i <= 5
BEGIN
SET @sql = @src + N'UPDATE x SET Address' + RTRIM(@i)
+ ' = CASE WHEN AddressID = Original AND rn = '
+ RTRIM(@i) + ' THEN AddressItem END;';
EXEC sp_executesql @sql, N'@i INT', @i;
SET @i += 1;
END
然后你就可以删除Address
柱:
ALTER TABLE dbo.Addresses DROP COLUMN [Address];
那么该表有:
AddressID Address1 Address2 Address3 Address4 Address5
--------- -------- -------- -------- -------- --------
1 foo bar NULL NULL NULL
2 add1 add2 add3 add4 add5
我敢肯定有人比我更聪明,将展示如何利用该功能,而不必循环。
我也可以预见到的功能略有变化,将让你简单地拔出某一个元素......保持请...
编辑
这里是一个标量函数,对自己更昂贵,但可以让你做表的一个传球,而不是5:
CREATE FUNCTION dbo.ElementFromOrderedList
(
@List VARCHAR(MAX),
@Delimiter VARCHAR(32),
@Index SMALLINT
)
RETURNS VARCHAR(255)
AS
BEGIN
RETURN
(
SELECT Item
FROM (SELECT rn = ROW_NUMBER() OVER (ORDER BY Number),
Item = LTRIM(RTRIM(SUBSTRING(@List, Number,
CHARINDEX(@Delimiter, @List + @Delimiter, Number) - Number)))
FROM (SELECT ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.all_objects) AS n(Number)
WHERE Number <= CONVERT(INT, LEN(@List))
AND SUBSTRING(@Delimiter + @List, Number, LEN(@Delimiter)) = @Delimiter
) AS y WHERE rn = @Index
);
END
GO
现在更新,给予上述(之前的更新和下降之前)上表,很简单:
UPDATE dbo.Addresses
SET Address1 = dbo.ElementFromOrderedList([Address], CHAR(13) + CHAR(10), 1),
Address2 = dbo.ElementFromOrderedList([Address], CHAR(13) + CHAR(10), 2),
Address3 = dbo.ElementFromOrderedList([Address], CHAR(13) + CHAR(10), 3),
Address4 = dbo.ElementFromOrderedList([Address], CHAR(13) + CHAR(10), 4),
Address5 = dbo.ElementFromOrderedList([Address], CHAR(13) + CHAR(10), 5);
我现在试试这个,谢谢。感谢您的时间并为此提供帮助。 – 2013-03-13 15:48:36
你有两个选择:
您可以创建一个临时表,然后解析地址到临时表,然后通过其连接到临时表更新原表。
或
您可以编写自己的T-SQL的功能和使用这些功能,在您的更新语句的功能类似如下:
UPDATE myTable
SET address1 = myGetAddress1Function(address),
address2 = myGetAddress2Function(address)....
我认为挑战是一个答案,(a)函数定义缺失,(b)创建5个不同的函数对我来说并不合适。 – 2013-03-13 15:40:02
还有很多其他选项。这些函数都没有使用'PARSENAME':http://www.sqlperformance.com/2012/07/t-sql-queries/split-strings – 2013-03-13 15:01:50
谢谢Aaron,我之前没有遇到过你的帖子,你会同意吗?詹姆斯的更新? – 2013-03-13 15:11:42
我正在研究只需要一个功能的完整答案。 – 2013-03-13 15:14:12