我有一个数据库,其中包括两个表,Labs和LabUsers
如何将LabUsers
中的列加入Labs
中的单元格。
具体来说,我希望将实验室的用户名连接起来并用子弹(• is Alt+0149
)分隔,并让这些用户名按字母顺序从左到右排序。
这是一个例子。
Labs
表如下所示:
LabID LabName LabStudents
----- ---------- -----------
1 North NULL
2 North East NULL
3 South West NULL
并且LabUsers
看起来像这样:
LabUserID LabUserName LabID
--------- ----------- -----
1 Diana 1
2 Paul 2
3 Paula 2
4 Romeo 1
5 Julia 1
6 Rose 2
7 Diana 2
我想在Labs
表格中得到这个结果:
LabID LabName LabUsers
----- ---------- ---------------------
1 North Diana•Julia•Romeo
2 North East Diana•Paul•Paula•Rose
3 South West NULL
以下是创建表格的脚本:
USE [tempdb];
GO
CREATE TABLE [dbo].[LabUsers]
(
[LabUserID] [int] PRIMARY KEY CLUSTERED,
[LabUserName] [nvarchar](50) NOT NULL,
[LabID] [int] NOT NULL
);
GO
INSERT [dbo].[LabUsers] SELECT 1, N'Diana', 1;
INSERT [dbo].[LabUsers] SELECT 2, N'Paul', 2;
INSERT [dbo].[LabUsers] SELECT 3, N'Paula', 2;
INSERT [dbo].[LabUsers] SELECT 4, N'Romeo', 1;
INSERT [dbo].[LabUsers] SELECT 5, N'Julia', 1;
INSERT [dbo].[LabUsers] SELECT 6, N'Rose', 2;
INSERT [dbo].[LabUsers] SELECT 7, N'Diana', 2;
CREATE TABLE [dbo].[Labs]
(
[LabID] [int] PRIMARY KEY CLUSTERED,
[LabName] [nvarchar](50) NOT NULL,
[LabUsers] [nvarchar](max) NULL
);
GO
INSERT [dbo].[Labs] SELECT 1, N'North', NULL;
INSERT [dbo].[Labs] SELECT 2, N'North East', NULL;
INSERT [dbo].[Labs] SELECT 3, N'South West', NULL;
答案 0 :(得分:2)
SELECT l.LabID, l.LabName, LabUsers = STUFF((SELECT N'•' + lu.LabUserName
FROM dbo.LabUsers AS lu
WHERE lu.LabID = l.LabID
ORDER BY lu.LabUserName
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, '')
FROM dbo.Labs AS l;
我认为没有理由将它存储在表中,因为在运行查询时,总是可以在运行时生成代码。如果将它存储在表中,则每次更改表中的任何行时都必须更新它。
但是,如果我不能说服你不要这样做(存储像这样的冗余数据真的很糟糕),你可以尝试这种方式:
;WITH x AS
(
SELECT l.LabID, l.LabName, x = STUFF((SELECT N'•' + lu.LabUserName
FROM dbo.LabUsers AS lu
WHERE lu.LabID = l.LabID
ORDER BY lu.LabUserName
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, '')
FROM dbo.Labs AS l
)
UPDATE l
SET LabUsers = x.x
FROM dbo.Labs AS l
INNER JOIN x ON l.LabID = x.LabID;
至于性能测试,我将上述版本与此变体进行比较:
SELECT l.LabID, l.LabName, LabUsers = STUFF((SELECT N'•' + lu.LabUserName
FROM dbo.LabUsers AS lu
WHERE lu.LabID = l.LabID
ORDER BY lu.LabUserName
FOR XML PATH('')), 1, 1, '')
FROM dbo.Labs AS l;
在我的系统上,我看到这个答案顶部的初始版本要贵得多。还要注意,将这些方法填充到用户定义的函数中会使它更接近@RThomas提出的串联方法。
答案 1 :(得分:2)
试一试
SELECT LabName ,
STUFF(( SELECT ',' + LabUsers.LabUserName
FROM dbo.LabUsers
WHERE LabUsers.LabID = Labs.LabID
ORDER BY LabName
FOR
XML PATH('')
), 1, 1, '') AS Labusers
FROM dbo.Labs
ORDER BY LabName
FOR XML PATH('')将您的字符串连接成一个XML结果,STUFF在第一个字符处放置一个“无”字符,例如擦掉不需要的第一个逗号。
答案 2 :(得分:0)
另一种方法是设置一个UDF,将所有实验室用户作为单个字符串返回,如下所示:
CREATE FUNCTION LabUserString
(
@pLabId Int
)
RETURNS NVarChar(Max)
AS
BEGIN
Declare @pResult NVarChar(Max)
SELECT @pResult = COALESCE(@pResult + N'•', '') + [LabUserName]
FROM LabUsers WHERE LabId = @pLabId
Return @pResult
END
然后是这样的查询:
Select LabID, LabName, dbo.LabUserString(LabID) AS LabUsers FROM Labs