【问题标题】:How to reuse a result column in an expression for another result column如何将表达式中的结果列重用于另一个结果列
【发布时间】:2011-05-12 08:36:42
【问题描述】:

例子:

SELECT
   (SELECT SUM(...) FROM ...) as turnover,
   (SELECT SUM(...) FROM ...) as cost,
   turnover - cost as profit

确定这是无效的(至少在 Postgres 中),但是如何在不重写子查询两次的情况下在查询中实现相同的效果?

【问题讨论】:

  • 取决于详细信息,例如所涉及的列和表。
  • @OMG Ponis:喜欢吗?没有通用的方法吗?
  • 我同意@OMG。也就是说,如果您可以编写 one 子查询,将turnovercost 作为列返回,则围绕该子查询的查询可以执行turnover - cost。有关更多详细信息,我们需要有关您的架构的一些详细信息。
  • 还可以考虑使用“通用表表达式”,也就是 CTE。见stackoverflow.com/questions/2686919/…postgresql.org/docs/8.4/static/queries-with.html
  • 已编辑标题:此问题不关注重用子查询(表),而是关注单个列,与 stackoverflow.com/q/2686919/648265 不同。

标签: sql postgresql subquery


【解决方案1】:

像这样:

SELECT
   turnover,
   cost,
   turnover - cost as profit
from (
   (SELECT SUM(...) FROM ...) as turnover,
   (SELECT SUM(...) FROM ...) as cost
   ) as partial_sums

【讨论】:

  • 通常当您执行select from table1, table2 时,您会得到两个表的 CROSS JOIN。 select from (table1, table2) as bla(就像你在这里一样)对这两个表做了什么?
  • @CharlBotha:它不是从 (foo, bar) 中选择的。它是 [select] (select sum from foo), (select sum from bar) [from nothing]。
  • 在你上面的例子中,你有... from ((select ...) as turnover, (select ...) as cost) as partial_sums——我仍然想知道营业额和成本子选择究竟是如何组合的?
  • @CharlBotha:它们是两个标量,与select 1 as foo, 2 as bar 的方式非常相似。
  • 如果子选择也使用普通的 FROM 怎么办:S
【解决方案2】:

您可以像这样重用查询:

WITH 
  TURNOVER AS (
    SELECT SUM(...) FROM ...)
  ),
  COST AS(
    SELECT SUM(...) FROM ...
  )

SELECT *
FROM(
 SELECT
   TURNOVER.sum as SUM_TURNOVER
 FROM
 TURNOVER,COST
 WHERE ....
) AS a

这相当于:

SELECT *
FROM(
 SELECT
   TURNOVER.sum as SUM_TURNOVER
 FROM
 (
   SELECT SUM(...) FROM ...)
 )AS TURNOVER,
 (
   SELECT SUM(...) FROM ...
 )AS COST
 WHERE ....
) AS a

这里有一点需要注意。第一种方法更具可读性和可重用性,但第二种方法可能更快,因为 DB 可能会为它选择更好的计划。

【讨论】:

    【解决方案3】:

    也许 sql "with" 子句会有所帮助,如 http://orafaq.com/node/1879 所述(其他数据库如 Postgres 也可以这样做,而不仅仅是 oracle)。

    【讨论】:

    【解决方案4】:
    SELECT turnover, cost, turnover - cost
    FROM
    (
    SELECT
    (SELECT ...) as turnover,
    (SELECT ...) as cost
    ) as Temp
    

    【讨论】:

    • 如果营业额和成本是表别名,你肯定不能这样做:营业额-成本作为利润
    • 无效:错误:FROM 中的子查询必须有别名提示:例如,FROM (SELECT ...) [AS] foo。
    • 在我的查询中,Temp 是 FROM 中子查询的别名
    【解决方案5】:

    实际上,我在这方面做了很多工作,遇到了许多砖墙,但最终找到了答案——更像是一个 hack——但它工作得很好,并将我的查询的读取开销减少了 90%... .

    因此,我没有多次复制相关查询以从子查询中检索多个列,而是将我想要返回的所有值连接到逗号分隔的 varchar 中,然后在应用程序中再次展开它们......

    所以不是

    select a,b,
    (select x from bigcorrelatedsubquery) as x,
    (select y from bigcorrelatedsubquery) as y,
    (select z from bigcorrelatedsubquery) as z
    from outertable
    

    我现在做

    select a,b,
    (select convert(varchar,x)+','+convert(varchar,x)+','+convert(varchar,x)+',' 
    from bigcorrelatedsubquery) from bigcorrelatedquery) as xyz
    from outertable
    group by country
    

    我现在拥有我需要的所有三个相关的“标量”值,但只需要执行一次相关的子查询而不是三次。

    【讨论】:

    • 你应该应该做的是JOIN bigcorrelatedsubqueryoutertable 一次,而不是重复多次或诉诸 concat hack。即使在最坏的情况下,您也可以将该子查询作为 CTE 考虑以避免重复。
    【解决方案6】:

    我认为以下方法会起作用:

    SELECT turnover, cost, turnover-cost as profit FROM
       (SELECT 1 AS FAKE_KEY, SUM(a_field) AS TURNOVER FROM some_table) a
    INNER JOIN
       (SELECT 1 AS FAKE_KEY, SUM(a_nother_field) AS COST FROM some_other_table) b
    USING (FAKE_KEY);
    

    未在动物身上进行测试 - 你会是第一个! :-)

    分享和享受。

    【讨论】:

      【解决方案7】:

      使用交叉应用或外部应用。

      SELECT
        Calc1.turnover,
        Calc2.cost,
        Calc3.profit
      from
         cross apply ((SELECT SUM(...) as turnover FROM ...)) as Calc1
         cross apply ((SELECT SUM(...) as cost FROM ...)) as Calc2
      
         /*
           Note there is no from Clause in Calc 3 below.
           This is how you can "stack" formulas like in excel.
           You can return any number of columns, not just one.
         */
         cross apply (select Calc1.turnover - Calc2.cost as profit) as Calc3
      

      【讨论】:

        【解决方案8】:

        这已经很老了,但是我遇到了这个问题并看到了这篇文章,但没有设法使用给定的答案解决我的问题,所以我最终找到了这个解决方案:

        如果您的查询是:

        SELECT
           (SELECT SUM(...) FROM ...) as turnover,
           (SELECT SUM(...) FROM ...) as cost,
           turnover - cost as profit
        

        你可以把它变成一个子查询,然后使用如下字段:

        SELECT *,(myFields.turnover-myFields.cost) as profit 
        FROM
        (      
        SELECT
               (SELECT SUM(...) FROM ...) as turnover,
               (SELECT SUM(...) FROM ...) as cost
        
        ) as myFields
        

        我不完全确定这是否是一种糟糕的做事方式,但从性能方面来说,我查询 224,000 记录似乎没问题,需要 1.5 秒 不确定它后来是否变成了 DB 相同子查询的 2 倍。

        【讨论】:

          【解决方案9】:

          你可以像这样使用用户定义的变量

          SELECT
             @turnover := (SELECT SUM(...) FROM ...),
             @cost := (SELECT SUM(...) FROM ...),
             @turnover - @cost as profit
          

          http://dev.mysql.com/doc/refman/5.7/en/user-variables.html

          【讨论】:

          • 也许这对 MySQL 有帮助,但对 Postgres 有帮助?
          猜你喜欢
          • 2018-11-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-11-12
          • 2013-04-20
          • 2021-02-10
          • 1970-01-01
          相关资源
          最近更新 更多