【问题标题】:Select row with most recent date per user where date is more than current date选择每个用户最近日期的行,其中日期大于当前日期
【发布时间】:2016-01-14 03:08:35
【问题描述】:

我的桌子是:

 id  user   date
 ---|-----|------------|
 1  | ab  | 2011-03-04 |
 2  | ab  | 2016-03-04 |
 3  | cd  | 2009-03-04 |
 4  | cd  | 2013-03-03 |
 5  | ef  | 2009-03-03 |

我需要选择每个不同的用户:

“更新”> 比当前日期晚的日期

结果是:

 id  user   date
 ---|-----|------------|
 2  | ab  | 2016-03-04 |
 5  | ef  | 2016-03-03 |

"过期" > 日期小于当前日期

结果是:

 id  user   date
 ---|-----|------------|
 3  | cd  | 2009-03-04 |

我试过了:

SELECT t1.* FROM tmp t1
WHERE t1.date = (SELECT MAX(t2.date)
FROM tmp t2 WHERE t2.user = t1.user
AND YEAR(MAX(t2.date))<(YEAR(CURRENT_TIMESTAMP)-1))
order by user asc

它不起作用。结果集有 0 行。 有任何想法吗?谢谢。这对我有很大帮助..

【问题讨论】:

  • 请查看下面给出的深思熟虑的答案,谢谢。

标签: php mysql sql date datetime


【解决方案1】:

对于大于当前日期的日期:

select distinct user
from t
where `update` >= curdate();

其实,我想你想要一个group by

select user
from t
group by user
having max(`date`) >= curdate();

这也适用于较早的日期。

【讨论】:

  • 我很抱歉,但“更新”和“过期”不是列或表的名称..这只是我所做的状态..
【解决方案2】:

几个观察:

“它不起作用”不能很好地描述您观察到的行为。它没有描述查询是否正在执行并返回意外结果,或者查询是否返回错误。

date 显示的值是一种奇怪的非 MySQL 格式。 DATE 值的标准格式是 YYYY-MM-DD。这让我们想知道名为 date 的列的实际 datatype 是什么。如果它是一个字符串,月份和日期在年份之前,那么在比较中就会出现问题。字符串比较是逐个字符进行的,从左到右。

YEAR() 函数在这种情况下的使用非常奇怪。你说你想比较“日期”值。 YEAR 函数从日期中提取年份值。所以看起来您的查询只会比较一年。

再一次,如果 YEAR() 函数的参数不是 DATE 数据类型,则该参数将隐式转换为 DATE... 并且该隐式转换正常工作,字符串需要采用类似“YYYY-MM-DD”的格式。

此外,子查询似乎在 WHERE 子句中使用聚合函数 MAX()。那是无效的。 WHERE 子句中的谓词在访问行时进行评估。直到 行被访问后,聚合函数的值才可用,并且执行 group by 操作。如果您需要聚合条件,则可以进入HAVING 子句。

【讨论】:

  • 很抱歉我的不当之处.. 是的,我检查了我的数据库,我的日期格式是 yyyy-mm-dd.. 所以也许格式不是问题..
  • "SELECT * FROM tmp where YEAR(date)>=(YEAR(CURRENT_TIMESTAMP)-1) order by date desc" > 我使用这个查询来显示更新行并且它有效.. 但我需要显示更新中未显示的过期行。我的意思是如果该行显示在更新中,那么它不会显示在过期中。请帮助我
  • @Fiki 这不是使用 Stack Overflow 的方式。您应该查看每个答案并评论每种方法是否有助于解决您的问题。
【解决方案3】:

您的日期采用MM/dd/YYYY 的特殊格式,在尝试此处给出的任何答案时可能会给您带来问题。您应该将04/03/2011 转换为2011-04-03。话虽如此,假设您的 date 列确实是 MySQL 日期类型,那么以下查询将为您提供所有不同的“更新”用户:

SELECT t1.id, t1.user, t1.date, 'update' AS status
FROM antivirus t1
INNER JOIN
(
    SELECT user, MAX(date) AS date
    FROM antivirus
    GROUP BY user
    HAVING MAX(date) >= CURDATE()
) t2
ON t1.user = t2.user AND t1.date = t2.date

SQLFiddle

请注意,在我的 Fiddle 中,我必须修改示例表中日期输入的格式。

如果您还希望在同一查询中包含“过期”用户,则可以添加 UNION ALL 以及以下内容:

SELECT t1.id, t1.user, t1.date, 'expired' AS status
FROM antivirus t1
INNER JOIN
(
    SELECT user, MAX(date) AS date
    FROM antivirus
    GROUP BY user
    HAVING MAX(date) < CURDATE()
) t2
ON t1.user = t2.user AND t1.date = t2.date

【讨论】:

  • 我认为您的数据可能有问题。查询应该会给你结果。等等,我会为你设置一个 SQL Fiddle。
  • @TimBiegeleisen:对该行为的最可能解释是 OP date 列是格式为 MM/DD/YYYYDD/MM/YYYY 的 VARCHAR,MySQL 不会将其转换为 DATE数据类型,没有明确的STR_TO_DATE 函数。
  • @spencer7593 我也注意到了这一点。由于格式问题,任何人的查询都不会在他的原始数据上运行。我现在在 Fiddle 中测试我的查询,它在按摩他的日期格式后工作。
  • "SELECT * FROM tmp where YEAR(date)>=(YEAR(CURRENT_TIMESTAMP)-1) order by date desc" > 我使用这个查询来显示更新字段并且它有效.. 但我需要显示更新中未显示的过期行。我的意思是如果该行显示在更新中,那么它不会显示在过期中。请帮助我
  • 我认为您的查询是错误的,我认为您应该使用两个单独的查询的UNION 来获取您的结果集。你甚至懒得看我的答案吗?
【解决方案4】:

感谢@TimBiegeleisen 的回答。。 我已经尝试过这段代码,它可以工作..

显示“更新”行的代码:

select a.* from tmp a 
inner join
(select user, max(date) as date from tmp group by user)
b on a.user=b.user and a.date=b.date
where year(a.date +interval 1 year) >= year(current_date())
order by a.user

这用于显示“过期”行:

select a.* from tmp a
inner join
(select user, max(date) as date from tmp group by user)
b on a.user=b.user and a.date=b.date
where year(a.date +interval 1 year) < year(current_date())
order by a.user

我希望我的问题和所有的答案可以帮助其他人的问题..

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 1970-01-01
    • 2022-01-19
    相关资源
    最近更新 更多