在SQL表中查找日期间隔(缺少日期范围)

时间:2014-12-18 18:57:04

标签: sql-server tsql

在这个SQL Server 2008数据库上,我有一张出勤表,学生每天都会上学并办理登机手续,表格看起来像这样:

SchoolID | StudentID | Date 

每张桌子上的每个学生都会有一个记录。我想知道的是,考虑到开始日期,结束日期和天数(差距),找到那些未在该天数内进入学校的学生。例如,我需要知道12月份哪些学生连续3天错过,并吐出学生ID列表。

我怎样才能完成这样的事情?

2 个答案:

答案 0 :(得分:0)

您可以生成从startdateenddate的日期范围 然后外部将这些数据与您的表联系起来,如果学生不会将其视为1则汇总这些数据。

生成日期范围,您可以使用此功能,如下所示

CREATE FUNCTION [dbo].[DateRange]
(     
      @Increment              CHAR(1),
      @StartDate              DATETIME,
      @EndDate                DATETIME
)
RETURNS  
@SelectedRange    TABLE 
(IndividualDate DATETIME)
AS 
BEGIN
      ;WITH cteRange (DateRange) AS (
            SELECT @StartDate
            UNION ALL
            SELECT 
                  CASE
                        WHEN @Increment = 'd' THEN DATEADD(dd, 1, DateRange)
                        WHEN @Increment = 'w' THEN DATEADD(ww, 1, DateRange)
                        WHEN @Increment = 'm' THEN DATEADD(mm, 1, DateRange)
                  END
            FROM cteRange
            WHERE DateRange <= 
                  CASE
                        WHEN @Increment = 'd' THEN DATEADD(dd, -1, @EndDate)
                        WHEN @Increment = 'w' THEN DATEADD(ww, -1, @EndDate)
                        WHEN @Increment = 'm' THEN DATEADD(mm, -1, @EndDate)
                  END)

      INSERT INTO @SelectedRange (IndividualDate)
      SELECT DateRange
      FROM cteRange
      OPTION (MAXRECURSION 3660);
      RETURN
END
GO 

然后

    select sum(isAbsent) absentDays, s.studentid from
    (
    select case when studentid is null then 1 else 0 end isAbsent,individualDate,s.studentid from DateRange('d', '01/11/2014', '30/11/2014') d
cross join tblstudent s
    left outer join yourtable on yourtable.Date = d.IndividualDate and yourtable.studentid = s.studentid 
    ) x
    group by s.studentid
    having sum(isAbsent) > 3

答案 1 :(得分:0)

看看这个。我想你将能够从中找到答案。这个解决方案可以解决周末和假期:

SQL Fiddle

MS SQL Server 2008架构设置

CREATE TABLE attendance
    ([SchoolID] int, [StudentID] int, [Date] datetime)
;

INSERT INTO attendance
    ([SchoolID], [StudentID], [Date])
VALUES
    (1, 1, '2014-12-01 00:00:00'),
    (1, 1, '2014-12-02 00:00:00'),
    (1, 1, '2014-12-03 00:00:00'),
    (1, 1, '2014-12-04 00:00:00'),
    (1, 1, '2014-12-05 00:00:00'),
    (1, 1, '2014-12-08 00:00:00'),
    (1, 1, '2014-12-09 00:00:00'),
    (1, 1, '2014-12-10 00:00:00'),
    (1, 1, '2014-12-11 00:00:00'),
    (1, 1, '2014-12-12 00:00:00'),
    (1, 1, '2014-12-15 00:00:00'),
    (1, 1, '2014-12-16 00:00:00'),
    (1, 1, '2014-12-17 00:00:00'),
    (1, 1, '2014-12-18 00:00:00'),
    (1, 1, '2014-12-19 00:00:00'),
    (1, 2, '2014-12-01 00:00:00'),
    (1, 2, '2014-12-02 00:00:00'),
    (1, 2, '2014-12-08 00:00:00'),
    (1, 2, '2014-12-09 00:00:00'),
    (1, 2, '2014-12-10 00:00:00'),
    (1, 2, '2014-12-11 00:00:00'),
    (1, 2, '2014-12-12 00:00:00'),
    (1, 2, '2014-12-15 00:00:00'),
    (1, 2, '2014-12-16 00:00:00'),
    (1, 2, '2014-12-17 00:00:00'),
    (1, 2, '2014-12-18 00:00:00'),
    (1, 2, '2014-12-19 00:00:00')
;

CREATE TABLE holidays
    ([Date] datetime)
;

INSERT INTO holidays
    ([Date])
VALUES
    ('2014-12-22 00:00:00'),
    ('2014-12-23 00:00:00'),
    ('2014-12-24 00:00:00'),
    ('2014-12-25 00:00:00'),
    ('2014-12-26 00:00:00'),
    ('2014-12-29 00:00:00'),
    ('2014-12-30 00:00:00'),
    ('2014-12-31 00:00:00')
;


CREATE TABLE students
    ([StudentID] int, [Name] varchar(5))
;

INSERT INTO students
    ([StudentID], [Name])
VALUES
    (1, 'John'),
    (2, 'Peter')
;

查询1

DECLARE @start DATE, @end DATE
SELECT @start = '20141201', @end = '20141231'

;WITH tdate AS 
(
  SELECT TOP (DATEDIFF(DAY, @start, @end) + 1) 
    n = ROW_NUMBER() OVER (ORDER BY [object_id])
  FROM sys.all_objects
)

SELECT DISTINCT Name
FROM students s 
INNER JOIN attendance a ON s.StudentID = a.StudentID
INNER JOIN tdate ON DATEADD(DAY, n-1, @start) = a.Date
GROUP BY NAME
HAVING 
(SELECT count(*)
FROM tdate
LEFT OUTER JOIN holidays h ON DATEADD(DAY, n-1, @start) = h.Date
WHERE h.date is null
AND DATEPART(dw,DATEADD(DAY, n-1, @start)) not in (1,7))
- COUNT(*) >= 3

<强> Results

|  NAME |
|-------|
| Peter |

<强>更新

SELECT s.StudentID, d.Date
FROM students s
INNER JOIN (
SELECT DATEADD(DAY, n-1, @start) as Date
FROM tdate
LEFT OUTER JOIN holidays h ON DATEADD(DAY, n-1, @start) = h.Date
WHERE h.date is null
AND DATEPART(dw,DATEADD(DAY, n-1, @start)) not in (1,7)) d ON 1 = 1
LEFT OUTER JOIN attendance a ON s.StudentID = a.StudentID AND d.Date = a.Date
WHERE a.StudentID IS NULL
ORDER BY s.StudentID, d.Date

<强> Results

| STUDENTID |       DATE |
|-----------|------------|
|         2 | 2014-12-03 |
|         2 | 2014-12-04 |
|         2 | 2014-12-05 |