SQL组合行并创建列

时间:2014-07-16 12:59:00

标签: sql tsql azure

有时最困难的事情是知道如何提出正确的问题,但我会尝试。
我试图弄清楚一条SQL语句(我在Azure SQL中)将检索多行,组合一些列并从其他列创建新的别名列,所有这些都是从更大的列返回的选择语句。 像泥一样清楚?让我试着把它画出来。

    Employees    
    ------------
    employeeID  |  managerID | fname
     1                 5        Bill
     2                 5        John
     3                 6        Mary


ClassRegistration
-----------------
employeeID   |  classID
  1               25
  2               25
  1               27
  1               28
  2               30
  1               45
  1               55
  2               35


Classes
----------
classID  |   classStartDate 
   25           7/1/2014
   27           7/14/2014
   28           7/28/2014
   30           7/11/2014
   35           8/1/2014
   45           8/1/2014

我需要返回的是这样一个表:

Employee fname  |  Last Class |  Upcoming Class 
 Bill                 27              28
 John                 30              35

所以我需要这样的东西:Select * Employees WHERE managerID = 5 然后使用具有指定managerID的所有员工的结果集,为返回的每个员工返回最后一个班级和一行中的下一个班级。
员工也可能有也可能没有最后一堂课和/或即将到来的课程。

我已经看到了许多不同的方法来使用临时表迭代行,或者与GROUP BY等结合使用。但我似乎无法理解我需要的组合。

2 个答案:

答案 0 :(得分:2)

更好的解决方案......使用over子句...

SELECT DISTINCT E.empId, E.managerid, e.fname,    
                Max(lastclass.classStartDate) over(partition by e.empId) as lastClass,
                Min(nextClass.classStartDate) over(partition by e.empId) as nextClass
FROM [T_employees] E
INNER JOIN T_ClassRegistration CR on E.empId = CR.empid   
LEFT JOIN T_Classes lastclass on CR.classid = lastclass.classid 
                             and lastclass.classStartDate <= getdate()
LEFT JOIN T_Classes nextClass on CR.classid = nextClass.classid 
                             and nextClass.classStartDate> getdate()
WHERE managerId = 5

答案 1 :(得分:1)

这不是解决问题的唯一方法,但这是我想到的。它需要两个内部查询,一个用于获取最后一个类,另一个用于获取下一个类。

-- For testing the query, lets set hardcoded date.  Normally one might use GETDATE()
DECLARE @today DATE = '2014-07-16'

SELECT
  e.FName,
  (
    -- Get the class with the highest ClassStartDate which started before today
    SELECT TOP 1 c.ClassID
    FROM ClassRegistration cr
      INNER JOIN Classes c on c.ClassID = cr.ClassId
    WHERE cr.EmployeeID = e.EmployeeID
      AND c.ClassStartDate < @today
    ORDER BY ClassStartDate DESC
  ) AS LastClass,
  (
    -- Get the class with the lowest ClassStartDate which started after, or including, today
    SELECT TOP 1 c.ClassID
    FROM ClassRegistration cr
      INNER JOIN Classes c on c.ClassID = cr.ClassId
    WHERE cr.EmployeeID = e.EmployeeID
      AND c.ClassStartDate >= @today
    ORDER BY ClassStartDate ASC
  ) AS NextClass
FROM Employees e
ORDER BY FName

如果您想按照之前课程中注册的员工进行过滤,那么请执行以下操作:

SELECT * FROM (
  SELECT
    e.FName,
    (
      -- Get the class with the highest ClassStartDate which started before today
      SELECT TOP 1 c.ClassID
      FROM ClassRegistration cr
        INNER JOIN Classes c on c.ClassID = cr.ClassId
      WHERE cr.EmployeeID = e.EmployeeID
        AND c.ClassStartDate < @today
      ORDER BY ClassStartDate DESC
    ) AS LastClass,
    (
      -- Get the class with the lowest ClassStartDate which started after, or including, today
      SELECT TOP 1 c.ClassID
      FROM ClassRegistration cr
            INNER JOIN Classes c on c.ClassID = cr.ClassId
          WHERE cr.EmployeeID = e.EmployeeID
            AND c.ClassStartDate >= @today
          ORDER BY ClassStartDate ASC
        ) AS NextClass
  FROM Employees e
) t
WHERE NextClass IS NOT NULL
ORDER BY FName