代码之家  ›  专栏  ›  技术社区  ›  Mark Pim

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

  •  2
  • Mark Pim  · 技术社区  · 15 年前

    我有一个数据库,它试图通过一个主表和一个历史记录表来获取时间点信息,记录另一个表中的字段将/确实更改的时间。例如

    表:雇员

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

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

    记录显示员工0(Alice)将于2009年5月5日调到第2部门。

    我想写一个查询来确定员工在特定日期的部门。因此,它需要:

    • 之前 给定日期
    • 如果不存在,则默认为主员工表中当前的值。

    我该怎么做?我的直觉是选择结果集的第一行,其中所有合适的历史记录按日期倒序,并且主表中的值位于最后(因此,如果没有合适的历史记录,这只是第一个结果),但我没有实现这一点所需的SQL fu。


    注:我意识到这可能不是实施该系统的最佳方式——我无法在短期内改变这一点——但如果你能提出更好的实施方式,我很高兴听到。

    2 回复  |  直到 15 年前
        1
  •  2
  •   Quassnoi    15 年前
    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
    

    两者 Oracle MS 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
    

    不过,请注意 ROWID 神谕

        2
  •  1
  •   Kluge    15 年前

    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)