TSQL查询列,如果在行的“链”内满足条件,则为true

问题描述 投票:0回答:1

这是this question的后续行动。这将变得复杂。

我有一个类似以下的表格,用于跟踪特定类型的事件的开始和结束:

+----------+-------------+------------------+------------------+
| PersonID | Weapon Used |     StartDate    |     EndDate      |
+----------+-------------|------------------+------------------+
|      006 | Knife       | 2019-12-01 09:30 | 2019-12-02 06:15 |
|      007 | Grenade     | 2019-12-01 12:15 | 2019-12-01 12:16 |
|      006 | Bat         | 2019-12-02 06:15 | 2019-12-02 15:15 |
|      006 | Pistol      | 2019-12-02 15:15 | 2019-12-02 23:01 |
|      007 | Pistol      | 2019-12-02 07:23 | 2019-12-04 08:30 |
+----------+-------------+------------------+------------------+

我正在尝试创建一个在以下情况下返回TRUE的计算列:

  • 行事件是1+个背对背事件的“链”的一部分。
  • AND手枪在事件链中使用1次以上。
  • AND行事件在链中具有最早的StartDate。

创建这样的表:

+----------+-------------+------------------+------------------+---------+
| PersonID | Weapon Used |     StartDate    |     EndDate      | Pistol+ |
+----------+-------------|------------------+------------------+---------+
|      006 | Knife       | 2019-12-01 09:30 | 2019-12-02 06:15 | TRUE    |
|      007 | Grenade     | 2019-12-01 12:15 | 2019-12-01 12:16 | FALSE   |
|      006 | Bat         | 2019-12-02 06:15 | 2019-12-02 15:15 | FALSE   |
|      006 | Pistol      | 2019-12-02 15:15 | 2019-12-02 23:01 | FALSE   |
|      007 | Pistol      | 2019-12-02 07:23 | 2019-12-04 08:30 | TRUE    |
+----------+-------------+------------------+------------------+---------+

无疑这是一个很高的顺序,但是我必须处理大量的行,因此我拼命尝试避免必须用手和眼球来计算它。这可能吗?

sql-server tsql sorting calculated-columns
1个回答
0
投票

您将需要recursive cte来找到相关的背对背行的grp

seq是标识group的第一个>

[确定组是否包含pistol,它使用带有条件sum()的窗口函数case

with
cte as
(
    select  *, rn = row_number() over (partition by PersonID order by StartDate)
    from    yourtable
),
rcte as
(
    select  c.PersonID, c.[Weapon Used], c.StartDate, c.EndDate, c.rn, 
            grp = 1, seq = 1
    from    cte c
    where   rn  = 1

    union all

    select  c.PersonID, c.[Weapon Used], c.StartDate, c.EndDate, c.rn,
            grp   = case    when    r.EndDate = c.StartDate
                            then    r.grp
                            else    r.grp + 1
                            end,
            seq   = case    when    r.EndDate = c.StartDate
                            then    r.seq + 1
                            else    1
                            end
    from    cte c
            inner join rcte r   on  c.PersonID  = r.PersonID
                               and  c.rn        = r.rn + 1
)
select  *,
        case    when    seq = 1
                and     sum(case when [Weapon Used] = 'Pistol' then 1 else 0 end) 
                        over (partition by PersonID, grp) >= 1
                then    'TRUE'
                else    'FALSE'
                end
from    rcte;
© www.soinside.com 2019 - 2024. All rights reserved.