我的查询可以提高效率吗?如何添加GROUP BY子句?

时间:2019-09-22 18:35:35

标签: sql sql-server group-by

我正在尝试编写一个返回以下内容的查询:

  1. 特定客户在日期范围之前发生的交易总数。
  2. 在特定日期范围内针对特定客户的交易总额。
  3. 在日期范围之前针对特定客户的总付款额。
  4. 在特定日期范围内针对特定客户的总付款额。

为此,我提出了以下查询。

declare @StartDate DATE = '2016-08-01'
declare @EndDate DATE = '2016-08-31'
declare @BillingCategory INT = 0

select c.Id, c.Name, c.StartingBalance,
(select coalesce(sum(Amount), 0) from Transactions t where t.CustomerId = c.Id and t.[Date] < @StartDate) xDebits,
(select coalesce(sum(Amount), 0) from Transactions t where t.CustomerId = c.Id and t.[Date] >= @StartDate and t.[Data] <= @EndDate) Debits,
(select coalesce(sum(Amount), 0) from Payments p where p.CustomerId = c.Id and p.[Date] < @StartDate) xCredits,
(select coalesce(sum(Amount), 0) from Payments p where p.CustomerId = c.Id and p.[Date] >= @StartDate and p.[Date] <= @EndDate) Credits
from customers c
where c.BillingCategory in (0,1,2,3,4,5)

此查询似乎给出了我想要的结果。我使用了子查询,因为我似乎无法弄清楚如何使用JOIN来完成同样的事情。但是我有几个问题。

  1. 此查询是否在根据我的WHERE条件对每个客户进行交易之前检索交易和付款数据?如果是这样,那似乎是一大浪费。可以改善吗?

  2. 我还想添加一个GROUP BY,以按BillingCategory汇总每个付款和交易列。但是,如果将GROUP BY列限制为聚合函数(如果它们不在SELECT子句中时,如何在此处添加GROUP BY子句?

TransactionsPayments表都具有Customers表的外键。

样本数据(不是真实的)

客户:

Id    Name    BillingCategory
----- ------- ---------------
1     'ABC'   0
2     'DEF'   1
3     'GHI'   0

交易:

Id    CustomerId Date         Amount
----- ---------- ------------ ------
1     2          '2016-08-01' 124.90
2     2          '2016-08-04' 37.23
3     1          '2016-08-27' 450.02

付款:

Id    CustomerId Date         Amount
----- ---------- ------------ ------
1     1          '2016-09-01' 50.00
2     1          '2016-09-23' 75.00
3     2          '2016-09-01' 100.00

2 个答案:

答案 0 :(得分:2)

您可以在CTE中分别为Wikipedia2Vec.load()Transactions构建和,然后将它们合并在一起:

Payments

答案 1 :(得分:1)

您可以使用子查询来提高效率。每个客户仅对符合所讨论类别条件的客户进行预查询。这些子查询将始终导致每个客户最多1条记录,因此您不会获得笛卡尔结果。获取您的借方和贷方,然后以左联接重新加入您的客户主列表,以防一侧或另一侧(借方/贷方)不存在。

declare @StartDate DATE = '2016-08-01'
declare @EndDate DATE = '2016-08-31'
declare @BillingCategory INT = 0

select
        c.ID,
        c.Name,
        c.StartingBalance,
        coalesce( AllDebits.xDebits, 0 ) DebitsPrior,
        coalesce( AllDebits.Debits, 0 ) Debits
        coalesce( AllCredits.xCredits, 0 ) CreditsPrior,
        coalesce( AllCredits.Credits, 0 ) Credits
    from 
        customers c
            LEFT JOIN 
            ( select t.CustomerID,
                    sum( case when t.[Date] < @StartDate then Amount else 0 end ) xDebits,
                    sum( case when t.[Date] >= @StartDate then Amount else 0 end ) Debits
                from
                    customers c1
                        JOIN Transactions t
                            on c1.CustomerID = t.CustomerID
                where
                    c1.BillingCategory in (0,1,2,3,4,5)
                group by
                    t.CustomerID ) AllDebits
                on c.CustomerID = AllDebits.CustomerID
            LEFT JOIN 
            ( select p.CustomerID,
                    sum( case when p.[Date] < @StartDate then Amount else 0 end ) xCredits,
                    sum( case when p.[Date] >= @StartDate then Amount else 0 end ) Credits
                from
                    customers c1
                        JOIN Payments p
                            on c1.CustomerID = p.CustomerID
                where
                    c1.BillingCategory in (0,1,2,3,4,5)
                group by
                    p.CustomerID ) AllCredits
                on c.CustomerID = AllCredits.CustomerID
    where
        c.BillingCategory in (0,1,2,3,4,5)

评论添加

关于托马斯的回答,是的,他们很接近。我的版本还将联接添加到特定计费类别的客户表中,这就是原因。我不知道您的数据库大小,多少客户,多少交易。如果您要处理的确会对性能产生很大影响,那么Thomas的版本将查询每个客户和每个交易。我的版本仅根据您限制的帐单类别条件查询合格的客户。

同样,不知道数据大小,如果您要处理10万条记录,则可能没有明显的性能。如果您要处理10万名客户,那就完全不一样了。

@JonathanWood,正确,但是我的版本中每个内部子查询都包含cus