如果另一个表中不存在相应的值,则选择SQL

时间:2009-04-01 16:02:15

标签: sql sql-server tsql

我有一个数据库,它试图通过一个主表和一个历史表来记录时间点信息,该表记录了另一个表中的字段何时会发生变化。 e.g。

表:员工

Id  | Name      | Department
-----------------------------
0   | Alice     | 1
1   | Bob       | 1

表:历史记录

ChangeDate   | Field      | RowId  | NewValue    
---------------------------------------------
05/05/2009   | Department | 0      | 2

记录员工0(Alice)将于05/05/2009移至部门2。

我想写一个查询来确定特定日期的员工部门。所以它需要:

  • 在指定日期之前找到该字段和员工的第一条历史记录
  • 如果不存在,则默认为主员工表中当前的值。

我该怎么做?我的直觉是选择结果集的第一行,该结果集具有按日期反向排序的所有合适的历史记录以及最后一个主表中的值(所以如果没有合适的历史记录,它只是第一个结果),但我不知道没有必要的SQL-fu来实现这一点。


注意:我意识到这可能不是实现这个系统的最佳方式 - 我无法在短期内改变这一点 - 尽管如果你能建议一个更好的方法来实现这个我很高兴听到它。

2 个答案:

答案 0 :(得分:2)

SELECT  COALESCE (
        (
        SELECT  newValue
        FROM    history
        WHERE   field = 'Department'
                AND rowID = ID
                AND changeDate =
                (
                SELECT MAX(changedate)
                FROM   history
                WHERE  field = 'Department'
                       AND rowID = ID
                       AND changeDate <= '01/01/2009'
                )
        ), department)
FROM    employee
WHERE   id = @id

OracleMS SQL中,您也可以使用:

SELECT  COALESCE(newValue, department)
FROM    (
        SELECT  e.*, h.*,
                ROW_NUMBER() OVER (PARTITION BY e.id ORDER BY changeDate) AS rn
        FROM    employee e
        LEFT OUTER JOIN
                history h
        ON      field = 'Department'
                AND rowID = ID
                AND changeDate <= '01/01/2009'
        WHERE   e.id = @id
        )
WHERE rn = 1

请注意,ROWIDOracle中的保留字,因此您需要在移植时重命名此列。

答案 1 :(得分:1)

这应该有效:

select iif(history.newvalue is null, employee.department, history.newvalue)
as Department
from employee left outer join history on history.RowId = employee.Id
and history.changedate < '2008-05-20'  // (i.e. given date)
and history.changedate = (select max(changedate) from history h1
where h1.RowId = history.RowId and h1.changedate <= history.changedate)