我有两张桌子,一张是工作模式,另一张是缺席。
1)工作模式
ID | Shift Start | Shift End
123| 01-03-2017 | 02-03-2017
2)缺席
ID| Absence Start | Absence End
123| 01-03-2017 | 04-03-2017
从工作模式中选择行时,排除任何在缺席表中标记为缺席的日期的最佳方法是什么?
例如,我有一份报告,它使用工作模式表来计算员工每周工作的天数,但我不希望它包含已标记为缺勤的日期。缺席表是否有意义?也不希望它包括在缺席开始和缺席结束日期之间的任何日期?
答案 0 :(得分:4)
如果{ ContentType: "image/jpeg; charset=utf-8", 'x-amz-acl': 'public-read' }
的范围始终包含要排除的班次,您可以使用absence
:
not exists()
rextester演示:http://rextester.com/DCODC76816
返回:
select *
from WorkPatterns w
where not exists (
select 1
from Absences a
where a.Id = w.Id
and a.AbsenceStart <= w.ShiftStart
and a.AbsenceEnd >= w.ShiftEnd
)
给出此测试设置:
+-----+------------+------------+
| id | ShiftStart | ShiftEnd |
+-----+------------+------------+
| 123 | 2017-02-27 | 2017-02-28 |
| 123 | 2017-03-05 | 2017-03-06 |
+-----+------------+------------+
答案 1 :(得分:1)
从工作模式中选择行时,最好的方法是什么
如果您只处理白色日期(没有时间)并控制数据库架构, 一种方法是创建日历表, 您将在公司成立以来的所有日期和未来几年的所有日期 填写该表一次。 之后很容易加入其他表格的白日期并做数学。
如果您在构建TSQL查询时遇到问题,请编辑问题,详细了解表格,关系和所需结果的列和值。
答案 2 :(得分:0)
这个怎么样:
SELECT WP_START.[id], WP_START.[shift_start], WP_START.[shift_end]
FROM work_pattern AS WP_START
INNER JOIN absences AS A ON WP_START.id = A.id
WHERE WP_START.[shift_start] NOT BETWEEN A.[absence_start] AND A.[absence_end]
UNION
SELECT WP_END.[id], WP_END.[shift_start], WP_END.[shift_end]
FROM work_pattern AS WP_END
INNER JOIN absences AS A ON WP_END.id = A.id
WHERE WP_END.[shift_end] NOT BETWEEN A.[absence_start] AND A.[absence_end]
在SQL小提琴上看到它:http://sqlfiddle.com/#!6/49ae6/6
答案 3 :(得分:0)
这是我的示例,其中包含Date Dimension表。如果您的DBA不能添加它,您可以创建#dateDim作为临时表,就像我用SQLFiddle 做的那样(我不知道我能做什么那)。典型的日期维度将包含有关日期的更多详细信息,但如果无法添加表格,只需使用您需要的内容即可。您必须填写您需要的其他假期。我经常使用的DateDim是https://github.com/shawnoden/SQL_Stuff/blob/master/sql_CreateDateDimension.sql
MS SQL Server 2014架构设置:
/* Tables for your test data. */
CREATE TABLE WorkPatterns ( id int, ShiftStart date, ShiftEnd date ) ;
INSERT INTO WorkPatterns ( id, ShiftStart, ShiftEnd )
VALUES
(123, '20170101', '20171031')
, (124, '20170601', '20170831')
;
CREATE TABLE Absences ( id int, AbsenceStart date, AbsenceEnd date ) ;
INSERT INTO Absences ( id, AbsenceStart, AbsenceEnd )
VALUES
( 123, '20170123', '20170127' )
, ( 123, '20170710', '20170831' )
, ( 124, '20170801', '20170820' )
;
/* ******** MAKE SIMPLE CALENDAR TABLE ******** */
CREATE TABLE dateDim (
theDate DATE NOT NULL
, IsWeekend BIT DEFAULT 0
, IsHoliday BIT DEFAULT 0
, IsWorkDay BIT DEFAULT 0
);
/* Populate basic details of dates. */
INSERT dateDim(theDate, IsWeekend, IsHoliday)
SELECT d
, CONVERT(BIT, CASE WHEN DATEPART(dw,d) IN (1,7) THEN 1 ELSE 0 END)
, CONVERT(BIT, CASE WHEN d = '20170704' THEN 1 ELSE 0 END) /* 4th of July. */
FROM (
SELECT d = DATEADD(DAY, rn - 1, '20170101')
FROM
(
SELECT TOP (DATEDIFF(DAY, '20170101', '20171231'))
rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
ORDER BY s1.[object_id]
) AS x
) AS y ;
/* If not a weekend or holiday, it's a WorkDay. */
UPDATE dateDim
SET IsWorkDay = CASE WHEN IsWeekend = 0 AND IsHoliday = 0 THEN 1 ELSE 0 END
;
查询计算:
SELECT wp.ID, COUNT(d.theDate) AS workDayCount
FROM WorkPatterns wp
INNER JOIN dateDim d ON d.theDate BETWEEN wp.ShiftStart AND wp.ShiftEnd
AND d.IsWorkDay = 1
LEFT OUTER JOIN Absences a ON d.theDate BETWEEN a.AbsenceStart AND a.AbsenceEnd
AND wp.ID = a.ID
WHERE a.ID IS NULL
GROUP BY wp.ID
ORDER BY wp.ID
<强> Results 强>:
| ID | workDayCount |
|-----|--------------|
| 123 | 172 | << 216 total days, 44 non-working
| 124 | 51 | << 65 total days, 14 non-working