这是我在StackOverflow上的第一篇文章,我是SQL的新手,感谢您的耐心等待!我已经进行了广泛的搜索,但没有找到遇到类似问题的人。从表面上看,我的问题似乎很简单(希望如此),但过去一周我一直在尝试各种不同的事情,但未能解决。简而言之,这里是:
到目前为止我尝试过的事情:
我只处理一个员工记录的成功案例:
DECLARE @Skill int
SET @Skill = 81
SELECT TOP 1
P.lastname+', '+P.firstname AS Employee,
P.external_id,
PC.job_title,
SD.name,
SV.schedule_days as ExpireInterval,
PO.course_startdate,
DATEADD(DD,SV.schedule_days,PO.course_startdate) as ExpireDate
FROM portfolio PO
INNER JOIN person P ON PO.person_id=P.person_id
INNER JOIN e_component EC ON PO.component_id=EC.component_id
JOIN skill_value SV ON EC.component_id=SV.object_id
JOIN skill_description SD ON SV.skill_id=SD.skill_id
JOIN person_custom PC ON P.person_id=PC.person_id
GROUP BY
PO.person_id,
PO.course_startdate,
SV.skill_id,
P.lastname,
P.firstname,
P.external_id,
PC.job_title,
SD.name,
SV.schedule_days,
SD.language_id
HAVING SD.language_id=26
AND PO.person_id=123456
AND SV.skill_id= @Skill
ORDER BY Employee, PO.course_startdate DESC
注意::过多的JOINS是由于主机数据库中缺少FK关系。我们的供应商将其设计为主要依赖于内置在其前端中的代码,因此我正在使用自己所拥有的东西。
前面列出的代码返回以下结果: Most Recent Record for Employee #123456
但是,当我尝试从员工列表中提取最新记录时:
DECLARE @Skill int
SET @Skill = 81
SELECT
P.lastname+', '+P.firstname AS Employee,
P.external_id,
PC.job_title,
SD.name,
SV.schedule_days as ExpireInterval,
PO.course_startdate,
DATEADD(DD,SV.schedule_days,PO.course_startdate) as ExpireDate
FROM portfolio PO
INNER JOIN person P ON PO.person_id=P.person_id
INNER JOIN e_component EC ON PO.component_id=EC.component_id
JOIN skill_value SV ON EC.component_id=SV.object_id
JOIN skill_description SD ON SV.skill_id=SD.skill_id
JOIN person_custom PC ON P.person_id=PC.person_id
GROUP BY
PO.person_id,
PO.course_startdate,
SV.skill_id,
P.lastname,
P.firstname,
P.external_id,
PC.job_title,
SD.name,
SV.schedule_days,
SD.language_id
HAVING SD.language_id=26
AND PO.person_id IN (SELECT DISTINCT person_id FROM portfolio)
AND SV.skill_id= @Skill
ORDER BY Employee, PO.course_startdate DESC
我为同一个雇员获得多个条目(例如,该雇员以相同的Skill_id参加培训的不同时间)。
我想做的是这样的:
IF count(SV.skill_id)>1
THEN SELECT TOP 1 component_id --for each individual
FROM portfolio
我只是不知道把条件放哪儿给我一个记录。我尝试分配局部变量,将 SELECT 子查询移动到各个列,添加和删除约束...等等。到目前为止,什么都没起作用。
我正在使用以下软件:
预先感谢您的帮助! 〜莱克斯
P.S。如果有使用正则表达式对报表表单上的记录进行排序的方法,请告诉我!我尝试了几种不同的方法,但是我可以肯定是需要帮助的是我的SQL。
答案 0 :(得分:1)
一些观察,然后是一个答案。
在SQL Server中,INNER JOIN
和JOIN
含义相同。
正如@DaleBurrell所指出的那样,除非您要使用汇总值进行过滤,否则请使用WHERE
子句,而不要使用HAVING
子句。 WHERE
在查询处理中较早地应用,您应该看到将过滤放在适当的位置会获得更好的性能。另外,如果可以的话,它更“标准”。
最后,我删除了person_id
的过滤子查询,因为它是portfolio
的自连接,我看不出有充分的理由。如果其中还有其他有用的条件,请继续并放回去。
话虽如此,您的第二次尝试确实非常接近。如果您使用现有的ORDER BY
子句RANK来搜索结果,然后应用TOP (1) WITH TIES,它将返回按日期排序的每位员工排名第一的结果。
DECLARE @Skill int
SET @Skill = 81
SELECT TOP (1) WITH TIES
P.lastname+', '+P.firstname AS Employee,
P.external_id,
PC.job_title,
SD.name,
SV.schedule_days as ExpireInterval,
PO.course_startdate,
DATEADD(DD,SV.schedule_days,PO.course_startdate) as ExpireDate
FROM portfolio PO
JOIN person P ON PO.person_id=P.person_id
JOIN e_component EC ON PO.component_id=EC.component_id
JOIN skill_value SV ON EC.component_id=SV.object_id
JOIN skill_description SD ON SV.skill_id=SD.skill_id
JOIN person_custom PC ON P.person_id=PC.person_id
JOIN portfolio PF ON PO.person_id = PF.person_id
WHERE SD.language_id=26
AND SV.skill_id= @Skill
GROUP BY
PO.person_id,
PO.course_startdate,
SV.skill_id,
P.lastname,
P.firstname,
P.external_id,
PC.job_title,
SD.name,
SV.schedule_days,
SD.language_id
ORDER BY RANK() OVER (PARTITION BY Employee ORDER BY PO.course_startdate DESC)
答案 1 :(得分:0)
如果您按课程名称分组,然后选择max(course_date),则会得到例如
DECLARE @Skill int
SET @Skill = 81
SELECT TOP 1
P.lastname+', '+P.firstname AS Employee,
P.external_id,
PC.job_title,
SD.name,
SV.schedule_days as ExpireInterval,
max(PO.course_startdate) most_recent_course_startdate,
max(DATEADD(DD,SV.schedule_days,PO.course_startdate)) as ExpireDate
FROM portfolio PO
INNER JOIN person P ON PO.person_id=P.person_id
INNER JOIN e_component EC ON PO.component_id=EC.component_id
JOIN skill_value SV ON EC.component_id=SV.object_id
JOIN skill_description SD ON SV.skill_id=SD.skill_id
JOIN person_custom PC ON P.person_id=PC.person_id
where SD.language_id=26
AND PO.person_id=123456
AND SV.skill_id= @Skill
GROUP BY
PO.person_id,
--PO.course_startdate,
SV.skill_id,
P.lastname,
P.firstname,
P.external_id,
PC.job_title,
SD.name,
SV.schedule_days,
SD.language_id
ORDER BY Employee, most_recent_course_startdate DESC
HAVING
也适用于汇总条件,否则请坚持使用WHERE
。
答案 2 :(得分:0)
您几乎发现了“我想做什么”代码段中的问题,也就是说,当您拥有的数量超过10个时,您就无法使用TOP 1
+ ORDER BY
获取最新记录1个用户(即希望返回1行以上)。
ROW_NUMBER()
是处理此问题的好方法。它根据条件为每行分配一个数字。
例如,ROW_NUMBER() OVER (PARTITION BY PO.person_id ORDER BY PO.course_startdate DESC) as RN
将为每一行分配一个1
,其中每个PO.course_startdate
都具有最新的PO.person_id
。如果您在派生表或CTE中执行此操作,则只需在最终/外部选择中过滤到RN = 1
即可找到每个用户的最新行。
CTE示例:
DECLARE @Skill int
SET @Skill = 81
;WITH yourCTE as (
SELECT
P.lastname+', '+P.firstname AS Employee,
P.external_id,
PC.job_title,
SD.name,
SV.schedule_days as ExpireInterval,
PO.course_startdate,
DATEADD(DD,SV.schedule_days,PO.course_startdate) as ExpireDate,
ROW_NUMBER() OVER (PARTITION BY PO.person_id ORDER BY PO.course_startdate DESC) as RN
FROM portfolio PO
JOIN person P ON PO.person_id=P.person_id
JOIN e_component EC ON PO.component_id=EC.component_id
JOIN skill_value SV ON EC.component_id=SV.object_id
JOIN skill_description SD ON SV.skill_id=SD.skill_id
JOIN person_custom PC ON P.person_id=PC.person_id
WHERE SD.language_id=26
AND SV.skill_id= @Skill
)
SELECT employee, extenal_id, job_title, name,
ExpireInterval, course_startdate, ExpireDate
FROM yourCTE
WHERE RN = 1
我还将您的HAVING
条件移至WHERE
(并删除了一个多余的条件),将INNER JOIN
简化为JOIN
(只是为了保持一致),并且删除了您的GROUP BY
和ORDER BY
。我没有看到指向分组的信息,但是如果仍然需要,可以将ORDER BY
添加到最终选择中。