根据 String 在 SQL (Snowflake) 中选择一行

Selecting a row in SQL (Snowflake) based on String

所以我有一个硬汉,我已经绞尽脑汁了一段时间。

假设我有一个 table 如下:

ID      Group                 Timestamp   Data
001         A   2021-04-13 12:51:12.063   content121
001  A-Direct   2021-04-13 12:52:13.063   content121
002  A-Direct   2021-04-13 12:50:14.063   content133
003  B-Direct   2021-04-13 12:55:12.063   content132
003         B   2021-04-13 12:56:11.063   content142
003        BA   2021-04-13 12:57:22.063   content153
004         D   2021-04-13 12:10:23.063   content113
004         C   2021-04-13 12:11:43.063   content144
005         C   2021-04-13 12:12:12.063   content111
005         A   2021-04-13 12:13:23.063   content100
005  D-Direct   2021-04-13 12:15:23.063   content121
006         A   2021-04-13 12:51:12.063   content121
006  B-Direct   2021-04-13 12:52:13.063   content121
007  A-Direct   2021-04-13 12:51:12.063   content121
007         A   2021-04-13 12:52:13.063   content121
008  B-Direct   2021-04-13 12:55:12.063   content132
008         B   2021-04-13 12:56:11.063   content142
008  B-Direct   2021-04-13 12:57:22.063   content153
009  B-Direct   2021-04-13 12:55:12.063   content132
009  C-Direct   2021-04-13 12:56:11.063   content142
009  D-Direct   2021-04-13 12:57:22.063   content153

所以我需要一个 table,其中每一行包含一个不同的 ID。但是选择ID的标准有点复杂。

默认选择应该是最近的条目,通过TIMESTAMP选择。

但复杂性来自任何具有 -Direct 行的 ID。具体来说,如果一行有多个条目并且一个是(例如)A,另一个是 A-Direct,我们需要 A。只有当字母匹配时才会出现这种情况。正如在 ID = 006 的例子中看到的,我们想要 B-Direct 因为它的对应物是 A.

所以我要寻找的核心逻辑是

如果 ID 有以相同字符串开头的行,其中一行以 -Direct 结尾,请将其替换为删除的 -Direct

最终输出:

ID      Group
001         A
002  A-Direct
003        BA
004         C
005  D-Direct
006  B-Direct
007         A
008         B
009  D-Direct

为了更加清楚,这里概述了每个 ID 发生的情况:

我知道如何获取最新的,但根据上述标准,我不确定如何调整

WITH data AS (
    select d.*,
        rank() over (
            partition by ID
            order by TIMESTAMP DESC
        ) as num
    FROM table d
)
select ID, TIMESTAMP
    from data
    where num = 1

我可能会从以下内容开始。它不是非常漂亮,所以可能有更好的解决方案,但我认为它可以满足您的需求。

WITH data AS (
    select d.*,
        rank() over (
            partition by ID
            order by TIMESTAMP DESC
        ) as num
    FROM table d
)
select ID, 
 CASE 
  WHEN EXISTS (SELECT * FROM table t WHERE t.id = d.id AND t.group || '-Direct' = d.group) 
   THEN replace(d.group, '-Direct') 
   ELSE d.group 
 END group
    from data d
    where num = 1

这会为每个 id 获取最近的一个(使用您当前的代码),但是 case/exists 语句中的 select 子句会检查是否存在匹配项“-Direct”,如果是,我们从字符串中删除“-Direct”。

使用:

SELECT ID
   ,CASE WHEN MIN(group) OVER(PARTITION BY ID, REPLACE(group, '-Direct'))
             = MAX(group) OVER(PARTITION BY ID, REPLACE(group, '-Direct'))
         THEN group
         ELSE REPLACE(group, '-Direct')
    END AS grp
FROM tab
QUALIFY RANK() OVER(PARTITION BY ID ORDER BY TIMESTAMP DESC) = 1;

Qualify 确保采用每个时间戳的最新值,并且 case 表达式处理“-Direct”覆盖。