选择将DISTINCT应用于仅一个特定字段的许多字段

时间:2009-05-31 22:11:23

标签: sql sql-server

在SQL Server中,如何选择多个字段(没有agregation函数)并将DISTINCT语句仅应用于一个特定字段?

例如:如果我有一个存储用户操作的表,那么伪模式将是这样的:

UserActions
------------
id,
User,
Action
insertDate

我想获取给定用户的最新操作,而不重复“Action”字段?

例如,如果表格内容为:

1, john, update, 01/01/09
2, john, update, 01/02/09
3, john, update, 01/03/09
4, john, delete, 01/04/09
5, john, insert, 01/05/09
6, john, delete, 01/06/09

我想得到:

6, john, delete, 01/06/09
5, john, insert, 01/05/09
3, john, update, 01/03/09

非常感谢提前。

5 个答案:

答案 0 :(得分:5)

内部查询应为用户'john'选择每个操作的最大ID,外部查询将选择与内部查询中的id集合匹配的那些记录,因此您应该只获取每个操作的最后一个指定用户。

select id, user, action, insertDate
from userActions
where id in (select max(id)
                 from userActions
                 where user ='john'
                 group by action)

答案 1 :(得分:1)

值得考虑的另一种选择(在SQL Server 2008中;不确定SS 2005):

SELECT id, User, Action, InsertDate
FROM Table
WHERE User = 'john'
AND ROW_NUMBER() 
    OVER(PARTITION BY Action ORDER BY InsertDate DESC) 
    = 1

(看,马,没有聚合函数! - )

答案 2 :(得分:1)

忽略OP需要没有聚合函数(仍不确定为什么......)

我对给定答案的问题是:

  1. 允许其他任何用户都不是动态的 - 比如'mark'
  2. 它假设某个操作的最大值(id)与最新操作相匹配 - 测试数据表明这一点,但我不会认为这是一个规则。
  3. 所以考虑到这些需要构建一个更动态的查询

    将2行添加到测试数据

     7, john, update, 04/01/09
     8, mark, insert, 01/02/09
    

    答案没有给出OP想要的东西

    这是我的第一稿快速 - 稍后会整理

    select
        userActions.id,
        userActions.[user],
        userActions.Action,
        userActions.insertDate
    
    from
    userActions
    join
        (
        select
            [user], action, max(insertdate) as maxinsertdate
        from userActions
        group by
            [user], action
        ) aggsubquery
        on userActions.[user] = aggsubquery.[user] 
             and userActions.action = aggsubquery.action 
             and userActions.insertdate = aggsubquery.maxinsertdate 
    

    ...更新

    第二版使用ID获取一个不同的行,特定用户可能会有多个行为,即测试数据是否也有以下行

     9, john, delete, 06/01/09
    

    然后你需要在行id 6和行id 9之间决定返回哪一个。我随意选择使用max(id),因为我猜数据很重要而不是行id

    select
        max(userActions.id) as id,
        userActions.[user],
        userActions.Action,
        userActions.insertDate  
    from
    userActions
    join
        (
        select
            [user], action, max(insertdate) as maxinsertdate
        from userActions
        group by
            [user], action
        ) aggsubquery
        on userActions.[user] = aggsubquery.[user] 
            and userActions.action = aggsubquery.action 
            and userActions.insertdate = aggsubquery.maxinsertdate 
    group by
        userActions.[user],
        userActions.Action,
        userActions.insertDate
    

答案 3 :(得分:0)

不确定如何只使用SQL来做到这一点。您可以执行完整查询(看起来您希望按InsertDate DESC排序),然后只手动拉出所需的查询。

set s = new set()
while (has more results) {
   var r = next result
   if (!s.contains(r)) {
      process result
      s.add(r)
   }
}

答案 4 :(得分:0)

如果您有一组固定的操作,您可以为每个操作的TOP 1编写查询,并将结果合并在一起:

SELECT TOP 1 [id], [User], [InsertDate] 
FROM [UserActions] 
WHERE [Action] = 'insert' 
ORDER BY [InsertDate] DESC

UNION

SELECT TOP 1 [id], [User], [InsertDate] 
FROM [UserActions] 
WHERE [Action] = 'update' 
ORDER BY [InsertDate] DESC

UNION

SELECT TOP 1 [id], [User], [InsertDate] 
FROM [UserActions] 
WHERE [Action] = 'delete' 
ORDER BY [InsertDate] DESC