use*_*340 5 sql-server t-sql group-concatenation
我有一张有 260 万条记录的表。它看起来像这样:
email prject_name
rafael.nadal@xyz.com lab1
rafael.nadal@xyz.com lab2
rafael.nadal@xyz.com lab3
TEST@TEST.COM shift1
TEST@TEST.COM shift2
Run Code Online (Sandbox Code Playgroud)
但我希望我的桌子看起来像这样:
email project_name
rafael.nadal@xyz.com lab1, lab2, lab3
TEST@TEST.COM shift1, shift2, shift3
Run Code Online (Sandbox Code Playgroud)
我用过这个查询
select distinct email ,
STUFF((Select ','+project_name
from dbo.[UMG sent 2016] as T1
where T1.email=T2.email
FOR XML PATH('')),1,1,'') from dbo.[UMG sent 2016] as T2;
Run Code Online (Sandbox Code Playgroud)
它已经运行了5个小时。
如何加快流程?
当你不关心的串接项目这将是顺序很容易磕了一个自定义的CLR聚合做到这一点,它很可能会出执行XML的方法,有一个在示例这篇文章。
不过,您可以对现有代码进行快速简便的更改。
代替
SELECT DISTINCT email,
STUFF((SELECT ',' + project_name
FROM dbo.[UMG sent 2016] AS T1
WHERE T1.email = T2.email
FOR XML PATH('')), 1, 1, '')
FROM dbo.[UMG sent 2016] AS T2;
Run Code Online (Sandbox Code Playgroud)
你可以用
SELECT email,
STUFF((SELECT ',' + project_name
FROM dbo.[UMG sent 2016] AS T1
WHERE T1.email = T2.email
FOR XML PATH('')), 1, 1, '')
FROM dbo.[UMG sent 2016] AS T2
GROUP BY email;
Run Code Online (Sandbox Code Playgroud)
不同之处在于,第一个计算 中所有行的连接字符串[UMG sent 2016]
,然后删除 中的重复项email,string
。第二个首先找到不同的email
,然后只对这些不同的值执行字符串连接工作。因此,在您的示例数据中,而不是执行 5 次工作(测试两次,纳达尔执行 3 次),然后扔掉其中的三个,它只会执行 2 次工作,每次执行一次。
这种STUFF FOR XML PATH
字符串连接技术确实很可爱,但它不能很好地扩展,而且在数百万行中它可能不是一个很好的主意。对于较大的表,您可能需要编写一些带有循环的老式程序 SQL,如下所示:
-- Create the working table ...
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL DROP TABLE #tmp
SELECT ROW_NUMBER() OVER( PARTITION BY email ORDER BY prject_name ) rowId, email, CAST( prject_name AS VARCHAR(500 ) ) prject_name
INTO #tmp
FROM dbo.[UMG sent 2016]
GO
-- Index temp table
CREATE UNIQUE CLUSTERED INDEX _cdx ON #tmp ( rowId, email )
GO
SELECT TOP 100 'before' s, *
FROM #tmp
ORDER BY email
-- Loop through appending the projects
DECLARE @n INT = 1
WHILE @@ROWCOUNT != 0
BEGIN
IF @n > 99 BEGIN RAISERROR( 'Too many loops!', 16, 1 ) BREAK END -- Loop safety
SET @n += 1
UPDATE t
SET t.prject_name = CONCAT( t.prject_name, ', ', s.prject_name )
FROM #tmp t
INNER JOIN #tmp s ON t.email = s.email
WHERE t.rowId = 1
AND s.rowId = @n
END
GO
SELECT TOP 100 'after' s, *
FROM #tmp
WHERE rowId = 1
ORDER BY email
Run Code Online (Sandbox Code Playgroud)
连接的结果都以“bucket 1”结尾。在我的简单重现中,有 260 万条记录,每个记录有 1 到 26 个项目,这个脚本在几分钟内运行。完整的复制脚本在这里。
请记住,此模式针对要连接的项目较少的大型表进行了优化。它还依赖于电子邮件/项目组合的唯一性,因此是我复制中的主键。将有一个临界点,该STUFF
技术更快。还有其他技术,例如 CLR、甚至游标,它们可能适合您的数据分布。
最后,您能否告诉我更多有关您的数据的信息,以便我可以调整我的重现?例如,平均每封电子邮件有多少个项目,分布是什么样的?
归档时间: |
|
查看次数: |
32092 次 |
最近记录: |