使用SQL Server并且不确定是否空白或尝试做我以前从未做过的事情!
为了简化,我正在为排班做一个Select查询。我有2张桌子:
[dbo].[LeaveBalances]
[PrimaryKey] [Employee] [LeaveType] [AsAtDate] [Balance]
1 100000 ANN 2017-10-23 10
2 100000 SIC 2017-10-23 16
[dbo].[P_R]
[PrimaryKey] [Employee] [ShiftDate] [LeaveType] [Hrs]
1 100000 2017-10-21 ANN 5
2 100000 2017-10-24 ANN 2
3 100000 2017-10-25 SIC 7
4 123456 2017-10-25 ANN 8
我希望查询获得休假余额的结果,除了[AsAtDate]之后的任何内容,是:
[Employee] [LeaveType] [AsAtDate] [Balance]
100000 ANN 2017-10-23 8
100000 SIC 2017-10-23 9
所以2017-10-21休假将被忽略,因为它在日期之前,并且员工123456休假将被忽略,因为它是一个不同的雇员,但其他两个将从相应的休假类型余额中减去。 我到目前为止的查询是:
SELECT [Employee]
,[LeaveType]
,[AsAtDate]
,[Balance] -
(SELECT SUM([Hrs]) FROM [dbo].[P_R] WHERE [Employee] = 100000)
AS [Balance]
FROM [dbo].[LeaveBalances]
WHERE [Employee] = 100000
但显然,无论[P_R]离开类型或日期如何,都会从每个休假类型中减去员工100000的所有[Hrs]值。我如何融入其他条件?
答案 0 :(得分:1)
基本上您要选择LeaveBalances
的所有P_R
条记录和总和小时数。您可以在SELECT
子句中的子查询中执行此操作:
select
employee,
leavetype,
asatdate,
balance - (select sum(hrs) from dbo.p_r p where p.employee = b.employee
and p.leavetype = b.leavetype
and p.shiftdate > b.asatdate
) as balance
from dbo.leavebalances b
order by employee, leavetype;
或者使用FROM
将子查询移动到OUTER APPLY
子句:
select
employee,
leavetype,
asatdate,
balance - coalesce(sums.total, 0) as balance
from leavebalances b
outer apply
(
select sum(hrs) as total
from p_r p
where p.employee = b.employee
and p.leavetype = b.leavetype
and p.shiftdate > b.asatdate
) sums
order by employee, leavetype;
答案 1 :(得分:0)
我设法解决了以下问题。在下面的CTE中,我汇总了每个员工在AsAtDate
表中指定的LeaveBalances
之后花费的病假天数。请注意,我必须在LeaveBalances
上做一个明确的选择,以隔离每个员工的截止日期,这意味着您的数据未正常化。
WITH cte AS (
SELECT t1.[Employee], t1.[LeaveType], SUM(t1.[Hrs]) AS [Hrs]
FROM [dbo].[P_R] t1
INNER JOIN
(
SELECT DISTINCT [Employee], [AsAtDate]
FROM [dbo].[LeaveBalances]
) t2
ON t1.[Employee] = t2.[Employee]
WHERE t1.[ShiftDate] > t2.[AsAtDate]
GROUP BY t1.[Employee], t1.[LeaveType]
)
SELECT
t1.[Employee], t1.[LeaveType], t1.[AsAtDate],
t1.[Balance] - COALESCE(t2.[Hrs], 0) AS [Balance]
FROM [dbo].[LeaveBalances] t1
LEFT JOIN cte t2
ON t1.[Employee] = t2.[Employee] AND
t1.[LeaveType] = t2.[LeaveType];
<强>输出:强>
在这里演示:
答案 2 :(得分:0)
This Can be achive by Using CTE
BEGIN TRAN
CREATE TABLE [dbo].[LeaveBalances]([ID] INT, [Employee] NVARCHAR(255), [LeaveType] NVARCHAR(6) , [AsAtDate] DATETIME, [Balance] INT)
CREATE TABLE[dbo].[P_R](ID INT,[Employee]NVARCHAR(255), [ShiftDate] DATETIME, [LeaveType] NVARCHAR(6) , [Hrs] INT)
INSERT INTO LeaveBalances
SELECT 1,'100000','ANN','2017-10-23',10 UNION ALL
SELECT 2,'100000','SIC','2017-10-23',16
INSERT INTO P_R
SELECT 1,'100000','2017-10-21','ANN',5 UNION ALL
SELECT 2,'100000','2017-10-24','ANN', 2 UNION ALL
SELECT 3 ,'100000','2017-10-25','SIC', 7 UNION ALL
SELECT 4,'123456','2017-10-25','ANN',8
;WITH CTE AS
(
SELECT DISTINCT a.Employee , a.LeaveType , a.AsAtDate , a.Balance
FROM LeaveBalances a INNER JOIN P_R P ON a.Employee=P.Employee
WHERE p.ShiftDate>a.AsAtDate
GROUP BY a.Employee , a.LeaveType , a.AsAtDate , a.Balance,p.Hrs
)
SELECT a.Employee , a.LeaveType , a.AsAtDate , a.Balance-b.Hrs Balance
FROM CTE a
INNER JOIN P_R b ON a.Employee=b.Employee AND a.LeaveType=b.LeaveType
WHERE b.ShiftDate > a.AsAtDate
ROLLBACK TRAN
答案 3 :(得分:0)
我实际上设法提出了一个似乎有效的解决方案,不知道哪种方法最有效,但是这个方法看起来很优雅:
SELECT [LB].[Employee]
,[LB].[LeaveType]
,[LB].[AsAtDate]
,[LB].[Balance] -
SUM(CASE WHEN [R].[LeaveType] = [LB].[LeaveType]
AND [R].[ShiftDate] > [LB].[AsAtDate]
THEN [R].[Hrs] ELSE 0 END) [Balance]
FROM [dbo].[LeaveBalances] [LB]
LEFT JOIN [dbo].[P_R] [R] ON [LB].[Employee] = [R].[Employee]
WHERE [LB].[Employee] = 100000 AND NOT [LB].[Entitlement] = 0
GROUP BY [LB].[LeaveType]
,[LB].[Employee]
,[LB].[AsAtDate]
GO
答案 4 :(得分:0)
CREATE TABLE #LeaveBalances([ID] INT, [Employee] NVARCHAR(255), [LeaveType] NVARCHAR(6) , [AsAtDate] DATETIME, [Balance] INT)
CREATE TABLE #P_R(ID INT,[Employee]NVARCHAR(255), [ShiftDate] DATETIME, [LeaveType] NVARCHAR(6) , [Hrs] INT)
INSERT INTO #LeaveBalances
SELECT 1,'100000','ANN','2017-10-23',10 UNION ALL
SELECT 2,'100000','SIC','2017-10-23',16
INSERT INTO #P_R
SELECT 1,'100000','2017-10-21','ANN',5 UNION ALL
SELECT 2,'100000','2017-10-24','ANN', 2 UNION ALL
SELECT 3 ,'100000','2017-10-25','SIC', 7 UNION ALL
SELECT 4,'123456','2017-10-25','ANN',8;
;WITH CTE AS (
SELECT LBS.Employee,LBS.LeaveType,LBS.AsAtDate,LBS.Balance,#P_R.Hrs,
ROW_NUMBER()OVER(
PARTITION BY LBS.Employee,LBS.LeaveType
ORDER BY LBS.LeaveType,#P_R.ShiftDate DESC
) AS RN
FROM #LeaveBalances AS LBS INNER JOIN #P_R
ON (LBS.Employee=#P_R.Employee)
AND
(LBS.LeaveType=#P_R.LeaveType)
)
SELECT Employee,LeaveType,CAST(AsAtDate AS DATE) AS AsAtDate,
SUM(Balance-Hrs)over(PARTITION BY Employee,LeaveType ORDER BY LeaveType) AS Balance
from CTE WHERE RN=1;
------------------------------------------
Employee LeaveType AsAtDate Balance
---------------------------------------------
100000 ANN 2017-10-23 8
100000 SIC 2017-10-23 9