【问题标题】:Is it possible to have Multiple String_Agg Columns with Conditions是否可以有多个带有条件的 String_Agg 列
【发布时间】:2019-01-29 23:15:40
【问题描述】:

我有下表的活动注册。在表中,多日事件被记录为每个注册日期的单独记录。此外,如果日期已满,该日期仍可注册为候补日期。我正在尝试从下表中的记录创建单个记录,其中日期是字符串聚合的。如下所示的表格,以及几个相关的表格比这更复杂,但为了举例,我进行了简化。

事件分配表

+--------+---------+----------+--------+------------+
| UserID | EventID | AssignID | DateID | WaitListed |
+--------+---------+----------+--------+------------+
|      1 |      19 |       14 |     67 |          0 |
|      1 |      19 |       14 |     68 |          0 |
|      1 |      19 |       14 |     69 |          1 |
+--------+---------+----------+--------+------------+ 

事件日期表

+--------+-------------------------+---------+------------+
| DateID |        EventDate        | EventID | DateTypeID |
+--------+-------------------------+---------+------------+
|     65 | 2019-03-20 00:00:00.000 |      19 |          1 |
|     66 | 2019-03-21 00:00:00.000 |      19 |          1 |
|     67 | 2019-03-22 00:00:00.000 |      19 |          2 |
|     68 | 2019-03-23 00:00:00.000 |      19 |          2 |
|     69 | 2019-03-24 00:00:00.000 |      19 |          2 |
|     70 | 2019-03-25 00:00:00.000 |      19 |          3 |
+--------+-------------------------+---------+------------+

所需的查询结果应如下所示:

+--------+---------+----------+----------------------------+---------------+
| UserID | EventID | AssignID |      RegisteredDates       | WaitListDates |
+--------+---------+----------+----------------------------+---------------+
|      1 |      19 |       14 | 03/22/2019<br />03/23/2019 | 03/24/2019    |
+--------+---------+----------+----------------------------+---------------+

我在想我需要一些逻辑,所以我尝试实现 CASE 的使用,如下所示。然而,结果仍然显示为两条记录。常规日期的第一条记录,等待列出日期的第二条记录

SELECT a.UserID, a.EventID, a.AssignID, 
(CASE WHEN a.WaitListed = 'false' 
    THEN STRING_AGG(CONVERT(varchar, d.EventDate, 101), '<br />') END) AS RegDates, 
(CASE WHEN a.WaitListed = 'true' 
    THEN STRING_AGG(CONVERT(varchar, d.EventDate, 101), '<br />') END) AS WaitListDates
FROM dbo.EventAssignments AS a 
INNER JOIN dbo.EventDates AS d ON a.DateID = d.DateID
GROUP BY a.UserID, a.EventID, a.WaitListed, a.AssignID

【问题讨论】:

    标签: sql sql-server tsql string-aggregation


    【解决方案1】:

    试试这个查询:

    SELECT a.UserID, 
           a.EventID, 
           a.AssignID, 
    STRING_AGG(CASE WHEN a.WaitListed = 'false' 
        THEN CONVERT(varchar, d.EventDate, 101) END, '<br />') AS RegDates, 
    STRING_AGG(CASE WHEN a.WaitListed = 'true' 
        THEN CONVERT(varchar, d.EventDate, 101) END, '<br />') AS WaitListDates
    FROM dbo.EventAssignments AS a 
    INNER JOIN dbo.EventDates AS d 
      ON a.DateID = d.DateID
    GROUP BY a.UserID, a.EventID, a.AssignID
    

    结果:

    UserID  EventID AssignID    RegDates                    WaitListDates
    1       19      14          03/22/2019<br />03/23/2019  03/24/2019
    

    【讨论】:

    • 所以昨晚我采取了不同的方法,并运行了一个子查询以从返回 RegDates 的主查询中返回 WaitListedDates。尽管我确实找到了自己问题的解决方案,但我授予您已接受的答案,因为它纠正了我原始帖子的问题,并且可能是性能更高的代码。 ——
    【解决方案2】:

    结果中缺少连续的&lt;br /&gt; 是我的错。

    你能用递归 CTE 试试这个吗?
    它可能需要替换 concat 运算符以及 ISNULL,但我不太确定您的 DBMS...

    WITH OrderedDates AS (
    SELECT a.UserID, a.EventID, a.AssignID, a.WaitListed, CONVERT(varchar, d.EventDate, 101)                AS strEventDate,
        ROW_NUMBER() OVER (Partition BY a.UserID, a.EventID, a.AssignID, a.WaitListed ORDER BY d.EventDate) AS EventDateOrder,
        COUNT(*)     OVER (Partition BY a.UserID, a.EventID, a.AssignID, a.WaitListed)                      AS EventDateCount
    FROM EventAssignments AS a 
    INNER JOIN EventDates AS d ON a.DateID = d.DateID
    ), ConcatDates AS (
        SELECT UserID, EventID, AssignID, WaitListed, EventDateOrder, EventDateCount, strEventDate
        FROM OrderedDates
        WHERE EventDateOrder = 1
        UNION ALL
        SELECT OD.UserID, OD.EventID, OD.AssignID, OD.WaitListed, OD.EventDateOrder, OD.EventDateCount, CD.strEventDate + '<br />' + OD.strEventDate
        FROM OrderedDates OD
        JOIN ConcatDates CD on OD.UserID = CD.UserID AND OD.EventID = CD.EventID AND OD.AssignID = CD.AssignID AND OD.WaitListed = CD.WaitListed AND OD.EventDateOrder = CD.EventDateOrder + 1
    )
    SELECT ISNULL(CD1.UserID, CD2.UserID), ISNULL(CD1.EventID, CD2.EventID), ISNULL(CD1.AssignID, CD2.AssignID), CD1.strEventDate, CD2.strEventDate
    FROM            (SELECT * FROM ConcatDates WHERE EventDateCOunt = EventDateOrder AND WaitListed = 'false') CD1
    FULL OUTER JOIN (SELECT * FROM ConcatDates WHERE EventDateCOunt = EventDateOrder AND WaitListed = 'true' ) CD2 ON CD1.UserID = CD2.UserID AND CD1.EventID = CD2.EventID AND CD1.AssignID = CD2.AssignID
    

    【讨论】:

    • 在使用varchar()时,您应该始终有一个长度。
    • @GordonLinoff,你是绝对正确的。只是想在我担心其他细节之前让逻辑正常工作。
    • @Lau,答案确实根据需要创建了一条记录,但它在 RegDated 和 WaitlistDates 列中的某些日期之前和之后添加了额外的不需要的
      标签。注册日期 03/22/2019
      03/23/2019

      03/25/2019 WaitListedDates

      03/24/2019
      我确实添加了测试时的额外日期。
    • 该解决方案不需要使用CASE,它可以使用任何其他可行的方法。我只是在我的舒适区使用 CASE。
    • 我想我会用 regexp_replace 包围 string_agg 。像regexp_replace( string_agg(...), '(&lt;br /&gt;)+', '&lt;br&gt;') 这样的东西。可能需要对某些字符进行转义...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-02
    • 2016-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-16
    • 2013-02-03
    相关资源
    最近更新 更多