关于总计的Where子句

时间:2019-03-22 14:48:22

标签: sql sql-server tsql sql-server-2014

我有此表,该表按区域和每个容器中的咖啡袋数量存储容器。

if object_id( 'dbo.Container' ) is not null
    drop table dbo.Container
go

create table dbo.Container
(
    Id   int not null,
    Region int not null,
    NumberOfCoffeePouches int not null,
    constraint pkc_Container__Id primary key clustered(Id asc)
)
go

insert into dbo.Container 
    ( Id , Region , NumberOfCoffeePouches ) 
values 
    ( 1, 1, 10 ),
    ( 2, 1, 30 ),
    ( 3, 1, 5),
    ( 4, 1, 7),
    ( 5, 1, 1),
    ( 6, 1, 3),
    ( 7, 2, 4),
    ( 8, 2, 4),
    ( 9, 2, 4)

我需要列出将用于完成50个咖啡袋订单的容器ID。过量供应是可以的。

这是我想出的问题

declare @RequiredCoffeePouches int = 50

select
        sq2.Id,
        sq2.NumberOfCoffeePouches,
        sq2.RunningTotal,
        sq2.LagRunningTotal
from
    (
        select
            sq1.Id,
            sq1.NumberOfCoffeePouches,
            sq1.RunningTotal,
            lag(sq1.RunningTotal, 1, 0) over (order by sq1.Id asc) 
                as 'LagRunningTotal'
        from
            (
                select
                    c.Id,
                    c.NumberOfCoffeePouches,
                    sum(c.NumberOfCoffeePouches) 
                        over (order by c.Id asc) as 'RunningTotal'
                from
                    dbo.Container as c
                where
                    c.Region = 1
            ) as sq1
    ) as sq2
where
    sq2.LagRunningTotal <= @RequiredCoffeePouches

它给出了预期的结果

Id          NumberOfCoffeePouches RunningTotal LagRunningTotal
----------- --------------------- ------------ ---------------
1           10                    10           0
2           30                    40           10
3           5                     45           40
4           7                     52           45

问题:

  1. 是否有更好,更优化的方法来实现这一目标?
  2. 特别是Container表是非常大的表,我认为子查询sq1会不必要地计算该区域中所有容器的RunningTotals。我想知道一旦RunnningTotal超过@RequiredCoffeePouches,是否有sq1停止处理更多行。

1 个答案:

答案 0 :(得分:-1)

两件事:

WHERE子句移到相关子选择的内部可以极大地提高查询速度,因为它会提取较少的数据。以您的示例为例:

SELECT
    sq2.Id,
    sq2.NumberOfCoffeePouches,
    sq2.RunningTotal,
    sq2.LagRunningTotal
FROM
    (
    SELECT
        sq1.Id,
        sq1.NumberOfCoffeePouches,
        sq1.RunningTotal,
        lag(sq1.RunningTotal, 1, 0) over (order by sq1.Id asc) AS 'LagRunningTotal'
    FROM
        (
         SELECT
             c.Id,
             c.NumberOfCoffeePouches,
             SUM(c.NumberOfCoffeePouches) OVER (order by c.Id asc) AS 'RunningTotal'
         FROM dbo.Container AS c
         WHERE c.Region = 1
        ) AS sq1
    WHERE sq2.LagRunningTotal <= @RequiredCoffeePouches
) AS sq2

CTE也可以提高性能:

;WITH sql1CTE AS (
    SELECT
        c.Id,
        c.NumberOfCoffeePouches,
        SUM(c.NumberOfCoffeePouches) OVER (order by c.Id asc) AS 'RunningTotal'
    FROM dbo.Container AS c
    WHERE c.Region = 1
),
sql2CTE AS (
SELECT
        Id,
        NumberOfCoffeePouches,
        RunningTotal,
        lag(RunningTotal, 1, 0) over (order by Id asc) AS 'LagRunningTotal'
FROM sql1CTE
WHERE LagRunningTotal <= @RequiredCoffeePouches
)
SELECT
    Id,
    NumberOfCoffeePouches,
    RunningTotal,
    LagRunningTotal
FROM sql2CTE

SQL Server CTE Basics

如果您使用的是SSMS,请选择“包括客户统计信息”和“包括实际执行计划”,以跟踪您在编写查询时的查询效果。