简体   繁体   English

用于计算小计和总计的 SQL 查询

[英]SQL query to calculate subtotal and grand total

I have following sample data:我有以下示例数据:

TimeSheetID RosterID    EmpID   RosterDate  StartTime   EndTime Total
       1         101    1001    2016-05-24  07:00   15:00   8
       2         101    1001    2016-05-24  16:00   21:00   5
       3         101    1002    2016-05-24  07:00   15:00   8
       4         101    1003    2016-05-24  07:00   15:00   8
       5         101    1001    2016-05-25  07:00   15:00   8
       6         101    1002    2016-05-25  07:00   15:00   8
       7         101    1002    2016-05-25  16:00   22:00   6
       8         101    1003    2016-05-25  07:00   15:00   8
       9         101    1001    2016-05-26  07:00   14:00   7
       10        101    1001    2016-05-26  15:00   21:00   6
       11        101    1002    2016-05-26  07:00   15:00   8
       12        101    1003    2016-05-26  07:00   15:00   8
       13        101    1001    2016-05-27  07:00   15:00   8
       14        101    1002    2016-05-27  07:00   15:00   8
       15        101    1003    2016-05-27  07:00   15:00   8
       16        101    1001    2016-05-28  07:00   15:00   8
       17        101    1002    2016-05-28  07:00   15:00   8
       18        101    1003    2016-05-28  07:00   15:00   8
       19        101    1001    2016-05-29  07:00   15:00   8
       20        101    1002    2016-05-29  07:00   15:00   8
       21        101    1003    2016-05-29  07:00   15:00   8
       22        102    1001    2016-05-30  07:00   15:00   8

I would like to produce:我想生产:

ID       RosterID   EmpID   RosterDate  StartTime   EndTime Total
1        101        1001    2016-05-24  07:00        15:00  8
2        101        1001    2016-05-24  16:00        21:00  5
3        101        1001    2016-05-24  Null         Null   13
4        101        1002    2016-05-24  07:00        15:00  8
5        101        1003    2016-05-24  07:00        15:00  8
6        101        1001    2016-05-25  07:00        15:00  8
7        101        1002    2016-05-25  07:00        15:00  8
8        101        1002    2016-05-25  16:00        22:00  6
9        101        1002    2016-05-25  Null         Null   14
10       101        1003    2016-05-25  07:00        15:00  8
11       101        1001    2016-05-26  07:00        14:00  7
12       101        1001    2016-05-26  15:00        21:00  6
13       101        1001    2016-05-26  Null         Null   13
14       101        1002    2016-05-26  07:00        15:00  8
15       101        1003    2016-05-26  07:00        15:00  8
16       101        1001    2016-05-27  07:00        15:00  8
17       101        1002    2016-05-27  07:00        15:00  8
18       101        1003    2016-05-27  07:00        15:00  8
19       101        1001    2016-05-28  07:00        15:00  8
20       101        1002    2016-05-28  07:00        15:00  8
21       101        1003    2016-05-28  07:00        15:00  8
22       101        1001    2016-05-29  07:00        15:00  8
23       101        1002    2016-05-29  07:00        15:00  8
24       101        1003    2016-05-29  07:00        15:00  8
25       102        1001    2016-05-30  07:00        15:00  8
26       Total      Null    Null        Null         Null   168

I would like to get the sample output using SQL Query RollUp statement because performance is issue.我想使用 SQL Query RollUp 语句获取示例输出,因为性能是问题。 As TimeSheet Table will have millions of records.由于时间表表将有数百万条记录。 Is there any other way of doing this writing procedure or function instead of views?有没有其他方法可以代替视图来执行此编写过程或函数? Thank you for your help in advance Regards Ishwor提前感谢您的帮助 Ishwor

I think you can't mix results with data in the same table.我认为您不能将结果与同一个表中的数据混合。 Also, if this is possible, I think it's not a good idea.另外,如果这是可能的,我认为这不是一个好主意。

You can get the subtotal with a query similar to this:您可以使用类似于此的查询获取小计:

select RosterID, EmpID, RosterDate, sum(Total) 
from tableRoster group by RosterID, EmpID, RosterDate;

The total is easier, you can get it with this:总数更容易,您可以通过以下方式获得:

select sum(Total) from tableRoster;

I tried to utilize your preferred method ... although there are probably some kinks to work out.我尝试使用你喜欢的方法......尽管可能有一些问题需要解决。 Apologies if it isn't working 100% as hoped for, but maybe you can take the below and modify it to your needs.如果它没有像预期的那样 100% 工作,请道歉,但也许您可以采用以下内容并根据您的需要对其进行修改。

My suspicion is that including the start/end dates in there will result in trivial sub-groupings which can be ignored.我怀疑在那里包含开始/结束日期会导致可以忽略的微不足道的子分组。 I realize not testing my solution fully is not ideal for this forum ... sorry for this ... just kind of whipped it up on a whim as a quick distraction from work.我意识到不完全测试我的解决方案对于这个论坛来说并不理想......对此感到抱歉......只是一时兴起,以分散工作的注意力。 Good luck to you.祝你好运。

SELECT 
 CASE WHEN (GROUPING(RosterID) = 1) THEN 'Total' 
      ELSE RosterID 
 END AS RosterID
,CASE WHEN (GROUPING(EmpID) = 1) AND (GROUPING(RosterID) = 1) THEN NULL 
      ELSE EmpID 
 END AS EmpID
,CASE WHEN (GROUPING(RosterDate) = 1) AND (GROUPING(RosterID) = 1) THEN NULL 
      ELSE RosterDate 
 END AS RosterDate
,CASE WHEN (GROUPING(RosterDate) = 1) THEN NULL 
      ELSE StartTime 
 END AS StartTime
,CASE WHEN (GROUPING(RosterDate) = 1) THEN NULL 
      ELSE EndTime 
 END AS EndTime
,Sum(Total) AS Total
FROM Table a
GROUP BY 
 ROLLUP(RosterID ,RosterDate ,EmpID ,StartTime ,EndTime)
ORDER BY
 RosterID, RosterDate, EmpID
I tried to resolve with basic loop as below

-- ASSUMED THAT DATA IS INSERTED INTO Roster TABLE 
-- STP_01: BY SEEING DATA COLUMNS ARE CREATED AS BELOW
CREATE TABLE Roster(TimeSheetID INT IDENTITY(1,1),RosterID INT ,EmpID INT , RosterDate DATE ,StartTime TIME, EndTime TIME, Total INT)

SET IDENTITY_INSERT Roster ON
GO

-- STP_02:INSERTING PROVIDED DATA AS BELOW
INSERT INTO Roster(TimeSheetID,RosterID,EmpID,RosterDate,StartTime,EndTime,Total)
VALUES(1 ,101,1001,'2016-05-24','07:00', '15:00', 8),
(2 ,101,1001,'2016-05-24','16:00', '21:00', 5),
(3 ,101,1002,'2016-05-24','07:00', '15:00', 8),
(4 ,101,1003,'2016-05-24','07:00', '15:00', 8),
(5 ,101,1001,'2016-05-25','07:00', '15:00', 8),
(6 ,101,1002,'2016-05-25','07:00', '15:00', 8),
(7 ,101,1002,'2016-05-25','16:00', '22:00', 6),
(8 ,101,1003,'2016-05-25','07:00', '15:00', 8),
(9 ,101,1001,'2016-05-26','07:00', '14:00', 7),
(10,101,1001,'2016-05-26','15:00', '21:00', 6),
(11,101,1002,'2016-05-26','07:00', '15:00', 8),
(12,101,1003,'2016-05-26','07:00', '15:00', 8),
(13,101,1001,'2016-05-27','07:00', '15:00', 8),
(14,101,1002,'2016-05-27','07:00', '15:00', 8),
(15,101,1003,'2016-05-27','07:00', '15:00', 8),
(16,101,1001,'2016-05-28','07:00', '15:00', 8),
(17,101,1002,'2016-05-28','07:00', '15:00', 8),
(18,101,1003,'2016-05-28','07:00', '15:00', 8),
(19,101,1001,'2016-05-29','07:00', '15:00', 8),
(20,101,1002,'2016-05-29','07:00', '15:00', 8),
(21,101,1003,'2016-05-29','07:00', '15:00', 8),
(22,102,1001,'2016-05-30','07:00', '15:00', 8)

SET IDENTITY_INSERT Roster OFF
GO

-- STP_03:CREATING Roster_1 TABLE TO INSERT PROCESSED DATA - NOT TOUCHING ORIGINAL TABLE
-- DROP TABLE Roster_1
CREATE TABLE [dbo].[Roster_1](
    [TimeSheetID] [int] NULL,
    [RosterID] [varchar](15) NULL,  -- CHANGED TO VARCHAR(15) TO PROVIDE GrpToal/GndTotal
    [EmpID] [varchar](15) NULL,     -- CHANGED TO VARCHAR(15) TO PROVIDE GrpToal/GndTotal
    [RosterDate] [date] NULL,
    [StartTime] [time](7) NULL,
    [EndTime] [time](7) NULL,
    [Total] [int] NULL
) 

-- STP_04: SOME VARIABLES TO PROCESS LOOP
DECLARE @MinRosterDate DATE,@MaxRosterDate DATE,@MinEmpId INT,@MaxEmpID INT,@kMinEmpId INT
SELECT 
        @MinRosterDate = MIN(RosterDate),   -- 2016-05-24
        @MaxRosterDate = MAX(RosterDate),   -- 2016-05-30
        @MinEmpId = MIN(EmpID),             -- 1001
        @MaxEmpID = MAX(EmpID)              -- 1003
FROM Roster

-- STP_05: RE-RUNNABLE
TRUNCATE TABLE Roster_1

SET @kMinEmpId  = @MinEmpId -- RESERVING THIS VALUE

-- STEP_06: ENTERING LOOP
WHILE (@MinRosterDate<= @MaxRosterDate)     -- OUTER LOOP
BEGIN
    WHILE(@MinEmpId <= @MaxEmpID)           -- INNER LOOP FOR ALL EMPID WORKED DURING THIS TIME FRAME
    BEGIN
        IF EXISTS(SELECT 1 FROM Roster WHERE RosterDate = @MinRosterDate AND EmpID = @MinEmpId) -- CHECKING WHETHER DATA EXISTS
        BEGIN
            INSERT INTO Roster_1    
            SELECT TimeSheetID,CONVERT(VARCHAR(7),RosterID),CONVERT(VARCHAR(7),EmpID),RosterDate,StartTime,EndTime,Total FROM Roster WHERE RosterDate = @MinRosterDate AND EmpID = @MinEmpId
            UNION
            SELECT null,'GrpTotalByEmpID',@MinEmpId,@MinRosterDate,null,null,SUM(Total)FROM Roster WHERE RosterDate = @MinRosterDate AND EmpID = @MinEmpId
        END 

        SET @MinEmpId = @MinEmpId + 1 -- BREAKING INNER LOOP
    END

    IF(@MinEmpId > @MaxEmpId)        -- RESTARING FROM FIRST EmpID
        SET @MinEmpId = @kMinEmpId

    INSERT INTO Roster_1
    SELECT null,null,'GrpTotalByDate',@MinRosterDate,null,null,SUM(Total) from Roster_1 where RosterID = 'GrpTotalByEmpID' and RosterDate = @MinRosterDate

    IF(@MinRosterDate = @MaxRosterDate)     -- CALCULATING Grand Total
    BEGIN
        INSERT INTO Roster_1
        SELECT null,'GrandTotal',null,null,null,null,SUM(Total) FROM Roster_1 WHERE TimeSheetID IS NULL AND EmpID = 'GrpTotalByDate'
    END

    SET @MinRosterDate = DATEADD(DD,1, @MinRosterDate) -- BREAKING OUTER LOOP

END

-- STP_07: READING PROCESSED DATA
SELECT * FROM Roster_1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM