如果行在其他列中具有相同的数据,则 SQL 查询 CONCAT/列出唯一列数据?

Posted

技术标签:

【中文标题】如果行在其他列中具有相同的数据,则 SQL 查询 CONCAT/列出唯一列数据?【英文标题】:SQL query to CONCAT/list unique column data if rows have identical data in the other columns? 【发布时间】:2021-12-23 16:35:23 【问题描述】:

提前致谢。我基本上是在尝试运行 SQL 查询,以便 StaffID:Name:Floor:Date:Shifts 的结果为 1:1:1:1:Many。

这是我的初始查询和示例结果:

SELECT
    ST.STAFFNUM [StaffID],
    ST.FULLNAME [Name],
    ST.AREA [Floor],
    CONVERT(VARCHAR(10), TS.EVENTDATE, 103) [Date],
    LEFT(CONVERT(VARCHAR(10), TS.SHIFTSTART, 8), 5) [ShiftStart],
    LEFT(CONVERT(VARCHAR(10), TS.SHIFTEND, 8), 5) [ShiftEnd]
FROM
    TIMES TS
    LEFT JOIN STAFF ST ON TS.STAFFNUM = ST.STAFFNUM
WHERE
        TS.EVENTDATE BETWEEN '2021/01/01' AND '2021/01/01'
ORDER BY
    ST.AREA,
    ST.FULLNAME,
    TS.EVENTDATE,
    TS.SHIFTSTART
;

StaffID | Name    | Floor | Date       | ShiftStart | ShiftEnd
==============================================================
1000    | Andrew  | 1     | 01/01/2021 | 06:00      | 14:00
1000    | Andrew  | 1     | 01/01/2021 | 14:00      | 15:00
8654    | Belinda | 2     | 01/01/2021 | 06:00      | 14:00
9876    | Craig   | 3     | 01/01/2021 | 06:00      | 14:00

然后,我将 ShiftStart 和 ShiftEnd 列与以下内容相结合,以获得以下结果:

CONCAT(LEFT(CONVERT(VARCHAR(10), TS.SHIFTSTART, 8), 5),'-',LEFT(CONVERT(VARCHAR(10), TS.SHIFTEND, 8), 5)) [Shift]

StaffID | Name    | Floor | Date       | Shift
====================================================
1000    | Andrew  | 1     | 01/01/2021 | 06:00-14:00
1000    | Andrew  | 1     | 01/01/2021 | 14:00-15:00
8654    | Belinda | 2     | 01/01/2021 | 06:00-14:00
9876    | Craig   | 3     | 01/01/2021 | 06:00-14:00

我想不出接下来要做的是将 Andrew 的班次(以及其他任何人在同一日期和楼层等的多个班次)结合起来,如下所示:

StaffID | Name    | Floor | Date       | Shifts
=================================================================
1000    | Andrew  | 1     | 01/01/2021 | 06:00-14:00, 14:00-15:00
8654    | Belinda | 2     | 01/01/2021 | 06:00-14:00
9876    | Craig   | 3     | 01/01/2021 | 06:00-14:00

注意:如果有人被转移到另一个楼层(偶尔),我想将该 Shift/s 保留在该楼层独有的单独行上,以便可以拆分楼层数据并通过电子邮件发送给该楼层的经理。 只要行的所有数据都相同,除了 Shift,我想组合这些行并列出 Shifts。 再次感谢!

【问题讨论】:

看来你需要STRING_AGG 我在这里解释了同样的事情:***.com/questions/69895021/… 我可以将它添加到我现有的查询中吗? Anton Grig 在下面做了,但还是不行 我对 STRING_AGG 命令进行了一些研究 - 我的数据库版本不够新,无法使用它(SQL Server 12) 【参考方案1】:

如前所述,您应该按如下方式使用 String_Agg 函数:

SELECT [StaffID], Max([Name]) As Name, [Floor], [Date], String_Agg([Shift], ',') WITHIN GROUP (ORDER BY [Shift]) As Shifts
FROM (
SELECT
    ST.STAFFNUM [StaffID],
    ST.FULLNAME [Name],
    ST.AREA [Floor],
    CONVERT(VARCHAR(10), TS.EVENTDATE, 103) [Date],
    CONCAT(LEFT(CONVERT(VARCHAR(10), TS.SHIFTSTART, 8), 5),'-',LEFT(CONVERT(VARCHAR(10), TS.SHIFTEND, 8), 5)) [Shift]
FROM
    TIMES TS
    LEFT JOIN STAFF ST ON TS.STAFFNUM = ST.STAFFNUM
WHERE
        TS.EVENTDATE BETWEEN '2021/01/01' AND '2021/01/01'
ORDER BY
    ST.AREA,
    ST.FULLNAME,
    TS.EVENTDATE,
    TS.SHIFTSTART) As T
Group by [StaffID], [Floor], [Date]

对于 Sql Server 2012,您可以尝试使用“CTE”和“FOR XML PATH”。

WITH CTE As
(SELECT
    ST.STAFFNUM [StaffID],
    ST.FULLNAME [Name],
    ST.AREA [Floor],
    CONVERT(VARCHAR(10), TS.EVENTDATE, 103) [Date],
    CONCAT(LEFT(CONVERT(VARCHAR(10), TS.SHIFTSTART, 8), 5),'-',LEFT(CONVERT(VARCHAR(10), TS.SHIFTEND, 8), 5)) [Shift]
FROM
    TIMES TS
    LEFT JOIN STAFF ST ON TS.STAFFNUM = ST.STAFFNUM
WHERE
        TS.EVENTDATE BETWEEN '2021/01/01' AND '2021/01/01'
ORDER BY
    ST.AREA,
    ST.FULLNAME,
    TS.EVENTDATE,
    TS.SHIFTSTART)
SELECT [StaffID], MAX([Name]) AS [Name], [Floor], [Date], 
       STUFF((SELECT ', ' + [Shift]  
              FROM CTE
              WHERE [StaffID] = T.[StaffID] AND [Floor] = T.[Floor] AND [Date] = T.[Date]
              FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)'),1,1,'') AS Shifts              
FROM CTE AS T
GROUP BY [StaffID], [Floor], [Date]

【讨论】:

不幸的是,我得到了:函数“String_Agg”可能没有 WITHIN GROUP 子句。 我对 STRING_AGG 命令进行了一些研究 - 我的数据库版本不够新,无法使用它(SQL Server 12) @S.Hampton 我为您的情况添加了另一个解决方案。 非常感谢! - 我必须做的唯一更改是从 CTE 中删除 ORDER BY 子句:“ORDER BY 子句在视图、内联函数、派生表、子查询和公用表表达式中无效,除非还指定了 TOP、OFFSET 或 FOR XML 。”

以上是关于如果行在其他列中具有相同的数据,则 SQL 查询 CONCAT/列出唯一列数据?的主要内容,如果未能解决你的问题,请参考以下文章

如果行不存在具有相同的值,如何在 Mysql 中插入行

SQL,查找两个给定名称在一列中是不是具有相同数字的查询

在 SQL 中只计算一次连接的数据

sql查询以选择两列中具有相同id但不同值的记录

SQL 查询 - 如果存在则更新,否则插入

如果行具有相同的“A 列”值,则用最后一个已知值填充空的“B 列”单元格