【问题标题】:How can I reference an aggregate column in another column in the same query?如何在同一查询的另一列中引用聚合列?
【发布时间】:2013-07-08 09:33:03
【问题描述】:

我的查询看起来或多或少像这样:

INSERT INTO #results
SELECT Name, 
        (SELECT 
            SUM(CAST(Amount AS BIGINT)) 
         FROM Items 
         WHERE RemittingMember = a.Number 
            and RecordId = 50), 
        (SELECT SUM(CAST(Std_Amount AS BIGINT)) 
         FROM Items 
         WHERE RemittingMember = a.Number 
            AND RecordId = 10)
FROM Member a

其中Amount 是货币(存储为varchar,没有小数点),RemittingMemberItems 表和Member 表之间的链接,RecordId 表示该行的项目类型是。在这种情况下,50 是借方,10 是贷方。

我需要从第二列中减去第一列,并将该值放在第三列中。我知道我可以这样做:

INSERT INTO #results
SELECT Name, 
            (SELECT 
                SUM(CAST(Amount AS BIGINT)) 
             FROM Items 
             WHERE RemittingMember = a.Number 
                and RecordId = 50), 
            (SELECT SUM(CAST(Std_Amount AS BIGINT)) 
             FROM Items 
             WHERE RemittingMember = a.Number 
                AND RecordId = 10),
             (SELECT 
                SUM(CAST(Amount AS BIGINT)) 
             FROM Items 
             WHERE RemittingMember = a.Number 
                and RecordId = 50) - (SELECT SUM(CAST(Std_Amount AS BIGINT)) 
             FROM Items 
             WHERE RemittingMember = a.Number 
                AND RecordId = 10)    
FROM Member a

但是如果需要进行更改,这将很难阅读并且更改起来很麻烦。我也知道我可以使用局部变量来做到这一点,但这是一份报告,其中a.Number 将发生变化,这将涉及我想要避免的迭代。

我还需要检查第三列的符号以将值放入第四列。

有没有聪明的方法来实现这一点?

【问题讨论】:

    标签: sql-server-2008 tsql subquery aggregate-functions


    【解决方案1】:

    您应该能够进一步简化查询,以删除对 items 表的附加连接。像这样的东西应该工作。 需要使用您的数据进行测试

    SELECT
        name, 
        debit, 
        credit, 
        Amount = debit - credit, 
        [SIGN] = SIGN(debit - credit)
    FROM Member a
    inner join(
         SELECT 
            RemittingMember,
            debit=SUM(CASE WHEN RecordId = 50 THEN CAST(Amount AS BIGINT) ELSE 0 END),
            credit=SUM(CASE WHEN RecordId = 10 THEN CAST(Std_Amount AS BIGINT) ELSE 0 END)
         FROM Items 
         WHERE RecordId IN(10,50)
         GROUP BY
            RemittingMember
    ) as Amts
        on Amts.RemittingMember = a.Number 
    

    【讨论】:

      【解决方案2】:

      您可以使用 CTE,如下所示:

      ;WITH intermediate_results (name, debit, credit)
      AS (
      SELECT
          Name
          AS name, 
      
          (SELECT 
              SUM(CAST(Amount AS BIGINT)) 
           FROM Items 
           WHERE RemittingMember = a.Number 
              and RecordId = 50)
          AS debit, 
      
          (SELECT SUM(CAST(Std_Amount AS BIGINT)) 
           FROM Items 
           WHERE RemittingMember = a.Number 
              AND RecordId = 10)
          AS credit
      
      FROM Member a
      )
      
      INSERT INTO #results
      SELECT name, debit, credit, debit - credit, SIGN(debit - credit)
        FROM intermediate_results
      

      【讨论】:

      • 更新:在结果 SELECT 语句中添加了第五列
      【解决方案3】:

      你可以使用outer apply声明:

      INSERT INTO #results
      SELECT Name, 
              s1.Value, 
              s2.Value,
              s2.Value - s1.Value,
              case
                  when s2.Value > s1.Value then 1
                  when s2.Value < s1.Value then -1
                  else 0
              end
      FROM Member a
          outer apply (SELECT 
                  SUM(CAST(Amount AS BIGINT)) Value
               FROM Items 
               WHERE RemittingMember = a.Number 
                  and RecordId = 50) s1
          outer apply (SELECT 
                  SUM(CAST(Std_Amount AS BIGINT)) Value
               FROM Items 
               WHERE RemittingMember = a.Number 
                  and RecordId = 10) s2
      

      【讨论】:

      • 你是第一个,但在我的情况下 CTE 更快:)
      • 当我回答 CTE 时,我也喜欢这个答案。顺便说一句,可能因为计算符号列而速度较慢。 CASE 太慢,尝试使用SIGN() function 另外,将第五列添加到 CTE 答案并再次运行测试:-)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-08
      • 2019-11-23
      • 2018-06-02
      • 1970-01-01
      • 2013-07-10
      • 1970-01-01
      • 2014-05-29
      相关资源
      最近更新 更多