繁体   English   中英

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

[英]Difference two rows in a single SQL SELECT statement

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

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。

只需选择两行,将它们连接成一行,然后减去这些值:

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

我想如果你想要做的是获取与两个select查询不相交的结果集行,你可以使用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'
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';

您可以使用窗口函数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窗口函数库中的 nth_value()

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM