基于多个日期范围的聚合值总和 - SQL Server

时间:2016-10-07 08:13:32

标签: sql sql-server aggregate-functions

我正在尝试根据建筑项目生命周期中的面板状态确定向电源面板添加额外负载的效果。电源面板可以承载很多负载(最多240个),并且可以根据任何给定时间的施工进度安装或卸载这些负载。面板上的负载总和在项目的生命周期内波动。仅仅因为今天的负载为90%,并不意味着你有10%可用,因为明天可以安排新的负载安装。必须始终考虑项目生命周期。

我需要一个查询,根据面板上所有负载的安装/卸载日期,确定给定日期面板的最大负载。

以下是负载及其安装/卸载日期的示例视图。

CREATE TABLE #temp(
   PanelID     INTEGER  NOT NULL 
  ,LOADID      INTEGER  NOT NULL
  ,Load        VARCHAR(7) NOT NULL
  ,kVA         NUMERIC(5,2) NOT NULL
  ,InstallDate DATE  NOT NULL
  ,DemoDate    DATE 
);
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,46706,'AUTO26',43.95,'07/07/1905','27/10/2016');
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,46706,'AUTO26',43.95,'07/07/1905','27/10/2016');
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,15539,'AUTO22',43.95,'01/01/2015',NULL);
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,20188,'OVEN101',46.47,'29/06/2017',NULL);
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,20186,'OVEN101',63.05,'29/06/2017',NULL);
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,46705,'AUTO28',61.25,'07/07/1905','27/10/2016');
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,20186,'OVEN101',63.05,'29/06/2017',NULL);
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,46705,'AUTO28',61.25,'07/07/1905','27/10/2016');
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,15539,'AUTO22',43.95,'01/01/2015',NULL);
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,20188,'OVEN101',46.47,'29/06/2017',NULL);
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,15538,'AUTO22',66.65,'01/01/2015',NULL);
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,20187,'OVEN101',50.44,'29/06/2017',NULL);
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,46704,'AUTO26',61.25,'07/07/1905','27/10/2016');
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,46707,'AUTO28',43.95,'07/07/1905','27/09/2016');
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,15538,'AUTO22',66.65,'01/01/2015',NULL);
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,20187,'OVEN101',50.44,'29/06/2017',NULL);
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,46704,'AUTO26',61.25,'07/07/1905','27/10/2016');
INSERT INTO #temp(PanelID,LOADID,Load,kVA,InstallDate,DemoDate) VALUES (1380,46707,'AUTO28',43.95,'07/07/1905','27/09/2016');

我迄今为止的解决方案是使用光标在与面板上的负载相关的每个给定日期找到面板的负载(Sum或kVA)。由于面板上最多可以有240个负载,因此会导致性能受到重大影响。

有更好的方法吗?

编辑:我按照建议简化了创建表。您只需按Panel进行分组,并将kVA列相加以检索结果。但是,我希望它基于面板上每个Load的安装日期。如果卸载日期小于安装日期,则不应出现在聚合函数中。

1 个答案:

答案 0 :(得分:1)

我假设DemoDate是从板上移除负载的日期,null表示它们不会被删除。这是一个常见的表表达式查询,它应该在持续时间内给出最大kVA:

SET DATEFORMAT dmy;

CREATE TABLE #temp(
     SourceID       INTEGER        NOT NULL
    ,PanelID        INTEGER        NOT NULL
    ,BP_DP          INTEGER        NOT NULL
    ,depth          BIT            NOT NULL
    ,LOADID         INTEGER        NOT NULL
    ,Load           VARCHAR(7)     NOT NULL
    ,kVA            NUMERIC(5,2)   NOT NULL
    ,InstallDate    DATE           NOT NULL
    ,DemoDate       DATE
);

INSERT INTO #temp
    (SourceID, PanelID, BP_DP, depth, LOADID, Load,      kVA,   InstallDate,  DemoDate    )
VALUES
    (1375,     1380,    2,     1,     46706,  'AUTO26',  43.95, '07/07/1905', '27/10/2016'),
    (1380,     1380,    2,     0,     46706,  'AUTO26',  43.95, '07/07/1905', '27/10/2016'),
    (1375,     1380,    2,     1,     15539,  'AUTO22',  43.95, '01/01/2015', NULL        ),
    (1375,     1380,    2,     1,     20188,  'OVEN101', 46.47, '29/06/2017', NULL        ),
    (1380,     1380,    2,     0,     20186,  'OVEN101', 63.05, '29/06/2017', NULL        ),
    (1380,     1380,    2,     0,     46705,  'AUTO28',  61.25, '07/07/1905', '27/10/2016'),
    (1375,     1380,    2,     1,     20186,  'OVEN101', 63.05, '29/06/2017', NULL        ),
    (1375,     1380,    2,     1,     46705,  'AUTO28',  61.25, '07/07/1905', '27/10/2016'),
    (1380,     1380,    2,     0,     15539,  'AUTO22',  43.95, '01/01/2015', NULL        ),
    (1380,     1380,    2,     0,     20188,  'OVEN101', 46.47, '29/06/2017', NULL        ),
    (1375,     1380,    2,     1,     15538,  'AUTO22',  66.65, '01/01/2015', NULL        ),
    (1375,     1380,    2,     1,     20187,  'OVEN101', 50.44, '29/06/2017', NULL        ),
    (1375,     1380,    2,     1,     46704,  'AUTO26',  61.25, '07/07/1905', '27/10/2016'),
    (1375,     1380,    2,     1,     46707,  'AUTO28',  43.95, '07/07/1905', '27/10/2016'),
    (1380,     1380,    2,     0,     15538,  'AUTO22',  66.65, '01/01/2015', NULL        ),
    (1380,     1380,    2,     0,     20187,  'OVEN101', 50.44, '29/06/2017', NULL        ),
    (1380,     1380,    2,     0,     46704,  'AUTO26',  61.25, '07/07/1905', '27/10/2016'),
    (1380,     1380,    2,     0,     46707,  'AUTO28',  43.95, '07/07/1905', '27/10/2016');   

WITH cte
AS
(
    SELECT 
        t1.PanelID,
        t1.InstallDate,
        SUM(t2.kVA) LoadAferInstall
    FROM
        (SELECT DISTINCT
            PanelID,
            InstallDate
        FROM
            #Temp
        ) t1
        JOIN #Temp t2
            ON t1.PanelID = t2.PanelID
            AND t2.InstallDate <= t1.InstallDate
            AND (t2.DemoDate IS NULL OR t2.DemoDate >= t1.InstallDate)
    GROUP BY
        t1.PanelID, t1.InstallDate
)
SELECT
    PanelID,
    MAX(LoadAferInstall) MaxPanelLoad_kVA
FROM
    cte
GROUP BY
    PanelID
;

DROP TABLE #temp