动态生成列的总和

时间:2018-02-15 13:56:20

标签: sql sql-server

我每月都会有学生上学。

CREATE PROCEDURE GET_ATTENDANCE_REPORT_FOR_FACULTY
@startdate DATE,  
@enddate DATE,
@collegecode nvarchar(10),
@coursecode nvarchar(10),
@subjectcode nvarchar(10)

AS BEGIN

DECLARE @query as varchar(MAX);

with cte (startdate) as 
(
    select @startdate startdate
    union all 
    select dateadd(DD, 1, startdate) 
    from cte
    where startdate < @enddate
)

select @query = coalesce(@query, '') + 
              N',coalesce(MAX(CASE when A.[Date] = ''' + 
              cast(cte.startdate as nvarchar(20)) + 
              N''' THEN Convert(varchar(10),A.[Attendance]) end), ''-'') ' + 
              quotename(convert(char(2), cte.startdate,104))
from cte
where datename(weekday, cte.startdate) <> 'Sunday';

set @query = 'Select S.RollNo AS [Roll No],Concat(FirstName,'' '',LastName) Name' + @query + ',Concat(sum(Attendance),''/'',count(Attendance)) Total
              from Attendance A, Student S, UserDetails U
              where A.EnrollmentNo=S.EnrollmentNo and S.EnrollmentNo=U.userID and S.CollegeCode=''' + @collegecode + ''' and A.CourseCode=''' + @coursecode + ''' and A.SubjectCode =''' + @subjectcode +''' 
              and A.Date between ''' + Convert(nvarchar,@startdate) + ''' and ''' + Convert(nvarchar,@enddate) + '''
              Group By S.RollNo,U.FirstName,U.LastName';


Execute (@query)
END

这样可以生成出席日期的记录,但可以有多个同一日期的记录。

在这种情况下,应该显示该特定日期的出勤总和。

那么,我应该在@query中改变什么以达到预期的结果呢?

示例数据:

CREATE TABLE #Attendance (EnrollmentNo varchar(50),
                          SubjectCode varchar(10),
                          [Date] datetime,
                          Attendance numeric(1,0),
                          CourseCode varchar(10),
                          FacultyId varchar(50));

INSERT INTO #Attendance
VALUES ('DDU-320/12','CSHT101','20180201',0,'BSCCS','Fac101'),
       ('DDU-320/12','CSHT101','20180201',1,'BSCCS','Fac101'),
       ('DDU-320/12','CSHT101','20180201',1,'BSCCS','Fac101'),
       ('DDU-320/12','CSHT101','20180202',1,'BSCCS','Fac101'),
       ('DDU-320/12','CSHT101','20180202',2,'BSCCS','Fac101'),
       ('DDU-320/12','CSHT101','20180202',0,'BSCCS','Fac101');

CREATE TABLE #Student (EnrollmentNo varchar(50),
                       RollNo numeric(3,0),
                       CollegeCode varchar(10),
                       CourseCode varchar(10),
                       [year] int);
INSERT INTO #Student
VALUES ('DDU-320/12',38,'DDUC','BSCCS',2012);

CREATE TABLE #UserDetail (userID varchar(50),
                          Firstname varchar(50),
                          LastName varchar(50),
                          Gender varchar (6),
                          [Address] varchar(500),
                          Phone varchar(10));
INSERT INTO #UserDetail
VALUES ('DDU-320/12','Suyash','Gupta','Male','Lucknow',9817271);
GO

期望输出:

+---------+--------------+----+----+-------+
| Roll No |     Name     | 01 | 02 | Total |
+---------+--------------+----+----+-------+
|      38 | Suyash Gupta |  2 |  3 |     5 |
+---------+--------------+----+----+-------+

3 个答案:

答案 0 :(得分:2)

使用您的示例数据(在更正之前),这将为您提供所需的答案,但仍需要适应动态工作:

WITH x AS (
SELECT
    s.RollNo,
    u.LastName + ' ' + u.Firstname AS [Name],
    DATEPART(DAY, a.[Date]) AS [day],
    SUM(a.Attendance) AS Attendance
FROM
    #Student s
    INNER JOIN #UserDetail u ON u.EnrollmentNo = s.EnrollmentNo
    INNER JOIN #Attendance a ON a.EnrollmentNo = s.EnrollmentNo
GROUP BY
    s.RollNo,
    u.LastName + ' ' + u.Firstname,
    DATEPART(DAY, a.[Date]))
SELECT 
    *,
    (SELECT SUM(Attendance) FROM x WHERE x.RollNo = p.RollNo) AS total
FROM 
    x 
    PIVOT (SUM(Attendance) FOR [Day] IN ([1], [2])) p;

结果:

RollNo  Name            1   2   total
38      Gupta Suyash    2   3   5

答案 1 :(得分:1)

这是编译代码时最终结果的样子:

  

我将测试数据从UserDetails更改为UserDetail。然后代替s.EnrollmentNo = u.UserId我写的s.EnrollmentNo = u.EnrollmentID

     

此外,我使用了连接而不是where子句

     

我也没有对你的总数做任何事情,因为很明显你只需要删除你的计数和斜线/

SELECT S.RollNo AS [Roll No]
    ,CONCAT (
        FirstName
        ,' '
        ,LastName
        ) NAME
    ,coalesce(sum(CASE 
                WHEN A.[Date] = '2018-02-01'
                    THEN A.[Attendance]
                END), 0) [01]
    ,coalesce(SUM(CASE 
                WHEN A.[Date] = '2018-02-02'
                    THEN  A.[Attendance]
                END), 0) [02]

    ,CONCAT (
        sum(Attendance)
        ,'/'
        ,count(Attendance)
        ) Total
FROM Attendance A
    inner join Student S on A.EnrollmentNo = S.EnrollmentNo
    inner join UserDetail U on S.EnrollmentNo = U.EnrollmentNo
WHERE
     S.CollegeCode = 'DDUC'
    AND A.CourseCode = 'BSCCS'
    AND A.SubjectCode = 'CSHT101'
    AND A.DATE BETWEEN '2018-02-01'
        AND '2018-02-02'
GROUP BY S.RollNo
    ,U.FirstName
    ,U.LastName

所以你SP希望这个

 CREATE PROCEDURE GET_ATTENDANCE_REPORT_FOR_FACULTY
@startdate DATE,  
@enddate DATE,
@collegecode nvarchar(10),
@coursecode nvarchar(10),
@subjectcode nvarchar(10)

AS BEGIN

DECLARE @query as varchar(MAX);



  with cte (startdate) as  (
    select @startdate startdate
    union all 
    select dateadd(DD, 1, startdate) 
    from cte
    where startdate < @enddate )

select @query = coalesce(@query, '') + 
              N',coalesce(sum(CASE when A.[Date] = ''' + 
              cast(cte.startdate as nvarchar(20)) + 
              N''' THEN A.[Attendance] end), 0) ' + 
              quotename(convert(char(2), cte.startdate,104)) from cte where datename(weekday, cte.startdate) <> 'Sunday';



set @query = 'Select S.RollNo AS [Roll No],Concat(FirstName,'' '',LastName) Name' + @query + ',Concat(sum(Attendance),''/'',count(Attendance)) Total
              from Attendance A inner join Student S on A.EnrollmentNo = S.EnrollmentNo
        inner join UserDetail U on S.EnrollmentNo = U.EnrollmentNo
              where S.CollegeCode=''' + @collegecode + ''' and A.CourseCode=''' + @coursecode + ''' and A.SubjectCode =''' + @subjectcode +''' 
              and A.Date between ''' + Convert(nvarchar,@startdate) + ''' and ''' + Convert(nvarchar,@enddate) + '''
              Group By S.RollNo,U.FirstName,U.LastName';

PRINT @query Execute (@query)

8天的结果只是为了显示不平等时发生的事情

enter image description here

答案 2 :(得分:1)

Richard Hansell的回复外, 我使用动态数据透视表来包含提供给存储过程的日期的所有日期,并且我使用分组集来总计总数

这是查询:

        /*Creating the sample data*/
                    IF OBJECT_ID ('tempdb..#Attendance') IS NOT NULL DROP TABLE #Attendance
        IF OBJECT_ID ('tempdb..#Student') IS NOT NULL DROP TABLE #Student
        IF OBJECT_ID ('tempdb..#UserDetail') IS NOT NULL DROP TABLE #UserDetail

        CREATE TABLE #Attendance (EnrollmentNo varchar(50),
                                  SubjectCode varchar(10),
                                  [Date] datetime,
                                  Attendance numeric(1,0),
                                  CourseCode varchar(10),
                                  FacultyId varchar(50));

        INSERT INTO #Attendance
        VALUES ('DDU-320/12','CSHT101','20180201',0,'BSCCS','Fac101'),
               ('DDU-320/12','CSHT101','20180201',1,'BSCCS','Fac101'),
               ('DDU-320/12','CSHT101','20180201',1,'BSCCS','Fac101'),
               ('DDU-320/12','CSHT101','20180202',1,'BSCCS','Fac101'),
               ('DDU-320/12','CSHT101','20180202',2,'BSCCS','Fac101'),
               ('DDU-322/12','CSHT100','20180202',2,'BSCCO','Fac101'),
               ('DDU-320/12','CSHT101','20180202',0,'BSCCS','Fac101');

        CREATE TABLE #Student (EnrollmentNo varchar(50),
                               RollNo numeric(3,0),
                               CollegeCode varchar(10),
                               CourseCode varchar(10),
                               [year] int);
        INSERT INTO #Student
        VALUES ('DDU-320/12',38,'DDUC','BSCCS',2012),
               ('DDU-322/12',39,'DDUC','BSCCO',2012);

        CREATE TABLE #UserDetail (userID varchar(50),
                                  Firstname varchar(50),
                                  LastName varchar(50),
                                  Gender varchar (6),
                                  [Address] varchar(500),
                                  Phone varchar(10));
        INSERT INTO #UserDetail
        VALUES ('DDU-320/12','Suyash','Gupta','Male','Lucknow',9817271),
               ('DDU-322/12','Gupta','Suyash','Male','Lucknow',9817279);
        GO

        SET NOCOUNT ON 
        IF OBJECT_ID ('tempdb..#T') IS NOT NULL DROP TABLE #T
        /*These are the Parameters for you stored procedure*/
        DECLARE @startdate DATE ='2018-02-01 00:00:00.000'  
        DECLARE @enddate DATE= '2018-02-02 00:00:00.000'
        DECLARE @collegecode nvarchar(10)= 'DDUC'
        DECLARE @coursecode nvarchar(10) = 'BSCCS'
        DECLARE @subjectcode nvarchar(10) ='CSHT101'

        ;
        with cte (startdate) as 
        (
            select @startdate startdate
            union all 
            select dateadd(DD, 1, startdate) 
            from cte
            where startdate < @enddate
        )

        SELECT startdate ,  CAST(RIGHT('0'+CONVERT(VARCHAR(3),DATEPART(DAY,[startdate])),2) AS VARCHAR(20)) startdate_Day
        INTO #T
        FROM cte

        DECLARE @Cols NVARCHAR(MAX) = ''

        SELECT @Cols += ',' + QUOTENAME(startdate_Day)
        FROM #T
        GROUP BY startdate_Day

        SET @Cols= STUFF(@Cols, 1,1,'') + ',[Total]'

        DECLARE @Pvt NVARCHAR(MAX)=
        '
        ;WITH Aggr as 
        (
        SELECT  s.RollNo , d.Firstname + '' '' + d.LastName [Name] , a.[Date],  T.startdate_Day,
        SUM(Attendance) Attendance
        FROM #T T
        LEFT JOIN #Attendance A 
        ON T.startdate = A.[Date]
        JOIN #Student S 
        ON A.EnrollmentNo = S.EnrollmentNo
        JOIN #UserDetail D
        ON S.EnrollmentNo = D.userID
        GROUP BY GROUPING SETS  (
                        (s.RollNo ,d.Firstname + '' '' + d.LastName , a.[Date] ,T.startdate_Day ) , (s.RollNo , d.Firstname + '' '' + d.LastName ))

        )
        SELECT RollNo , [Name] , '+@Cols+'
        FROM 
        (
        SELECT RollNo, [Name]  ,  ISNULL(startdate_Day,''Total'') startdate_Day , Attendance
         FROM Aggr
         ) Main 
         PIVOT
            (
            MAX(Attendance) FOR startdate_Day IN ('+@Cols+')
            ) P
        '
        EXEC sp_executesql @Pvt