我有一张表,列出了不同用户的假期信息(用户名,假期开始和假期结束日期) - 下面列出了4位用户:
Username VacationStart DeploymentEnd
rsuarez 2014-03-10 2014-03-26
studd 2014-01-18 2014-01-29
studd 2014-02-11 2014-02-26
studd 2014-03-02 2014-03-04
ssteele 2014-03-11 2014-03-26
ssteele 2014-03-18 2014-03-28
atidball 2014-03-05 2014-03-20
atidball 2014-03-06 2014-03-26
atidball 2014-03-13 2014-03-20
atidball 2014-03-18 2014-03-31
对于新查询,我想只显示4行,每个用户只显示一组休假日期,当前/进行中休假,未来/下一个休假(如果没有当前存在)或最近(如果以上两个都是假的。)
最终结果应该是(假设今天是2014年3月9日):
Username VacationStart DeploymentEnd
rsuarez 2014-03-10 2014-03-26
studd 2014-03-02 2014-03-04
ssteele 2014-03-11 2014-03-26
atidball 2014-03-05 2014-03-20
假期日期实际上来自另一个表(data_vacations),我将其连接到data_users。我试图在左连接语句中执行大小写选择。
这是我之前尝试过的,但我的逻辑在那里失败了,因为我最终将不同的假期结束日期与假期开始日期混合:
SELECT Username, VacationStart, VacationEnd
FROM data_users
LEFT JOIN
(
SELECT userGUID,
CASE WHEN MIN(CASE WHEN (VacationEnd < getdate()) THEN NULL ELSE VacationStart END) IS NULL THEN MAX(VacationStart)
ELSE MIN(VacationStart) END AS VacationStart,
CASE WHEN MIN(CASE WHEN (VacationEnd < getdate()) THEN NULL ELSE VacationEnd END) IS NULL THEN MAX(VacationEnd)
ELSE MIN(VacationEnd) END AS VacationEnd
FROM data_vacations
GROUP BY userGUID
) b ON(data_empl_master.userGUID= b.userGUID)
我做错了什么?我怎么能解决它?
另外..旁边注意..我是否正确地在LEFT JOIN中执行此过滤?由于data_users更大,具有不同的用户ID ...我想基于上面的示例加入可用的度假信息,同时仍然显示所有唯一的用户ID。
答案 0 :(得分:0)
select u.name,s.startdate,s.enddate
from users u
left join
(
select su.name,
max(su.start) as startdate,
max(su.end) as enddate from users su group by su.name
)s on u.name= s.name
group by u.name
答案 1 :(得分:0)
既然你问了两个问题,我会回答一个关于获得假期的问题,并让你弄清楚加入。
我认为您不能在一个简单的查询中获得所需的假期日期。首先,您需要确定给定的日期范围是过去,现在还是将来。然后,您需要按开始/结束日期对这些范围进行排序,以获得最新或即将到来的日期。您需要按降序排序过去的假期并按升序排序。足够有趣的用户atidball有两个正在进行的假期,我以与未来假期相同的方式对其进行排序。最后应用你的规则,我按状态排序。
declare @currentDate date = '20140309'
;
with cte1 as
(
-- state: the lower number the higher priority
select Username, VacationStart, DeploymentEnd,
case
when VacationStart <= @currentDate and DeploymentEnd >= @currentDate
then 0 -- in progress
when VacationStart > @currentDate
then 1 -- future
when DeploymentEnd < @currentDate
then 2 -- past
else NULL
end as state
from data_vacations
)
, cte2 as
(
select *,
row_number() over(partition by username, state order by VacationStart, DeploymentEnd) as rn
from cte1
where state < 2 -- current or upcoming
union all
select *,
row_number() over(partition by username, state order by DeploymentEnd desc, VacationStart desc) as rn
from cte1
where state = 2 -- past
)
, cte3 as
(
-- apply the rules: find the record with highest priority
select Username, min(state) as minstate
from cte1
group by Username
)
select cte2.Username, cte2.VacationStart, cte2.DeploymentEnd
from cte2
inner join cte3
on cte2.Username = cte3.Username
and cte2.state = cte3.minstate
and cte2.rn = 1 -- most recent or next upcoming
请参阅SQLFiddle。
答案 2 :(得分:0)
使用公用表表达式按类别排序(current = 1,future = 2,past = 3),每个类别按开始日期/差异从GETDATE()开始,您可以通过对结果进行排名来获得所需的结果使用ROW_NUMBER()
;
DECLARE @DATE DATETIME = GETDATE()
;WITH cte AS (
SELECT *, 1 r, VacationStart s FROM data_users
WHERE @DATE BETWEEN VacationStart and DeploymentEnd
UNION ALL
SELECT *,2 r, VacationStart - @DATE s FROM data_users
WHERE VacationStart > @DATE
UNION ALL
SELECT *,3 r, @DATE - DeploymentEnd s FROM data_users
WHERE DeploymentEnd < @DATE
), cte2 AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY username ORDER BY r,s) rn FROM cte
)
SELECT Username, VacationStart, DeploymentEnd FROM cte2 WHERE rn=1;
获取日期作为变量是必要的,以便在整个查询中获得一致的GETDATE()
值,否则如果多次调用它可能不一致。