将同一查询中的计算列重新用于其他计算

时间:2020-01-28 15:54:08

标签: sql postgresql subquery

我必须使用计算列来计算另一列的值。因为我使用的是非常大的表,并且还对前两列进行了复杂的计算,所以重复相同的函数来派生第三列并不是一个好主意,因此寻找一种使用子查询的方法。 / p>

我的桌子:

SELECT * FROM my_table LIMIT 5;
 session_id |  seconds   | millis |  gpstime   | gpsmillis | nsats |    lat     |    lon     | alt | track |  speed  | acc 
------------+------------+--------+------------+-----------+-------+------------+------------+-----+-------+---------+-----
      14026 | 1460464791 |    264 | 1460464791 |       264 |    -1 |  41.178237 | -8.5947137 |   0 |     0 |       0 |  20
      14026 | 1460464983 |    970 | 1460464983 |       970 |    -1 |  41.177956 | -8.5953581 | 234 |    67 | 10.2583 |  25
      14026 | 1460464984 |    712 | 1460464984 |       712 |    -1 | 41.1780008 | -8.5952012 | 182 |    58 | 9.19696 |  31
      14026 | 1460464985 |    700 | 1460464985 |       700 |    -1 | 41.1779522 |  -8.595209 | 196 |    74 | 7.63053 |  19
      14026 | 1460464986 |    714 | 1460464986 |       714 |    -1 |  41.177981 | -8.5951491 | 196 |    74 | 5.51359 |  22
(5 rows)

然后,我运行下面的查询,以在子查询中计算a1a2,并在主查询中将它们平均为acceleration

SELECT session_id
    , gpstime
    , lat
    , lon
    , track AS heading
    , speed
    , AVG(a1, a2) AS acceleration
FROM (
        SELECT *
            ,((LEAD(speed) OVER (ORDER BY gpstime)) - speed) / 
               (((LEAD(gpstime) OVER (ORDER BY gpstime)) - gpstime) +0.001) AS a2
        , (speed - (LAG(speed) OVER (ORDER BY gpstime))) / 
                     (gpstime - (LAG(gpstime) OVER (ORDER BY gpstime)) + 0.001) AS a1
        FROM my_table
    );

错误:

ERROR:  subquery in FROM must have an alias
LINE 9:  (
         ^
HINT:  For example, FROM (SELECT ...) [AS] foo.
SQL state: 42601
Character: 111

我还向子查询添加了别名,但是没有用。

我发现了这个answer,它似乎适用于Oracle数据库,但是在我的情况下(使用PostgreSQL)却不起作用。我在小提琴here中重现了一个最小的工作示例,以说明问题。

有人可以指出我在这里错过或做错了什么吗?

1 个答案:

答案 0 :(得分:2)

提示告诉您该怎么做:给子查询一个别名:

SELECT session_id
    , gpstime
    , lat
    , lon
    , track AS heading
    , speed
    , AVG(a1) AS acceleration
FROM (
        SELECT *
            ,((LEAD(speed) OVER (ORDER BY gpstime)) - speed) / 
               (((LEAD(gpstime) OVER (ORDER BY gpstime)) - gpstime) +0.001) AS a2
        , (speed - (LAG(speed) OVER (ORDER BY gpstime))) / 
                     (gpstime - (LAG(gpstime) OVER (ORDER BY gpstime)) + 0.001) AS a1
        FROM my_table
    ) as sub; --<< HERE

但是AVG(a1, a2)也是错误的。

avg()是一个聚合函数,适用于单列和独立行。因此,您需要使用avg(a1)avg(a2),或者如果想要两个值之间的平均值,则可能需要(a1 + a2) / 2

Demo