SQL获取每条记录的最佳详细信息

时间:2010-12-08 18:22:58

标签: sql sql-server

我需要制定一个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

任何帮助或想法非常感谢。感谢。

4 个答案:

答案 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)