在查询中加入表值函数

时间:2012-10-21 00:22:53

标签: sql-server sql-server-2008 sql-server-2005 sql-server-2008-r2

我有一个表vwuser。我想用表值函数fnuserrank(userID)连接这个表。所以我需要交叉应用表值函数:

SELECT *
FROM vwuser AS a
CROSS APPLY fnuserrank(a.userid)

对于每个userID,它会生成多个记录。我只希望每个empid的最后一条记录没有Term of Term(inated)。我怎么能这样做?

数据:

HistoryID empid  Rank  MonitorDate
1          A1     E1    2012-8-9
2          A1     E2    2012-9-12 
3          A1     Term  2012-10-13
4          A2     E3     2011-10-09
5          A2     TERM   2012-11-9 

必须从第2条记录和第4条记录中选择。

2 个答案:

答案 0 :(得分:3)

在SQL Server 2005+中,您可以使用此公用表表达式(CTE)来确定MonitorDate的最新记录,该记录没有“Term”等级:

WITH EmployeeData AS
(
   SELECT *
      , ROW_NUMBER() OVER (PARTITION BY empId, ORDER BY MonitorDate DESC) AS RowNumber
   FROM vwuser AS a
   CROSS APPLY fnuserrank(a.userid)
   WHERE Rank != 'Term'
)
SELECT *
FROM EmployeeData AS ed
WHERE ed.RowNumber = 1;

注意:此CTE之前的语句需要以分号结尾。因此,我看到很多人都像;WITH EmployeeData AS...

那样写它们

答案 1 :(得分:2)

你必须要玩这个。无法在sqlfiddle上模拟您的架构。

Select bar.*
from 
(
SELECT *
FROM vwuser AS a
CROSS APPLY fnuserrank(a.userid)
where rank != 'TERM'
) foo
left join 
(
SELECT *
FROM vwuser AS b
CROSS APPLY fnuserrank(b.userid)
where rank != 'TERM'
) bar
on foo.empId = bar.empId
  and foo.MonitorDate > bar.MonitorDate
where bar.empid is null

我总是需要在更高的日期测试左外。。它的工作方式是你做左外。除每个用户一行外,每行都有一个具有更高监视日期的行。那一排是你想要的那一排。我通常使用我的代码中的一个例子,但我在错误的笔记本电脑上。为了使它工作,您可以选择foo。,bar。并查看结果并找到您想要的行并使条件正确。

您也可以这样做,这更容易记住

SELECT *
FROM vwuser AS a
CROSS APPLY fnuserrank(a.userid)
) foo
join 
(
select empid, max(monitordate) maxdate
FROM vwuser AS b
CROSS APPLY fnuserrank(b.userid)
 where rank != 'TERM'
) bar
on foo.empid = bar.empid
and foo.monitordate = bar.maxdate

我通常更喜欢使用基于集合的逻辑而不是聚合函数,但无论如何都可行。您也可以通过将TVF联接的结果缓存到表变量中来调整它。

编辑: http://www.sqlfiddle.com/#!3/613e4/17 - 我在这里嘲笑你的TVF。显然,sqlfiddle不喜欢“去”。

select foo.*, bar.*
from 
(
SELECT f.*
FROM vwuser AS a
join fnuserrank f
  on a.empid = f.empid
where rank != 'TERM'
) foo
left join 
(
SELECT f1.empid [barempid], f1.monitordate [barmonitordate]
FROM vwuser AS b
join fnuserrank f1
  on b.empid = f1.empid
where rank != 'TERM'
) bar
on foo.empId = bar.barempid
  and foo.MonitorDate > bar.barmonitordate
where bar.barempid is  null