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

时间:2009-02-13 22:28:26

标签: sql tsql

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

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

现在,我正在尝试查找当前为“Connected”的所有人(例如StateTypeId == 1),我不知道该怎么做。当我说当前连接时,我的意思是用户没有'LostConnection'状态(即StateType == 2)作为他们最近的条目。

我正在思考。

SELECT UserId
FROM UserData
WHERE StateType = 1
GROUP BY UserId

SELECT UserId
FROM UserData
WHERE StateType != 1
GROUP BY UserId

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

有什么建议吗?

(我猜我错过了TOP(1)和某些排名/顺序的东西?)

修改

DOH!我忘了提,我在表格中有一个DateTime列 - > DateEntered。

编辑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。 Foo和Joe走了。还要注意,Bar的最后一个活动是截图,意思是,他的最后一个活动不是LostConnection状态。

HTH。

6 个答案:

答案 0 :(得分:3)

您正在寻找的是StateType为1或2的“最新”条目:

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

select UserName, max(DateAdded) as LastDate
from UserData
where State IN ('Connected', 'LostConnection')
Group by UserName

然后你需要检查这些状态(需要与原始表连接):

SELECT UserName
FROM UserData allData join 
    (select UserName, max(DateAdded) as LastDate
    from UserData
    where State IN ('Connected', 'LostConnection')
    Group by UserName) as lastData on allData.UserName = lastData.UserName
        and allData.DateAdded = lastData.LastDate
WHERE StateType = 'Connected'

另一种加入方式是使用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'

答案 1 :(得分:1)

如果你有日期时间条目或时间戳,你可以这样做:

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

答案 2 :(得分:1)

我认为值得测试NOT EXISTS方法的表现。

即。查找具有相应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表上放置一个Trigger来强制执行此操作) )

UserData中的StateType不能很好地编入索引以使其有用。您可以使用DateEntered,StateType,UserId来覆盖查询,因此应该使用该索引,但实际上,如果您可以限制检查的DateEntered范围,那么这只会有所帮助。如果您只是在寻找最后一小时/天的罚款,如果您从一开始就在寻找,那么它将无济于事。

答案 3 :(得分:1)

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

SELECT UserId
FROM
(
    SELECT  *, row_number() 
        OVER
        (
            partition BY UserId 
            ORDER BY DateEntered DESC
        ) AS RecordNumber
    FROM UserData
) AS UD
WHERE      RecordNumber = 1
        AND StateType = 1

答案 4 :(得分:0)

这是另一种可能的解决方案,尽管使用NOT EXISTS的解决方案可能表现更好。

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;

答案 5 :(得分:-1)

您需要一个时间戳列,您需要编写一个将表连接到自身的查询

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