在单个SQL SELECT语句中区分两行

时间:2012-05-07 21:31:38

标签: sql postgresql

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

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。

5 个答案:

答案 0 :(得分: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

答案 1 :(得分: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'

答案 2 :(得分: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';

答案 3 :(得分:0)

您可以使用窗口功能以及 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')

任何两天。使用单个索引或表扫描,因此它应该很快。

我没有订购窗口,但所有计算都使用相同的窗口,因此值是一致的。

该解决方案可以很容易地推广用于n行之间的计算。在这种情况下,您可能希望使用Postgres arsenal of window functions中的nth_value()

答案 4 :(得分:0)

如果你正在寻找一个简单的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')

您可能不知道第一行或第二行是否排在第一位,但您始终可以将答案包装在abs(first(col1)-last(col1))