4

我有一个数据库表,其结构如下所示:

CREATE TABLE dated_records (
              recdate DATE NOT NULL
              col1    DOUBLE NOT NULL,
              col2    DOUBLE NOT NULL,
              col3    DOUBLE NOT NULL,
              col4    DOUBLE NOT NULL,
              col5    DOUBLE NOT NULL,
              col6    DOUBLE NOT NULL,
              col7    DOUBLE NOT NULL,
              col8    DOUBLE NOT NULL
              );

我想编写一个 SQL 语句,允许我返回一条记录,其中包含两个提供的日期之间的更改,对于指定的列 - 例如 col1、col2 和 col3

例如,如果我想查看 col1、col2 和 col3 中的值在两个日期之间的时间间隔内发生了多少变化。这样做的一种愚蠢方法是(分别)为每个日期选择行,然后区分数据库服务器之外的字段 -

SQL1 = "SELECT col1, col2 col3 FROM dated_records WHERE recdate='2001-01-01'";
SQL1 = "SELECT col1, col2 col3 FROM dated_records WHERE recdate='2001-02-01'";

但是,我确信有一种更智能的方法可以使用纯 SQL 执行差分。我这将涉及使用自连接(可能还有嵌套子查询),但我可能过于复杂了 - 我决定最好在这里询问 SQL 专家,看看他们将如何解决这个问题最有效的方式。

理想情况下,SQL 应该与数据库无关,但如果需要将其绑定到特定数据库,那么它必须是 PostgreSQL。

4

5 回答 5

4

只需选择两行,将它们合二为一,然后减去值:

select d1.recdate, d2.recdate,
       (d2.col1 - d1.col1) as delta_col1,
       (d2.col2 - d1.col2) as delta_col2,
       ...
from (select *
      from dated_records
      where recdate = <date1>
     ) d1 cross join
     (select *
      from dated_records
      where recdate = <date2>
     ) d2
于 2012-05-07T21:36:11.253 回答
2

我认为,如果您要做的是获取不与两个选择查询相交的结果集行,则可以使用 EXCEPT 运算符:

EXCEPT 运算符返回在第一个结果集中但不在第二个结果集中的行。

因此,您的两个查询将成为一个查询,其中包含 except 运算符:

SELECT col1, col2 col3 FROM dated_records WHERE recdate='2001-01-01'
EXCEPT
SELECT col1, col2 col3 FROM dated_records WHERE recdate='2001-02-01'
于 2012-05-07T21:37:17.197 回答
0

You could use window functions plus DISTINCT:

SELECT DISTINCT
       first_value(recdate) OVER () AS date1
      ,last_value(recdate)  OVER () AS date2
      ,last_value(col1)     OVER () - first_value(col1) OVER () AS delta1
      ,last_value(col2)     OVER () - first_value(col2) OVER () AS delta2
       ...
FROM   dated_records
WHERE  recdate IN ('2001-01-01', '2001-01-03')

For any two days. Uses a single index or table scan, so it should be fast.

I did not order the window, but all calculations use the same window, so the values are consistent.

This solution can easily be generalized for calculations between n rows. You may want to use nth_value() from the Postgres arsenal of window functions in this case.

于 2012-05-08T00:52:43.673 回答
0

This seemed a quicker way to write this if you are looking for a simple delta.

SELECT first(col1) - last(col1) AS delta_col1
, first(col2) - last(col2) AS delta_col2
FROM dated_records WHERE recdate IN ('2001-02-01', '2001-01-01')

You may not know whether the first row or the second row comes first, but you can always wrap the answer in abs(first(col1)-last(col1))

于 2012-05-08T03:47:13.203 回答
0
SELECT
COALESCE
(a.col1 -
  (
    SELECT b.col1
    FROM dated_records b
    WHERE b.id = a.id + 1
  ),
a.col1)
FROM dated_records a
WHERE recdate='2001-01-01';
于 2012-05-07T21:52:06.887 回答