匹配 Redshift SQL 中最近的时间戳

Posted

技术标签:

【中文标题】匹配 Redshift SQL 中最近的时间戳【英文标题】:Match nearest timestamp in Redshift SQL 【发布时间】:2021-12-05 12:13:08 【问题描述】:

我有两张桌子,t1 和 t2。对于 t1 中的每个 id,我在 t2 中有多个记录。我想将 t2 的最近时间戳与 t1 的每条记录相匹配。在 t1 中有一个标志,如果它是 1,我想匹配 t2 的最接近的较小的时间戳,如果它是 0,我想匹配大于 t1 中的最接近的时间戳。 所以我总共有下表: T1 id、标志、时间戳 T2 id,时间戳

有没有有效的方法来做到这一点?

编辑,这里有一些例子:

T1

customer_id timestamp_t1 flag
1 01.01.21 12:00 1
2 01.01.21 13:00 0

T2

customer_id timestamp_t2 additional attributes
1 01.01.21 11:00 attribute1
1 01.01.21 10:00 attribute2
1 01.01.21 13:00 attribute3
2 01.01.21 11:00 attribute4
2 01.01.21 12:00 attribute5
2 01.01.21 14:00 attribute6
2 01.01.21 15:00 attribute7

结果:

customer_id timetsamp_t1 timestamp_t2 flag additional attributes
1 01.01.21 12:00 01.01.21 11:00 1 attribute1
2 01.01.21 13:00 01.01.21 14:00 0 attribute6

我希望这会有所帮助。如你看到的。结果,我们将 T2 的 11:00 与 T1 的 12:00 匹配,因为标志为 1,我们选择了小于 12:00 的最接近的时间戳。我们还将 14:00 与 13:00 进行了匹配,因为标志为 0(因此我们匹配了 id 为 2 且大于 13:00 的最接近的时间戳)。

【问题讨论】:

提供样本数据和期望的结果会更有帮助 你需要table2的id还是时间戳?时间戳 table2 是否保证唯一? (这是示例数据和所需结果非常有用的一个示例。) 感谢您的建议。我添加了一个应该清楚的例子。我注意到这样解释会更好。 customer_id 在 T1 中是否唯一? T2 是否有id 列? 【参考方案1】:

您可以使用相关子查询来查找时间戳之前/之后的行,然后使用 CASE 表达式来选择要加入的行...

SELECT
  *
FROM
  t1
INNER JOIN
  t2
    ON t2.id = CASE WHEN t1.flag = 1 THEN
                 (
                   SELECT t2.id
                     FROM t2
                    WHERE t2.customer_id   = t1.customer_id
                      AND t2.timestamp_t2 <= t1.timestamp_t1
                 ORDER BY t2.timestamp DESC
                    LIMIT 1
                 )
               ELSE
                 (
                   SELECT t2.id
                     FROM t2
                    WHERE t2.customer_id   = t1.customer_id
                      AND t2.timestamp_t2 >= t1.timestamp_t1
                 ORDER BY t2.timestamp ASC
                    LIMIT 1
                 )
               END

哦,您的示例中没有包含 id 列,这同样适用...

SELECT
  *
FROM
  t1
INNER JOIN
  t2
    ON  t2.customer_id  = t1.customer_id
    AND t2.timestamp_t2
        =
        CASE WHEN t1.flag = 1 THEN
          (
            SELECT MAX(t2.timestamp_t2)
              FROM t2
             WHERE t2.customer_id   = t1.customer_id
               AND t2.timestamp_t2 <= t1.timestamp_t1
          )
        ELSE
          (
            SELECT MIN(t2.timestamp_t2)
              FROM t2
             WHERE t2.customer_id   = t1.customer_id
               AND t2.timestamp_t2 >= t1.timestamp_t1
          )
        END

【讨论】:

嘿,非常感谢。这是一个简单的解决方案,我很惊讶。我想到了一个非常复杂的分区方法。我想知道这对于更大的数据集是否是最有效的方法。 @MiepMiep 分区将允许您在两个查询中使用 UNION ALL,而不是在单个查询中使用 CASE 表达式。如果您想询问有关重塑数据的问题,您应该在问题中说明(提供完整的 DDL、有关数据量、基数等的详细信息)。

以上是关于匹配 Redshift SQL 中最近的时间戳的主要内容,如果未能解决你的问题,请参考以下文章

SQL (RedShift):从时间戳列中为每个月选择不同的日期

2 个时间戳之间的 SQL Redshift 天数差异

Redshift sql根据某个记录之前的时间戳识别记录

从 SQL 中的时间戳中提取时间

Redshift (SQL):尝试转换为时间戳

过去 7 天 Unix/Redshift 过滤器不工作