【问题标题】:Join the table valued function in the query在查询中加入表值函数
【发布时间】:2012-10-11 05:24:18
【问题描述】:

我有一张桌子 vwuser。我想用表值函数 fnuserrank(userID) 加入这个表。所以我需要与表值函数交叉应用:

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

对于每个用户 ID,它会生成多条记录。我只想要每个没有 Term(inated) Rank 的 empid 的最后一条记录。我该怎么做?

数据:

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

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

【问题讨论】:

  • 您使用什么标准来确定“最后一条记录”?
  • monitordate 列只有一个,必须是最大值
  • 我也在我的问题中给出了数据以及我想要什么
  • 您不想要第 3 条和第 4 条记录吗,因为 3 的 MonitorDate 是在 10 月,而第二条记录的日期只有 9 月?
  • 不,我只想要第二和第四条记录。这是因为我不想终止记录。我想要在此之前的记录。即最后的活动记录

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


【解决方案1】:

在 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...

【讨论】:

  • 实际上,我认为您必须使用 CTE。您可以只使用嵌套的SELECT,例如SELECT t1.* FROM (SELECT a,b,c FROM xyz) t1。但是,ROW_NUMBER() 语句确实需要 SQL Server 2005 或更高版本。编辑:我相信APPLY 也是如此。
  • @BaconBits 你是对的,你不必使用 CTE。不过,我更喜欢它们查看嵌套选择的方式,这就是为什么我在 OP Tags SQL Server 2005+ 时在我的答案中使用它们(在这种情况下,任何一个选项的功能都相同)
【解决方案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 不喜欢“go”。

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  

【讨论】:

  • 顺便说一句 - 你可以在 SQL Fiddle 中“GO”(全部大写)(用于 SQL Server 查询) - sqlfiddle.com/#!3/0e45d/1
  • 大写对这件事有多重要。
  • 是的,我想我可以放宽案件要求。也许我会把它添加到我的待办事项列表中。我的印象是人们总是使用大写的 GO,所以以前没有出现过。
  • 这需要按 SHIFT。一个完整的额外按键!我太懒了:)嘿,sqlfiddle 的大道具!
  • 好消息,Brian - 作为我们聊天的结果,我已将代码修复为不再区分大小写。去,去,去,去 - 谢谢!
猜你喜欢
  • 1970-01-01
  • 2023-04-04
  • 1970-01-01
  • 2015-01-01
  • 2016-02-19
  • 2011-10-09
  • 1970-01-01
  • 2018-07-02
  • 1970-01-01
相关资源
最近更新 更多