需要一些关于简单SQL查询的帮助吗

需要一些关于简单SQL查询的帮助吗,sql,tsql,Sql,Tsql,我有一个将状态信息转储到数据库的游戏。例如,连接、断开连接、抓取屏幕转储等 每个状态都由一个名为StateTypeId的字段定义,该字段是简单查找表'StateTypes'的外键 现在,我正试图找到所有当前已连接的人(例如StateTypeId==1),但我不确定该怎么做。当我说当前已连接时,我的意思是用户没有“LostConnection”状态(即StateType==2)作为其最新条目 我当时在想一件事 SELECT UserId FROM UserData WHERE StateType

我有一个将状态信息转储到数据库的游戏。例如,连接、断开连接、抓取屏幕转储等

每个状态都由一个名为
StateTypeId
的字段定义,该字段是简单查找表
'StateTypes'
的外键

现在,我正试图找到所有当前已连接的人(例如StateTypeId==1),但我不确定该怎么做。当我说当前已连接时,我的意思是用户没有“
LostConnection
”状态(即StateType==2)作为其最新条目

我当时在想一件事

SELECT UserId
FROM UserData
WHERE StateType = 1
GROUP BY UserId

但这会返回所有结果,而不仅仅是最新的结果

有什么建议吗

(我猜我缺少了一个
TOP(1)
和一些排名/顺序?)

编辑 啊!我忘了提到,我在表->DateEntered中有一个DateTime列

编辑2-澄清问题和一些样本数据。 我尝试了建议的解决方案,但运气不太好。因此,我将提供一些示例数据,看看这是否有助于澄清我的问题

ID State          UserName DateAdded
1  Connected      Foo      1/1/2000 12:00 
2  Connected      Bar      1/1/2000 12:01  
3  ScreenShot     Foo      1/1/2000 12:05 
4  LostConnection Foo      1/1/2000 12:06
5  Connected      Joe      1/1/2000 12:10
6  LostConnection Joe      1/1/2000 12:15
7  Screenshot     Bar      1/1/2000 12:16
8  Connected      Jane     1/1/2000 12:22
所以从这个角度来看,(目前)有联系的人是Bar和Jane。福和乔走了。还要注意,Bar的最后一个活动是一个屏幕截图,这意味着,他的最后一个活动不是一个LostConnection状态


HTH.

您要查找的是StateType为1或2的“最近”条目:

然后,您需要为每个用户确定“最后一个”:

select UserName, max(DateAdded) as LastDate
from UserData
where State IN ('Connected', 'LostConnection')
Group by UserName
然后需要检查这些表的状态(这需要与原始表连接):

另一种加入方式是使用UserData的id,如下所示:

SELECT UserName
FROM UserData allData join 
    (select max(id) as id -- if ids are assigned in ascending order
    from UserData
    where State IN ('Connected', 'LostConnection')
    Group by UserName) as lastData on allData.id = lastData.id
WHERE StateType = 'Connected'

您要查找的是StateType为1或2的“最近”条目:

然后,您需要为每个用户确定“最后一个”:

select UserName, max(DateAdded) as LastDate
from UserData
where State IN ('Connected', 'LostConnection')
Group by UserName
然后需要检查这些表的状态(这需要与原始表连接):

另一种加入方式是使用UserData的id,如下所示:

SELECT UserName
FROM UserData allData join 
    (select max(id) as id -- if ids are assigned in ascending order
    from UserData
    where State IN ('Connected', 'LostConnection')
    Group by UserName) as lastData on allData.id = lastData.id
WHERE StateType = 'Connected'

您将需要一个timestamp列,并且需要编写一个将表与自身连接起来的查询,如下所示

Select *
From Userdata U
Where 1 = (Select Top 1 StateType
           From Userdata U2
           Where U.UserId = U2.UserId
           order by u2.TimeStamp desc)

您将需要一个timestamp列,并且需要编写一个将表与自身连接起来的查询,如下所示

Select *
From Userdata U
Where 1 = (Select Top 1 StateType
           From Userdata U2
           Where U.UserId = U2.UserId
           order by u2.TimeStamp desc)

如果您有datetime条目或时间戳,可以通过以下方式执行:

Select UserID
From UserData
Where StateType = 1
Group by UserID
Having Date = Max(Date)

如果您有datetime条目或时间戳,可以通过以下方式执行:

Select UserID
From UserData
Where StateType = 1
Group by UserID
Having Date = Max(Date)

我认为值得测试一个不存在的方法的性能

i、 e.查找具有适当StateType且没有较新记录的用户

SELECT UD1.UserId
FROM  UserData AS UD1
WHERE UD1.StateType = 1
      AND NOT EXISTS
      (
--        Check for newer records:
          SELECT *
          FROM UserData AS UD2
          WHERE UD2.DateEntered > UD1.DateEntered
      )
如果它们有许多行存储在UserData中,并且/或者您将它们保存了很长一段时间,那么这种方法的性能可能会很差

如果是这种情况,并且这是一个频繁发生的查询,我将创建一个UserCurrentState表(columns=UserId,StateType),当StateType更改时更新该表(我将在UserData表上放置触发器以强制执行此操作)


UserData中的StateType索引不够好,无法发挥作用。您可以有一个包含DateEntered、StateType和UserId的索引,该索引将覆盖查询,因此应该使用该索引,但实际上,只有在您可以限制检查的DateEntered范围的情况下,该索引才有帮助。如果你只寻找最后一个小时/天,那么如果你从一开始就在寻找,那么它不会有多大帮助。

我认为值得测试一种不存在的方法的性能

i、 e.查找具有适当StateType且没有较新记录的用户

SELECT UD1.UserId
FROM  UserData AS UD1
WHERE UD1.StateType = 1
      AND NOT EXISTS
      (
--        Check for newer records:
          SELECT *
          FROM UserData AS UD2
          WHERE UD2.DateEntered > UD1.DateEntered
      )
如果它们有许多行存储在UserData中,并且/或者您将它们保存了很长一段时间,那么这种方法的性能可能会很差

如果是这种情况,并且这是一个频繁发生的查询,我将创建一个UserCurrentState表(columns=UserId,StateType),当StateType更改时更新该表(我将在UserData表上放置触发器以强制执行此操作)


UserData中的StateType索引不够好,无法发挥作用。您可以有一个包含DateEntered、StateType和UserId的索引,该索引将覆盖查询,因此应该使用该索引,但实际上,只有在您可以限制检查的DateEntered范围的情况下,该索引才有帮助。如果您只寻找最后一个小时/天,那么如果您从一开始就在寻找,那么它不会有多大帮助。

实际上,这可能会更有效(SQL Server 2005以后)


实际上,这可能更有效(SQL Server 2005以后)


下面是另一个可能的解决方案,尽管使用
的解决方案不存在
可能会执行得更好

SELECT U1.*
FROM UserData U1
 LEFT OUTER JOIN UserData U2
 ON (U1.UserName = U2.UserName
  AND U1.DateAdded < U2.DateAdded
  AND U2.StateType IN (1,2))
WHERE U1.StateType = 1
  AND U2.UserName IS NULL
ORDER BY U1.DateAdded DESC;
选择U1*
从用户数据U1
左外部联接用户数据U2
打开(U1.UserName=U2.UserName
和U1.DateAdded
这里有另一种可能的解决方案,尽管使用
的解决方案不存在
可能会执行得更好

SELECT U1.*
FROM UserData U1
 LEFT OUTER JOIN UserData U2
 ON (U1.UserName = U2.UserName
  AND U1.DateAdded < U2.DateAdded
  AND U2.StateType IN (1,2))
WHERE U1.StateType = 1
  AND U2.UserName IS NULL
ORDER BY U1.DateAdded DESC;
选择U1*
从用户数据U1
左外部联接用户数据U2
打开(U1.UserName=U2.UserName
和U1.DateAdded
UserData中还有哪些列?Oops。我忘了提到DateTime列:)Edited inital post.Mabye这是显而易见的,但是如果您经常执行此查询并且有很多状态更改,那么您最好将最后一个状态反规范化到UserData表中。优点:查询更容易/更快。缺点:更新数据库更难/更慢(必须做两件事并且始终正确)听起来像是触发器的一个好用法…UserData中还有哪些列?Oops。我忘了提到DateTime列:)Edited inital post.Mabye这是显而易见的,但是如果您经常执行此查询并且有很多状态更改,那么您最好将最后一个状态反规范化到UserData表中。优点:查询更容易/更快。C