0

LabUsers我有一个数据库,其中包括两个表 Labs 和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;
4

3 回答 3

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(N'./text()[1]', N'nvarchar(max)'), 1, 1, N'')
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(N'./text()[1]', N'nvarchar(max)'), 1, 1, N'')
    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 提出的串联方法。

于 2012-05-21T23:40:03.677 回答
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 在第一个字符处放置一个“无”字符,例如清除不需要的第一个逗号。

于 2012-05-21T23:43:49.313 回答
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
于 2012-05-21T23:45:41.043 回答