【问题标题】:how do I query sql for a latest record date for each user如何查询sql以获取每个用户的最新记录日期
【发布时间】:2011-01-25 13:49:19
【问题描述】:

我有一个表,它是关于用户何时登录的集合条目。

username, date,      value
--------------------------
brad,     1/2/2010,  1.1
fred,     1/3/2010,  1.0
bob,      8/4/2009,  1.5
brad,     2/2/2010,  1.2
fred,     12/2/2009, 1.3

etc..

如何创建一个查询,为我提供每个用户的最新日期?

更新:我忘记了我需要一个与最新日期一致的值。

【问题讨论】:

标签: sql greatest-n-per-group


【解决方案1】:

如果您的数据库语法支持它,那么TOP 1 WITH TIES 可以与ROWNUMER 结合使用。

根据您提供的示例数据,使用以下查询:

SELECT TOP 1 WITH TIES
  username, date, value
FROM user_log_in_attempts
ORDER BY ROW_NUMBER() OVER (PARTITION BY username ORDER BY date DESC)

它产生:

username | date      | value
-----------------------------
bob      | 8/4/2009  | 1.5
brad     | 2/2/2010  | 1.2
fred     | 12/2/2009 | 1.3

Demo

它是如何工作的:

  • ROWNUMBER() OVER (PARTITION BY... ORDER BY...) 对于每个用户名,从最年轻的 (rownumber=1) 到最老的 (rownumber=high) 计算行列表
  • ORDER BY ROWNUMBER... 将每个用户最年轻的行排序到顶部,然后是每个用户的次年轻行,以此类推
  • TOP 1 WITH TIES 因为每个用户都有一个最年轻的行,所以这些最年轻的行在排序标准的意义上是相等的(所有行号=1)。将返回所有最年轻的行。

使用 SQL-Server 测试。

【讨论】:

  • 但是fred的最新结果是date=1/3/2010 and value=1.0
【解决方案2】:
SELECT MAX(DATE) AS dates 
FROM assignment  
JOIN paper_submission_detail ON  assignment.PAPER_SUB_ID = 
     paper_submission_detail.PAPER_SUB_ID 

【讨论】:

  • 虽然此代码可能会解决问题,including an explanation 关于如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的答案以添加解释并说明适用的限制和假设。 From Review
【解决方案3】:

根据我的经验,最快的方法是获取表格中没有更新行的每一行。

另一个优点是使用的语法非常简单,并且查询的含义相当容易掌握(获取所有行,使得所考虑的用户名不存在更新的行)。

不存在

SELECT username, value
FROM t
WHERE NOT EXISTS (
  SELECT *
  FROM t AS witness
  WHERE witness.username = t.username AND witness.date > t.date
);

ROW_NUMBER

SELECT username, value
FROM (
  SELECT username, value, row_number() OVER (PARTITION BY username ORDER BY date DESC) AS rn
  FROM t
) t2
WHERE rn = 1

内连接

SELECT t.username, t.value
FROM t
INNER JOIN (
  SELECT username, MAX(date) AS date
  FROM t
  GROUP BY username
) tm ON t.username = tm.username AND t.date = tm.date;

左外连接

SELECT username, value
FROM t
LEFT OUTER JOIN t AS w ON t.username = w.username AND t.date < w.date
WHERE w.username IS NULL

【讨论】:

  • 我很难理解 NOT EXISTS 版本。您不是在子查询部分缺少聚合吗?如果我在我的表上运行它,我只能从表中的 40 名员工中获取 3 条员工记录。我应该得到至少 40 条记录。在内部查询中,我们不应该也按用户名进行匹配吗?
  • 它适用于我使用以下内容:SELECT username, value FROM t WHERE NOT EXISTS ( SELECT * FROM t AS witness WHERE witness.date &gt; t.date AND witness.username = t.username );
  • 我查看了 NOT EXISTS,它看起来只为所有用户返回较高的条目,而不是:“一个可以为我提供每个用户的最新日期的查询”。
  • 你说得对,我更新了我的查询。谢谢你的评论! @Narshe 对不起,我因为某种原因错过了你的 cmets:/ 但你是绝对正确的。
  • 这非常好用,非常简单。谢谢!
【解决方案4】:

你也可以使用分析排名函数

    with temp as 
(
select username, date, RANK() over (partition by username order by date desc) as rnk from t
)
select username, rnk from t where rnk = 1

【讨论】:

    【解决方案5】:

    使用窗口函数(适用于 Oracle、Postgres 8.4、SQL Server 2005、DB2、Sybase、Firebird 3.0、MariaDB 10.3)

    select * from (
        select
            username,
            date,
            value,
            row_number() over(partition by username order by date desc) as rn
        from
            yourtable
    ) t
    where t.rn = 1
    

    【讨论】:

    • 值得澄清哪个 Sybase 产品/版本。它不适用于 Sybase ASE 16。
    • 这种方法的一大好处是它保证每个分区总是只返回一行(username,在这种情况下),甚至不需要唯一的“可订购”字段(如在其他答案中加入max(date))。
    • 只是在@MarcoRoy 所说的内容中添加一些内容,如果您碰巧有多个具有相同最大日期的记录,如果您更改查询,例如在调试时,可能会出现不同的记录接收到的行号为 1,所以结果可能不一致。但只要你真的不在乎,那么这应该不是问题。如果您在日期之后添加PK,则可以解决此问题。例如:order by date desc, id desc).
    【解决方案6】:

    这类似于上面的答案之一,但在我看来,它更简单、更整洁。此外,还显示了交叉应用语句的良好用途。对于 SQL Server 2005 及更高版本...

    select
        a.username,
        a.date,
        a.value,
    from yourtable a
    cross apply (select max(date) 'maxdate' from yourtable a1 where a.username=a1.username) b
    where a.date=b.maxdate
    

    【讨论】:

      【解决方案7】:

      我为我的申请做了一些事情:

      下面是查询:

      select distinct i.userId,i.statusCheck, l.userName from internetstatus 
      as i inner join login as l on i.userID=l.userID 
      where nowtime in((select max(nowtime) from InternetStatus group by userID));    
      

      【讨论】:

        【解决方案8】:

        我看到大多数开发人员使用内联查询时没有考虑它对海量数据的影响。

        简单地说,您可以通过以下方式实现:

        SELECT a.username, a.date, a.value
        FROM myTable a
        LEFT OUTER JOIN myTable b
        ON a.username = b.username 
        AND a.date < b.date
        WHERE b.username IS NULL
        ORDER BY a.date desc;
        

        【讨论】:

        • 实际上这仅适用于重复项,如果您有两个以上的值,则条件 a.date
        • 有趣的是,Sybase ASE 16 适用于较小的(100k 行)它会挂起......我认为这将是关系数据库应该的完美示例擅长...
        • @levantpied... 是的,左连接在较大的数据集上成本很高。如果可能的话,您可以通过将过滤条件放在 join 本身上以某种方式处理它来调整性能。
        • 我不明白的是 IS NULL 部分:如果表自连接基于用户名 (a.username = b.username) 那么我们如何找到 b.username 在结果窗口?
        • @KatherineChen 对于a 中具有最大日期的记录,b 中不会有任何记录,后者更大。
        【解决方案9】:

        这也应该可以为用户获取所有最新条目。

        SELECT username, MAX(date) as Date, value
        FROM MyTable
        GROUP BY username, value
        

        【讨论】:

        • 您好,value列需要在group by子句中。
        【解决方案10】:

        我的小合集

        • 自我join优于嵌套select
        • 但是group by 没有给你primary key,这对于join 来说是更可取的
        • 此密钥可由partition byfirst_value (docs) 一起提供

        所以,这里有一个查询:

        选择 t.* 从 表 t 内连接 ( select distinct first_value(ID) over(partition by GroupColumn order by DateColumn desc) 作为 ID 从表 其中 FilterColumn = '值' ) j 上 t.ID = j.ID

        优点:

        • 使用任意列使用where 语句过滤数据
        • select 过滤行中的任何列

        缺点:

        • 从 2012 年开始需要 MS SQL Server。

        【讨论】:

          【解决方案11】:
          SELECT * FROM TABEL1 WHERE DATE= (SELECT MAX(CREATED_DATE) FROM TABEL1)
          

          【讨论】:

          • 欢迎来到 StackOverflow 并感谢您提供帮助。与解释解决方案的答案相比,像您这样的纯代码答案不太受欢迎。
          • 请阅读此how-to-answer 以提供高质量的答案。
          • 和。它不会为每个用户名返回 MAX,只是返回到最新的单行。
          【解决方案12】:

          我使用这种方式为我桌子上的每个用户获取最后一条记录。 这是根据最近在 PDA 设备上检测到的时间获取推销员的最后位置的查询。

          CREATE FUNCTION dbo.UsersLocation()
          RETURNS TABLE
          AS
          RETURN
          Select GS.UserID, MAX(GS.UTCDateTime) 'LastDate'
          From USERGPS GS
          where year(GS.UTCDateTime) = YEAR(GETDATE()) 
          Group By GS.UserID
          GO
          select  gs.UserID, sl.LastDate, gs.Latitude , gs.Longitude
                  from USERGPS gs
                  inner join USER s on gs.SalesManNo = s.SalesmanNo 
                  inner join dbo.UsersLocation() sl on gs.UserID= sl.UserID and gs.UTCDateTime = sl.LastDate 
                  order by LastDate desc
          

          【讨论】:

            【解决方案13】:

            Select * from table1 where lastest_date=(select Max(latest_date) from table1 where user=yourUserName)

            内查询会返回当前用户的最新日期,外查询会根据内查询结果拉取所有数据。

            【讨论】:

              【解决方案14】:
              SELECT t1.username, t1.date, value
              FROM MyTable as t1
              INNER JOIN (SELECT username, MAX(date)
                          FROM MyTable
                          GROUP BY username) as t2 ON  t2.username = t1.username AND t2.date = t1.date
              

              【讨论】:

              • 一两句关于实施或解释的内容对于创建高质量的答案大有帮助。
              【解决方案15】:
              SELECT DISTINCT Username, Dates,value 
              FROM TableName
              WHERE  Dates IN (SELECT  MAX(Dates) FROM TableName GROUP BY Username)
              
              
              Username    Dates       value
              bob         2010-02-02  1.2       
              brad        2010-01-02  1.1       
              fred        2010-01-03  1.0       
              

              【讨论】:

              • 如果多个用户在同一日期有订单,这可能不起作用;如果布拉德和鲍勃在 1 月 2 日都有订单怎么办?
              • 我按用户名分组,所以它可以工作,结果如下:用户名日期值 bob 2010-02-02 1.2 brad 2010-02-02 1.4 fred 2010-01-03 1.0
              【解决方案16】:

              Oracle对结果集进行降序排序,取第一条记录,所以你会得到最新的记录:

              select * from mytable
              where rownum = 1
              order by date desc
              

              【讨论】:

                【解决方案17】:
                SELECT *     
                FROM MyTable T1    
                WHERE date = (
                   SELECT max(date)
                   FROM MyTable T2
                   WHERE T1.username=T2.username
                )
                

                【讨论】:

                • 虽然这是另一种可能的解决方案,但这通常不是解决此问题的好方法。这样做会导致内部查询为表中的每个名称运行一次,从而导致任何显着大小的表的速度大幅下降。在 where 子句中执行一个没有第一个查询元素的单独查询,然后将两个表连接起来通常会更快。
                • 这确实有一个很好的特点,它是一种更易于理解的解决方案,不是特定于实现的。
                【解决方案18】:
                SELECT *
                FROM ReportStatus c
                inner join ( SELECT 
                  MAX(Date) AS MaxDate
                  FROM ReportStatus ) m
                on  c.date = m.maxdate
                

                【讨论】:

                  【解决方案19】:
                  select t.username, t.date, t.value
                  from MyTable t
                  inner join (
                      select username, max(date) as MaxDate
                      from MyTable
                      group by username
                  ) tm on t.username = tm.username and t.date = tm.MaxDate
                  

                  【讨论】:

                  • 使用 postgresql 时,这个版本会比使用 IN(子查询)而不是内部连接更快吗?
                  • @TheOne 以我的经验,使用内连接比使用条件快
                  • 谨慎使用这种方法:如果每个用户每个日期有多个记录,它可以返回多个行(max(date) 将返回一个可以连接多个记录的日期)。为避免此问题,最好使用@dotjoe 的解决方案:stackoverflow.com/a/2411763/4406793
                  • @RedFilter 这非常适合我的问题。非常感谢这样的技术查询。顺便说一句,我使用日期时间而不是日期来避免在特定日期获得多个结果
                  • 为什么需要 'and t.date = tm.MaxDate' 分组还不够?
                  【解决方案20】:

                  获取包含用户最大日期的整行:

                  select username, date, value
                  from tablename where (username, date) in (
                      select username, max(date) as date
                      from tablename
                      group by username
                  )
                  

                  【讨论】:

                  • 为 MySQL 工作
                  • 请注意,如果特定用户有多个具有相同日期的记录,这会给您重复。你可能想要也可能不想要这个。
                  • 这个sql在带有in子句的Oracle中很慢,它不会使用索引
                  【解决方案21】:

                  这应该为您编辑的问题提供正确的结果。

                  子查询确保只找到最新日期的行,外部GROUP BY 将处理关系。当同一用户有两个相同日期的条目时,它将返回具有最高value的条目。

                  SELECT t.username, t.date, MAX( t.value ) value
                  FROM your_table t
                  JOIN (
                         SELECT username, MAX( date ) date
                         FROM your_table
                         GROUP BY username
                  ) x ON ( x.username = t.username AND x.date = t.date )
                  GROUP BY t.username, t.date
                  

                  【讨论】:

                    【解决方案22】:
                    SELECT Username, date, value
                     from MyTable mt
                     inner join (select username, max(date) date
                                  from MyTable
                                  group by username) sub
                      on sub.username = mt.username
                       and sub.date = mt.date
                    

                    将解决更新后的问题。即使有良好的索引,它在大型表上也可能效果不佳。

                    【讨论】:

                      【解决方案23】:

                      你会使用聚合函数 MAX 和 GROUP BY

                      SELECT username, MAX(date), value FROM tablename GROUP BY username, value
                      

                      【讨论】:

                      • 您的编辑只会随机选择一个value,而不是与MAX(date) 行关联的那个。
                      • 它会给出最大日期,但用户名和值可能不同。
                      猜你喜欢
                      • 2023-01-22
                      • 1970-01-01
                      • 1970-01-01
                      • 2021-01-10
                      • 2020-07-21
                      • 1970-01-01
                      • 2018-07-09
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多