我正在寻找关于我应该对查询采取的方法的一些建议。我有一张桌子(EMP),用于存储今年的员工详细信息和工作时间(每周40小时)。另外两个表存储员工所属的主要和二级办公室。由于员工可以在办公室之间移动,因此会存储日期。
我希望在员工在办公室期间返回工作时数。如果主要办公室与雇员的二级办公室重叠,则应按重叠期间的重叠办公室数量分配小时数。
我在下面附上样本DDL。
-- Employee Table with hours for year 2014
CREATE TABLE [dbo].[EMP](
[EMP_ID] [int] NOT NULL,
[EMP_NAME] [varchar](255) NULL,
[EMP_FYHOURS] [float] NULL,
CONSTRAINT [PK_EMP] PRIMARY KEY CLUSTERED
(
[EMP_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]
) ON [PRIMARY]
GO
-- Employees and their primary offices
CREATE TABLE [dbo].[OFFICEPRIMARY](
[OFFICEPRIMARY_ID] [int] NOT NULL,
[OFFICEPRIMARY_NAME] [varchar](255) NULL,
[OFFICEPRIMARY_EMP_ID] [int] NOT NULL,
[OFFICEPRIMARY_START] [datetime] NULL,
[OFFICEPRIMARY_END] [datetime] NULL,
CONSTRAINT [PK_OFFICEPRIMARY] PRIMARY KEY CLUSTERED
(
[OFFICEPRIMARY_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[OFFICEPRIMARY] WITH CHECK ADD CONSTRAINT [FK_OFFICEPRIMARY_FK1] FOREIGN KEY([OFFICEPRIMARY_EMP_ID])
REFERENCES [dbo].[EMP] ([EMP_ID])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[OFFICEPRIMARY] CHECK CONSTRAINT [FK_OFFICEPRIMARY_FK1]
GO
-- Employees and their secondary offices
CREATE TABLE [dbo].[OFFICESECONDARY](
[OFFICESECONDARY_ID] [int] NOT NULL,
[OFFICESECONDARY_NAME] [varchar](255) NULL,
[OFFICESECONDARY_EMP_ID] [int] NOT NULL,
[OFFICESECONDARY_START] [datetime] NULL,
[OFFICESECONDARY_END] [datetime] NULL,
CONSTRAINT [PK_OFFICESECONDARY] PRIMARY KEY CLUSTERED
(
[OFFICESECONDARY_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[OFFICESECONDARY] WITH CHECK ADD CONSTRAINT [FK_OFFICESECONDARY_FK1] FOREIGN KEY([OFFICESECONDARY_EMP_ID])
REFERENCES [dbo].[EMP] ([EMP_ID])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[OFFICESECONDARY] CHECK CONSTRAINT [FK_OFFICESECONDARY_FK1]
GO
-- Insert sample data
INSERT INTO EMP (EMP_ID, EMP_NAME, EMP_FYHOURS)
VALUES (1, 'John Smith', 2080);
INSERT INTO EMP (EMP_ID, EMP_NAME, EMP_FYHOURS)
VALUES (2, 'Jane Doe', 2080);
GO
INSERT INTO OFFICEPRIMARY (OFFICEPRIMARY_ID, OFFICEPRIMARY_NAME, OFFICEPRIMARY_EMP_ID, OFFICEPRIMARY_START, OFFICEPRIMARY_END)
VALUES (1, 'London', 1, '2014-01-01', '2014-05-31')
INSERT INTO OFFICEPRIMARY (OFFICEPRIMARY_ID, OFFICEPRIMARY_NAME, OFFICEPRIMARY_EMP_ID, OFFICEPRIMARY_START, OFFICEPRIMARY_END)
VALUES (2, 'Berlin', 1, '2014-06-01', '2014-08-31')
INSERT INTO OFFICEPRIMARY (OFFICEPRIMARY_ID, OFFICEPRIMARY_NAME, OFFICEPRIMARY_EMP_ID, OFFICEPRIMARY_START, OFFICEPRIMARY_END)
VALUES (3, 'New York', 1, '2014-09-01', '2014-12-31')
INSERT INTO OFFICEPRIMARY (OFFICEPRIMARY_ID, OFFICEPRIMARY_NAME, OFFICEPRIMARY_EMP_ID, OFFICEPRIMARY_START, OFFICEPRIMARY_END)
VALUES (4, 'New York', 2, '2014-01-01', '2014-04-15')
INSERT INTO OFFICEPRIMARY (OFFICEPRIMARY_ID, OFFICEPRIMARY_NAME, OFFICEPRIMARY_EMP_ID, OFFICEPRIMARY_START, OFFICEPRIMARY_END)
VALUES (5, 'Paris', 2, '2014-04-16', '2014-09-30')
INSERT INTO OFFICEPRIMARY (OFFICEPRIMARY_ID, OFFICEPRIMARY_NAME, OFFICEPRIMARY_EMP_ID, OFFICEPRIMARY_START, OFFICEPRIMARY_END)
VALUES (6, 'London', 2, '2014-10-01', '2014-12-31')
GO
INSERT INTO OFFICESECONDARY (OFFICESECONDARY_ID, OFFICESECONDARY_NAME, OFFICESECONDARY_EMP_ID, OFFICESECONDARY_START, OFFICESECONDARY_END)
VALUES (1, 'Paris', 1, '2014-01-01', '2014-03-31')
INSERT INTO OFFICESECONDARY (OFFICESECONDARY_ID, OFFICESECONDARY_NAME, OFFICESECONDARY_EMP_ID, OFFICESECONDARY_START, OFFICESECONDARY_END)
VALUES (2, 'Lyon', 1, '2014-04-01', '2014-05-15')
INSERT INTO OFFICESECONDARY (OFFICESECONDARY_ID, OFFICESECONDARY_NAME, OFFICESECONDARY_EMP_ID, OFFICESECONDARY_START, OFFICESECONDARY_END)
VALUES (3, 'Berlin', 1, '2014-05-16', '2014-09-30')
INSERT INTO OFFICESECONDARY (OFFICESECONDARY_ID, OFFICESECONDARY_NAME, OFFICESECONDARY_EMP_ID, OFFICESECONDARY_START, OFFICESECONDARY_END)
VALUES (4, 'Chicago', 1, '2014-10-01', '2015-02-22')
INSERT INTO OFFICESECONDARY (OFFICESECONDARY_ID, OFFICESECONDARY_NAME, OFFICESECONDARY_EMP_ID, OFFICESECONDARY_START, OFFICESECONDARY_END)
VALUES (5, 'Chicago', 2, '2013-11-21', '2014-04-10')
INSERT INTO OFFICESECONDARY (OFFICESECONDARY_ID, OFFICESECONDARY_NAME, OFFICESECONDARY_EMP_ID, OFFICESECONDARY_START, OFFICESECONDARY_END)
VALUES (6, 'Berlin', 2, '2014-04-11', '2014-09-16')
INSERT INTO OFFICESECONDARY (OFFICESECONDARY_ID, OFFICESECONDARY_NAME, OFFICESECONDARY_EMP_ID, OFFICESECONDARY_START, OFFICESECONDARY_END)
VALUES (7, 'Amsterdam', 2, '2014-09-17', '2015-03-31')
GO
感谢指针。我调整了您的查询,因此它提供了主要和次要办公室的联合。
剩下的就是计算办公室之间重叠时间的时间。例如,
John Smith,纽约,2014年4月1日,2014年8月10日
约翰史密斯,伦敦,2014年8月1日,2014年12月31日
对于2014年8月1日至2014年8月10日办公室之间的重叠期,我希望将时间平均分配。如果有3个重叠的办公室,那么它将被分成3路。
select 'Primary' as Office, e.EMP_NAME, op.OFFICEPRIMARY_NAME, op.OFFICEPRIMARY_START, op.OFFICEPRIMARY_END, datediff(wk,OFFICEPRIMARY_START,OFFICEPRIMARY_END) * 40 as HoursWorkedPrimary
from EMP e
inner join OFFICEPRIMARY op on op.OFFICEPRIMARY_EMP_ID = e.EMP_ID
union all
select 'Secondary' as Office, e.EMP_NAME, os.OFFICESECONDARY_NAME, os.OFFICESECONDARY_START, os.OFFICESECONDARY_END, datediff(wk,OFFICESECONDARY_START,OFFICESECONDARY_END) * 40 as HoursWorkedSecondary
from EMP e
inner join OFFICESECONDARY os on os.OFFICESECONDARY_EMP_ID = e.EMP_ID
order by e.EMP_NAME
答案 0 :(得分:0)
这应该让你有个先机:
select datediff(wk,OFFICEPRIMARY_START,OFFICEPRIMARY_END) * 40 as HoursWorkedPrimary
,datediff(wk,OFFICESECONDARY_START,OFFICESECONDARY_END) * 40 as HoursWorkedSecondary
,EMP_NAME
,OFFICEPRIMARY_NAME,OFFICEPRIMARY_START,OFFICEPRIMARY_END
,OFFICESECONDARY_NAME,OFFICESECONDARY_START,OFFICESECONDARY_END
from [EMP]
inner join OFFICEPRIMARY as op on op.OFFICEPRIMARY_EMP_ID = EMP.EMP_ID
inner join OFFICESECONDARY as os on os.OFFICESECONDARY_EMP_ID = EMP.EMP_ID
答案 1 :(得分:0)
以下链接可帮助您找到确定日期重叠方向的正确方向。
Count days in date range with set of exclusions which may overlap
答案 2 :(得分:0)
如果我理解正确,您希望看到的最终结果是每位员工和办公室的总工作小时数?
我想出了这个:
-- generate date table
declare @MinDate datetime, @MaxDate datetime
SET @MinDate = (SELECT MIN(d) FROM (SELECT d = OFFICEPRIMARY_START FROM dbo.OFFICEPRIMARY UNION SELECT OFFICESECONDARY_START FROM dbo.OFFICESECONDARY) a)
SET @MaxDate = (SELECT MAX(d) FROM (SELECT d = OFFICEPRIMARY_END FROM dbo.OFFICEPRIMARY UNION SELECT OFFICESECONDARY_END FROM dbo.OFFICESECONDARY) a)
SELECT
d = DATEADD(day, number, @MinDate)
INTO
#tmp_dates
FROM
(SELECT DISTINCT number FROM master.dbo.spt_values WHERE name IS NULL) n
WHERE
DATEADD(day, number, @MinDate) < @MaxDate
;WITH CTE AS
(
SELECT
d.d
,o.OfficeType
,o.OfficeID
,o.OfficeName
,o.EmpID
,EmpName = e.EMP_NAME
,HoursWorked = 8 / (COUNT(1) OVER (PARTITION BY EmpID, d))
FROM
(
SELECT
OfficeType = 1
,OfficeID = op.OFFICEPRIMARY_ID
,OfficeName = op.OFFICEPRIMARY_NAME
,EmpID = op.OFFICEPRIMARY_EMP_ID
,StartDate = op.OFFICEPRIMARY_START
,EndDate = op.OFFICEPRIMARY_END
FROM
dbo.OFFICEPRIMARY op
UNION
SELECT
OfficeType = 2
,OfficeID = os.OFFICESECONDARY_ID
,OfficeName = os.OFFICESECONDARY_NAME
,EmpID = os.OFFICESECONDARY_EMP_ID
,StartDate = os.OFFICESECONDARY_START
,EndDate = os.OFFICESECONDARY_END
FROM
dbo.OFFICESECONDARY os
) o
INNER JOIN
dbo.EMP e ON e.EMP_ID = o.EmpID
INNER JOIN
#tmp_dates d ON o.StartDate<=d.d AND o.EndDate>=d.d
)
SELECT
EmpID
,EmpName
,OfficeType
,OfficeName
,TotalHoursWorked = SUM(HoursWorked)
FROM
CTE
GROUP BY
EmpID
,EmpName
,OfficeType
,OfficeID
,OfficeName
ORDER BY
EmpID
,OfficeName
我首先生成一个临时表,其中包含最小日期和最大日期之间的日期。
然后我联合两个办公桌(为什么你还有两张桌子?)我得到一份CTE,它返回员工,日期,办公室和办公室工作小时数据(8除以员工所在的办公室数量)在这一天工作。)
然后我将这些数据相加得到按员工和办公室分组的小时数。
也许有一个更简单的解决方案。这是我想到的第一个解决方案。