今天在工作中,我们讨论了哪个是进行这样查询的最佳方式:
例如,假设有一个用户表:
tblUsers
ID = Autoint
Name = String
和登录表:
tblLogin
ID = AUtoint
UserID = Int
IP = String
Browser = String
OS = String
timestamp = DateTime
列出所有用户以及他们上次登录时(如果有的话)最有效的方法是什么,并提供如下输出:
user | ip | timestamp | browser | os |
-------------------------------------------------
Some User |1.1.1.1 | 12/12/12 | userBA | win |
Other User |1.1.1.1 | 12/12/12 | userBA | win |
And Other |null | null | null | null |
Other Yet |1.1.1.1 | 12/12/12 | userBA | win |
请记住,我们想要的是即使他从未登录过,也只显示所有用户一次,并且只显示最近的登录(即max(timestamp))。
有没有办法在一个SQL语句中执行此操作?
我们正在使用MSSQL 2005。
先谢谢你们,吉姆
答案 0 :(得分:2)
SELECT tblUsers.Name, MAX(tblLogin.timestamp)
FROM
tblUsers LEFT JOIN tblLogin ON tblUsers.ID = tblLogin.UserID
GROUP BY tblUsers.ID
答案 1 :(得分:2)
根据经验,以下查询通常快几倍
select
u.name,
l1.ip,
l1.timestamp,
l1.browser,
l1.os
from
tblUsers u
inner join
tblLogin l1
on
u.id = l1.userid
and l1.Id = ISNULL(
(select
top 1 l2.id
from
tblLogin l2
where
u.id = l2.userid
order by
timestamp desc), 0)
比这个查询:
select *
from (
select u.name, l.ip, l.timestamp, l.browser, l.os,
row_number() over (partition by u.id order by timestamp desc) rn
from tblUsers u
inner join tblLogin l on u.id = l.userid
) sub
where rn = 1
有一段时间我对这个主题特别感兴趣,因为我有一个巨大的(几百万行)表,我需要以类似的方式处理。所以我设置了一个测试两种方式,更快的查询运行大约20秒,而较慢的查询运行大约3分15秒。 (这是在SQL 2005上)。你的设置当然可能有所不同,这也取决于索引,但如果性能对你很重要,我会以两种方式测试并选择性能更好的。
通常的免责声明:我实际上没有运行上面的查询,它是为了说明这个想法,可能会出现一些语法错误。
答案 2 :(得分:1)
;WITH cLogins AS
(
SELECT
L.ip, M.LastSeen, L.browser, L.os
FROM
(SELECT UserID, MAX(timestamp) AS LastSeen FROM tblLogin GROUP BY UserID) M
LEFT JOIN
tblLogin L ON M.UserID = L.UserID AND M.LastSeen = L.JOIN
)
SELECT
I.Name, L.ip, L.LastSeen, L.browser, L.os
FROM
tblUsers U
LEFT JOIN
cLogins L ON U.UserID = L.UserID
答案 3 :(得分:1)
我认为,最易读的方法是使用row_number()
。您可以使用它来为每个用户编号,从1开始,如:
select *
from (
select u.name, l.ip, l.timestamp, l.browser, l.os,
row_number() over (partition by u.id order by timestamp desc) rn
from tblUsers u
inner join tblLogin l on u.id = l.userid
) sub
where rn = 1
rn = 1
上的过滤器为每个用户提供最新行。子查询是必需的,因为SQL Server 2005不允许您在row_number()
子句中引用where
。
执行此操作的最有效方法取决于每个用户的登录量。您可以在this blog post中找到一些更高级方法的详细解释。