我需要制定一个SQL。为了更好地表达我的要求,我将使用以下数据说明相同的内容:
必须重新解释问题和示例以便更好地理解
T_Employee
ID Name
1 John
2 Jane
3 Joe
T_Roles
ID RoleName
1 Clerk I
2 Clerk II
3 Manager
4 Senior Manager
T_EmployeeRoles
ID EmployeeID RoleID
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
6 2 3
7 2 4
8 3 3
9 4 4
现在,SQL select应该能够产生以下输出:
ID Name Current Role Last Role
1 John Manager Clerk II
2 Jane Senior Manager Manager
3 Joe Senior Manager Manager
任何帮助或想法非常感谢。感谢。
答案 0 :(得分:2)
您可以从T_EmployeeRole中选择所有内容并添加一个额外的RoleNumber列,使用ROW_NUMBER函数为每个人的角色编号,如下所示:
ROW_NUMBER() OVER(PARTITION BY Name ORDER BY ID desc) as RoleNumber
每个Name的重启号,给出最高ID,RoleNumber为1. RoleNumber = 1的所有内容都是当前角色,RoleNumber = 2的所有内容都是之前的角色。
http://msdn.microsoft.com/en-us/library/ms186734.aspx
编辑: 为了匹配您更新的问题,请在您的数据中注明Joe只是一个管理员,并且之前没有任何角色,因此您的示例答案与数据不匹配。
select 1 as ID, 'John' as Name
into #T_Employee
union select 2, 'Jane'
union select 3, 'Joe'
select 1 as ID, 'Clerk I' as RoleName
into #T_Roles
union select 2, 'Clerk II'
union select 3, 'Manager'
union select 4, 'Senior Manager'
select 1 as ID, 1 as EmployeeID, 1 as RoleID
into #T_EmployeeRoles
union select 2, 1, 2
union select 3, 1, 3
union select 4, 2, 1
union select 5, 2, 2
union select 6, 2, 3
union select 7, 2, 4
union select 8, 3, 3
union select 9, 4, 4
select er.ID
,er.EmployeeID
,er.RoleID
,r.RoleName
,ROW_NUMBER() OVER(PARTITION BY er.EmployeeID ORDER BY er.ID desc) as RoleNumber
into #OrderedRoles
from #T_EmployeeRoles er
left join #T_Roles r on r.ID = er.RoleID
select emp.ID
,emp.Name
,r1.RoleName as CurrentRole
,r2.RoleName as LastRole
from #T_Employee emp
left join #OrderedRoles r1 on r1.EmployeeID = emp.ID
and r1.RoleNumber = 1
left join #OrderedRoles r2 on r2.EmployeeID = emp.ID
and r2.RoleNumber = 2
答案 1 :(得分:1)
我无法在实时实例上对此进行验证,但以下操作可能正常。
;WITH current AS (
SELECT ID = MAX(er.ID)
FROM T_Employees er
GROUP BY
er.Name
)
SELECT c.Name, c.Current, l.Last
FROM (
SELECT er.Name, Current = er.Role
FROM T_Employees er
INNER JOIN current ON current.ID = er.ID
) c
LEFT OUTER JOIN (
SELECT er.Name, Last = er.Role
FROM T_Employees er
INNER JOIN (
SELECT ID = MAX(er.ID)
FROM T_Employees er
WHERE NOT EXISTS (
SELECT *
FROM current
WHERE current.ID = er.ID
)
GROUP BY
er.Name
) last ON last.ID = er.ID
) l ON l.Name = c.Name
答案 2 :(得分:1)
the answer by Alex works for me这是一种不同的方式,没有ROW_Number ......
我认为您的示例输出有误,请尝试一下:
SET NOCOUNT ON
DECLARE @T_Employee table (ID int, Name varchar(10))
INSERT @T_Employee VALUES(1, 'John')
INSERT @T_Employee VALUES(2, 'Jane')
INSERT @T_Employee VALUES(3, 'Joe')
DECLARE @T_Roles table (ID int, RoleName varchar(15))
INSERT @T_Roles VALUES(1, 'Clerk I')
INSERT @T_Roles VALUES(2, 'Clerk II')
INSERT @T_Roles VALUES(3, 'Manager')
INSERT @T_Roles VALUES(4, 'Senior Manager')
DECLARE @T_EmployeeRoles table (ID int, EmployeeID int, RoleID int)
INSERT @T_EmployeeRoles VALUES(1, 1, 1)
INSERT @T_EmployeeRoles VALUES(2, 1, 2)
INSERT @T_EmployeeRoles VALUES(3, 1, 3)
INSERT @T_EmployeeRoles VALUES(4, 2, 1)
INSERT @T_EmployeeRoles VALUES(5, 2, 2)
INSERT @T_EmployeeRoles VALUES(6, 2, 3)
INSERT @T_EmployeeRoles VALUES(7, 2, 4)
INSERT @T_EmployeeRoles VALUES(8, 3, 3)
INSERT @T_EmployeeRoles VALUES(9, 4, 4)
SET NOCOUNT OFF
;WITH CurrentInfo AS
(SELECT
e.ID AS EmployeeID, e.Name, r.RoleID AS CurrentRoleID, mr.ID AS EmployeeRoleID
FROM @T_Employee e
LEFT OUTER JOIN (SELECT
EmployeeID,MAX(ID) AS ID
FROM @T_EmployeeRoles
GROUP BY EmployeeID
) mr ON e.ID=mr.EmployeeID
LEFT OUTER JOIN @T_EmployeeRoles r ON mr.ID=r.ID
)
SELECT
c.EmployeeID AS ID, c.Name, r.RoleName AS "Current Role", llr.RoleName AS "Last Role"
FROM CurrentInfo c
LEFT OUTER JOIN @T_Roles r ON c.CurrentRoleID=r.ID
LEFT OUTER JOIN (SELECT
rr.EmployeeID,MAX(rr.ID) AS ID
FROM @T_EmployeeRoles rr
LEFT OUTER JOIN CurrentInfo cc ON rr.ID=cc.EmployeeRoleID
WHERE cc.EmployeeRoleID IS NULL
GROUP BY rr.EmployeeID
) mr ON c.EmployeeID=mr.EmployeeID
LEFT OUTER JOIN @T_EmployeeRoles lr ON mr.ID=lr.ID
LEFT OUTER JOIN @T_Roles llr ON lr.RoleID=llr.ID
输出:
ID Name Current Role Last Role
----------- ---------- --------------- ---------------
1 John Manager Clerk II
2 Jane Senior Manager Manager
3 Joe Manager NULL
(3 row(s) affected)
如果只有“当前角色”,因为员工只处理了一个职位,您可以通过在SELECT中执行此操作将“当前角色”推送到“最后角色”:
... , ISNULL(llr.RoleName,r.RoleName) AS "Last Role"
编辑
这里是没有CTE的查询版本,因此它将在SQL Server 2000上运行,我还用OP的实际表名替换了变量表:
SELECT
c.EmployeeID AS ID, c.Name, r.RoleName AS "Current Role", llr.RoleName AS "Last Role"
FROM (SELECT
e.ID AS EmployeeID, e.Name, r.RoleID AS CurrentRoleID, mr.ID AS EmployeeRoleID
FROM T_Employee e
LEFT OUTER JOIN (SELECT
EmployeeID,MAX(ID) AS ID
FROM T_EmployeeRoles
GROUP BY EmployeeID
) mr ON e.ID=mr.EmployeeID
LEFT OUTER JOIN T_EmployeeRoles r ON mr.ID=r.ID
) c
LEFT OUTER JOIN T_Roles r ON c.CurrentRoleID=r.ID
LEFT OUTER JOIN (SELECT
rr.EmployeeID,MAX(rr.ID) AS ID
FROM T_EmployeeRoles rr
LEFT OUTER JOIN (SELECT
e.ID AS EmployeeID, e.Name, r.RoleID AS CurrentRoleID, mr.ID AS EmployeeRoleID
FROM T_Employee e
LEFT OUTER JOIN (SELECT
EmployeeID,MAX(ID) AS ID
FROM T_EmployeeRoles
GROUP BY EmployeeID
) mr ON e.ID=mr.EmployeeID
LEFT OUTER JOIN T_EmployeeRoles r ON mr.ID=r.ID
) cc ON rr.ID=cc.EmployeeRoleID
WHERE cc.EmployeeRoleID IS NULL
GROUP BY rr.EmployeeID
) mr ON c.EmployeeID=mr.EmployeeID
LEFT OUTER JOIN T_EmployeeRoles lr ON mr.ID=lr.ID
LEFT OUTER JOIN T_Roles llr ON lr.RoleID=llr.ID
答案 3 :(得分:0)
我认为这个会奏效:
CREATE TABLE #T_EmployeeRole
(
id int identity(1,1),
name varchar(10),
role varchar(20)
)
INSERT INTO #T_EmployeeRole(name, role)
SELECT 'John', 'Clerk I' UNION ALL
SELECT 'John', 'Clerk II' UNION ALL
SELECT 'John', 'Clerk III' UNION ALL
SELECT 'Mark', 'Junior Developer' UNION ALL
SELECT 'Mark', 'Developer' UNION ALL
SELECT 'Mark', 'Senior Developer' UNION ALL
SELECT 'Alice', 'Accountant I' UNION ALL
SELECT 'Alice', 'Treasury Analyst I' UNION ALL
SELECT 'Alice', 'Treasury Analyst II' UNION ALL
SELECT 'Alice', 'Controller' UNION ALL
SELECT 'Chris', 'Secretary I' UNION ALL
SELECT 'Chris', 'Secretary II' UNION ALL
SELECT 'Eric', 'Analyst I' UNION ALL
SELECT 'Eric', 'Analyst II'
select cur.name, cur.role, prev.role
from #T_EmployeeRole cur
left outer join #T_EmployeeRole prev on prev.name = cur.name
and prev.id = (select max(#T_EmployeeRole.id) from #T_EmployeeRole where #T_EmployeeRole.name = cur.name and #T_EmployeeRole.id <> cur.id)
where cur.id = (select max(#T_EmployeeRole.id) from #T_EmployeeRole where #T_EmployeeRole.name = cur.name)