3

我读到这个:http: //blog.sqlauthority.com/2012/09/14/sql-server-grouping-by-multiple-columns-to-single-column-as-a-string/

我可以将此应用于我的一个查询:

SELECT t.TicketID, STUFF(
(SELECT ',' + tt.Tag
FROM TicketTag tt
WHERE tt.TicketID = t.TicketID
FOR XML PATH('')),1,1,'') AS CSV
FROM Ticket AS t
GROUP BY t.TicketID
GO

这会导致如下所示:

TicketID  CSV
1         tsql, sqlserver, c++
2         hi, bye, no

现在这行得通,因为我能够直接加入一个表......现在我想STUFF()再次申请以显示分配给它的 TicketID。

显示被分配工单的人的查询如下:

SELECT  l.Login
FROM Ticket t1
LEFT JOIN
    TicketAssignments tass
ON
    tass.TicketID=t1.TicketID
LEFT JOIN
    Login l 
ON
    l.LoginID = tass.LoginID

但是,我缺少两个关键的东西:

1)我需要像在第一个示例中一样显示 TicketID(按 ticketID 分组) 2)我需要 STUFF() 登录名,以便它以逗号分隔

请坚持使用 STUFF() 我知道有时它可能不是最好的方法,但我只是想在我的代码中使用它。

编辑

3张桌子

Ticket 
------
TicketID

TicketAssignments
-----------------
TicketID
LoginID

Login
------
LoginID

Sample data:

Ticket
------
1
2
3


TicketAssignments
------------------
1   25
1   26
2   25
3   26
3   27

Login
-----
25 Joe
26 Jon
27 Jason

我想要的结果:

TicketID  Assignment
--------------------
    1, "Joe, Jon"
    2, "Joe"
    3, "Jon", "Jason"

也就是说,Joe 和 Jon 被分配了工单 1,Joe 被分配了工单 2 Jon 和 Jason 被分配到工单 3

所以 STUFF() 只是将它们放在每个ticketid 的一行中。我知道这效率不高,我现在不要求优化......

如前所述,我必须获得票证分配的查询是:

SELECT l.Login FROM Ticket t1 LEFT JOIN TicketAssignments tass ON tass.TicketID=t1.TicketID LEFT JOIN Login l ON l.LoginID = tass.LoginID

但是,我缺少 2 个关键的东西:1)我需要显示 TicketID,就像我在第一个示例中一样(按 t​​icketID 分组)2)我需要 STUFF() 登录名,以便它以逗号分隔

4

3 回答 3

6

正如 Nathan 解释的那样,STUFF()实际上并没有执行任何连接,它只是删除了前导逗号(这更好,恕我直言,然后必须通过计算输出字符串的长度并连接来删除尾随逗号):

SELECT t.TicketID, Assignment = STUFF(
(
  SELECT N', "' + l.Name + '"'
    FROM dbo.Logins AS l
    INNER JOIN dbo.TicketAssignments AS ta
      ON l.LoginID = ta.LoginID
    WHERE ta.TicketID = t.TicketID
    FOR XML PATH(''), 
    TYPE).value(N'./text()[1]', N'nvarchar(max)'), 1, 2, N'')
FROM dbo.Tickets AS t
ORDER BY t.TicketID;

输出:

票号 任务
1 “乔”、“乔恩”
2 “乔”
3 “乔恩”、“杰森”

请注意,在 SQL Server 2017 及更高版本上,您可以使用STRING_AGG(),这会变得更容易一些:

SELECT t.TicketID, 
  Assignment = STRING_AGG(CONCAT('"', l.Name, '"'), ', ')
FROM dbo.Tickets AS t
INNER JOIN dbo.TicketAssignments AS ta
  ON t.TicketID = ta.TicketID
INNER JOIN dbo.Logins AS l
  ON ta.LoginID = l.LoginID
GROUP BY t.TicketID;
于 2013-01-18T19:50:36.690 回答
2

STUFF只是删除了由于您连接标签的方式(或您请求的 login.name)而产生的前导逗号。该FOR XML子句实际上是在做连接的工作。

看这个例子:

declare @Ticket table (TicketId int);
insert into @Ticket
    select 1 union all select 2 union all select 3;

declare @TicketAssignments table (TicketId int, LoginId int)
insert into @TicketAssignments
    select 1,25 union all
    select 1,26 union all
    select 2,25 union all
    select 3,26 union all
    select 3,27;

declare @Login table (LoginId int, Name varchar(10));
insert into @Login
    select 25, 'Joe' union all
    select 26, 'Jon' union all
    select 27, 'Jason';


select  ticketId,
        p.n,
        stuff(p.n, 1, 1, '')
from    @Ticket t
cross
apply   (   select  ',' + l.Name
            from    @TicketAssignments ta
            join    @Login l on ta.LoginId = l.LoginId
            where   ta.TicketId = t.TicketId
            for xml path('')
        )p(n)
于 2013-01-18T19:51:39.857 回答
0

以下示例显示了如何在两列上应用填充函数。我有 3 个按层次顺序排列的表。Job->storejob-> StorejobAssignment。层次结构中的表与外键相关联。表 Job 的主键 JobNo_pk 将作为外键出现在存储作业表中,即 Jobno_fk。但是 JObno_fk 在 StoreJobAssignment 表中不可用,因为它是分层顺序的。

Select Top 10 j.JobNo_pk,
Stuff((select ','+ convert(varchar,StoreJobNo_pk) from Storejob
  where j.JobNo_PK=StoreJob.JobNo_FK  for XML path ('') ),1,1,'') as StorejobNO_pk,

 Stuff((select ','+ convert(varchar,StoreJobAssignmentNo_pk) from StorejobAssignment inner join StoreJob on StoreJob.StoreJobNo_PK=StoreJobAssignment.StoreJobNo_FK
  where StoreJob.Storejobno_pk=StoreJobAssignment.StorejobNo_fk for XML path ('') ),1,1,'') as Storejobassignmnet_pk   

  from job j
  inner join storejob    on j.jobno_pk=StoreJob.jobno_fk 
   inner join StorejobAssignment   on StoreJob.StoreJobno_pk=StoreJobAssignment.Storejobno_fk 
   group by Jobno_pk 

单击此处查看上述查询的输出

于 2017-09-01T05:25:58.560 回答