【问题标题】:Find closest match to value in another table在另一个表中查找与值最接近的匹配项
【发布时间】:2021-03-11 22:10:41
【问题描述】:

在 PostgreSQL 13 中,我有一个 table_a,其中每个时间戳都有很多行和列。我试图找到 X 列中的值最接近从另一个表获得的基准值的行。 第二个表对于每个时间戳只有一个基准值。对于每个时间戳,我需要返回 table_a 的大部分列。直接提供基准值时,下面的查询可以正常工作。

如何从 table_b 获取基准值以用于此查询?

只需将 table_b.benchmark 替换为 (SELECT benchmark FROM table_b WHERE table_a.timestamp = table_b.timestamp) 会导致“关系“t1”不存在”错误。

也无法找到有效的连接。

table_a:

+-----------------+-----+---------------+
|    timestamp    |  x  | other_columns |
+-----------------+-----+---------------+
| 2020-01-01 8:00 | 100 |               |
| 2020-01-01 8:00 | 200 |               |
| 2020-01-01 8:00 | 300 |               |
| 2020-01-01 8:00 | 400 |               |
| 2020-01-01 8:00 | 500 |               |
| ...             |     |               |
| 2020-01-01 9:00 | 100 |               |
| 2020-01-01 9:00 | 200 |               |
| 2020-01-01 9:00 | 300 |               |
| 2020-01-01 9:00 | 400 |               |
| 2020-01-01 9:00 | 500 |               |
| ...             |     |               |
+-----------------+-----+---------------+

table_b:

+-----------------+-----------+
|    timestamp    | benchmark |
+-----------------+-----------+
| 2020-01-01 8:00 |       340 |
| 2020-01-01 9:00 |       380 |
| ...             |           |
+-----------------+-----------+

预期结果:

+-----------------+-----+
|    timestamp    |  x  |
+-----------------+-----+
| 2020-01-01 8:00 | 300 |
| 2020-01-01 9:00 | 400 |
| ...             |     |
+-----------------+-----+

SQL 查询:

WITH date_filter AS (
    SELECT *
    FROM table_a
    WHERE timestamp >= {start_date} and timestamp < {end_date}
    )

SELECT DISTINCT t1.timestamp, t1.x, t1.etc
FROM date_filter AS t1

INNER JOIN (
    SELECT timestamp, MIN(ABS(x - (table_b.benchmark))) AS target_value
    FROM t1
    GROUP BY timestamp
    ) AS t2

ON t2.timestamp = t1.timestamp AND t2.target_value = ABS(x - (table_b.benchmark))
ORDER BY timestamp ASC;```

【问题讨论】:

    标签: sql postgresql datetime lateral-join postgresql-13


    【解决方案1】:

    一个选项使用横向连接:

    select b.timestamp, a.x
    from table_b b
    cross join lateral (
        select a.*
        from table_a a
        where a.timestamp = b.timestamp
        order by abs(a.x - b.benchmark)
        limit 1
    ) a
    

    你也可以使用distinct on:

    select distinct on (b.timestamp) b.timestamp, a.x
    from table_b b
    inner join table_a a on a.timestamp = b.timestamp
    order by b.timestamp, abs(a.x - b.benchmark)
    

    【讨论】:

    • @HH16:在发布答案后更改问题不是一个好习惯。我建议为此提出一个新问题...
    【解决方案2】:

    我建议横向连接:

    select b.*, a.x
    from table_b b left join lateral
         (select a.*
          from table_a a
          where a.timestamp = b.timestamp
          order by abs(a.x - b.benchmark)
          limit 1
         ) b
         on 1=1;
    

    【讨论】:

      猜你喜欢
      • 2021-02-08
      • 1970-01-01
      • 1970-01-01
      • 2014-09-01
      • 2015-01-23
      • 1970-01-01
      • 2011-07-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多