SQL:查明一个事件是否发生在另一个事件之前或之后

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

我有两张这样的桌子:

CREATE TABLE XX 
(
    name VARCHAR(50),
    date DATE,
    a INT,
    b INT,
    c INT
);

INSERT INTO XX (name, date, a, b, c) 
VALUES 
('john', '2010-11-01', 1, 0, 0),
('john', '2010-10-01', 0, 1, 0),
('sara', '1999-02-01', 1, 0, 0),
('julie', '2015-09-01', 1, 0, 0),
('julie', '2015-09-01', 0, 1, 0);


  name       date a b c
  -----------------------
  john 2010-11-01 1 0 0
  john 2010-10-01 0 1 0
  sara 1999-02-01 1 0 0
 julie 2015-09-01 1 0 0
 julie 2015-09-01 0 1 0

还有另一张桌子

CREATE TABLE YY 
(
    name VARCHAR(50),
    yy_date DATE,
    yy CHAR(1)
);

INSERT INTO YY (name, yy_date, yy) 
VALUES 
('john', '2015-01-01', 'A'),
('john', '2016-01-01', 'A'),
('john', '2000-02-01', 'B'),
('john', '2010-03-01', 'C'),
('julie', '2017-09-01', 'A'),
('julie', '2010-09-01', 'B');
('tom', '2010-09-01', 'B');


  name  yy_date     yy
  --------------------
  john  2015-01-01  A
  john  2016-01-01  A
  john  2000-02-01  B
  john  2010-03-01  C
  julie 2017-09-01  A
  julie 2010-09-01  B
  tom   2010-09-01  B

我想编写一个 SQL 查询来回答以下问题:

在特定日期收到 type_yy 的客户,即使他们在该日期之前已经拥有相同类型的 xx

例如

  • John,A:XX 发生在 YY 之前
  • John, B:YY 发生在 XX 之前
  • Sara:不适用(仅出现在一张表中)
  • 朱莉,A:XX 发生在 YY 之前
  • 朱莉,B:XX 发生在 YY 之后
  • Tom:不适用(仅出现在一张表中)

最终结果应该是表YY,其中有一个额外的列,指示对于每个(名称,类型),XX是否发生在YY之前或XX是否发生在YY之后。

 name   yy_date yy  xx_vs_yy
 --------------------------------------------
 john   2015-01-01  A XX happened before YY   
john   2016-01-01  A XX happened before YY
 john   2000-02-01  B YY happened before XX
 john   2010-03-01  C        Not applicable
 julie  2017-09-01  A XX happened before YY
 julie  2010-09-01  B YY happened before XX
 tom    2010-09-01  B        Not applicable

是否可以使用多个 CTE、CASE WHEN、UNION ALL 和 MAX 语句来执行类似的操作?

WITH earliest_xx AS 
(
    SELECT name, MIN(date) as earliest_xx_date
    FROM XX
    GROUP BY name
),
yy_with_xx AS 
(
    SELECT 
        y.name, 
        y.yy_date, 
        y.yy, 
        e.earliest_xx_date
    FROM YY y
    LEFT JOIN earliest_xx e ON y.name = e.name
),
comparison_result AS 
(
    SELECT 
        name, 
        yy_date, 
        yy,
        CASE
            WHEN earliest_xx_date IS NULL THEN 'Not applicable'
            WHEN earliest_xx_date < yy_date THEN 'XX happened before YY'
            ELSE 'YY happened before XX'
        END as xx_vs_yy
    FROM yy_with_xx
)
SELECT *
FROM comparison_result
ORDER BY name, yy_date;

我对这个问题感到有点迷失......


我认为我在这方面取得了一些进展 - 需要添加一些内容以确保 XX 日期对应于 XX 和 YY 之间的相同类型(例如,a 到 a、b 到 b、c 到 c):

WITH xx_mapped AS (
    SELECT name, date, 
           CASE 
               WHEN a = 1 THEN 'A'
               WHEN b = 1 THEN 'B'
               WHEN c = 1 THEN 'C'
           END AS xx_type
    FROM XX
),
earliest_xx AS (
    SELECT name, xx_type, MIN(date) as earliest_xx_date
    FROM xx_mapped
    GROUP BY name, xx_type
),
yy_with_xx AS (
    SELECT 
        y.name, 
        y.yy_date, 
        y.yy, 
        e.earliest_xx_date
    FROM YY y
    LEFT JOIN earliest_xx e ON y.name = e.name AND y.yy = e.xx_type
),
comparison_result AS (
    SELECT 
        name, 
        yy_date, 
        yy,
        CASE
            WHEN earliest_xx_date IS NULL THEN 'Not applicable'
            WHEN earliest_xx_date < yy_date THEN 'XX happened before YY'
            WHEN earliest_xx_date > yy_date THEN 'YY happened before XX'
            ELSE 'XX and YY happened on the same date'
        END as xx_vs_yy
    FROM yy_with_xx
)
SELECT *
FROM comparison_result
ORDER BY name, yy_date;
sql db2
1个回答
0
投票

左连接应该得到你想要的结果:

select y.name, y.yy_date, y.yy,
  case when x.date is null then 'Not applicable'
       when x.date > y.yy_date then 'YY happened before XX'
       else 'XX happened before YY'
  end as xx_vs_yy
from yy y
left join xx x on x.name = y.name and (
  x.a = 1 and y.yy = 'A' or
  x.b = 1 and y.yy = 'B' or
  x.c = 1 and y.yy = 'C');

结果:

NAME    YY_DATE    YY  XX_VS_YY             
-----  ----------  --  ---------------------
john   2015-01-01  A   XX happened before YY
john   2016-01-01  A   XX happened before YY
john   2000-02-01  B   YY happened before XX
john   2010-03-01  C   Not applicable       
julie  2017-09-01  A   XX happened before YY
julie  2010-09-01  B   YY happened before XX
tom    2010-09-01  B   Not applicable       
© www.soinside.com 2019 - 2024. All rights reserved.