在Mariadb子查询中LIMIT的行为

时间:2017-12-18 10:03:46

标签: sql mariadb greatest-n-per-group

这是我的问题。

我在SQL查询方面不是很好,所以我希望能够深入了解LIMIT子句的不同行为。我有两个问题。可以说我的表有3列,namedatedate_modified。我每小时修改一次表格,并使用date_modified列对其进行修订。我试图获取针对特定日期2017-12-12修改日期的最后一条记录(最近修改过)。

SELECT * from 
   (SELECT * from table where name in ('name1','name2','name3') 
    and date in ('2017-12-12') order by date_modified desc)
    as tmp_table group by name

SELECT * from 
   (SELECT * from table where name in ('name1','name2','name3') 
    and date in ('2017-12-12') order by date_modified desc LIMIT 100)
    as tmp_table group by name

第一个返回一个表,其中修改的日期是当天最早的记录。第二个是我想要的,它返回最新修改的数据。如果我有一个更大的表,其中name3是第101条记录,则查询无法正常工作。因此,对LIMIT进行硬编码既不可行又不好。

为什么会有区别?订单是否在子查询中不起作用?

*我只是在添加其他信息,因为我自己想到了一个解决方案。

添加:上面的子查询具有相同的行为;即数据按修改日期的降序排序。

date_modifieddate都采用日期时间格式。

2 个答案:

答案 0 :(得分:0)

表是一组无序数据。对于派生表,即子查询,情况也是如此。

首次查询

您可以从表中选择某些记录并对其进行排序。 DBMS可以完全忽略这个ORDER BY子句,因为您只将数据用作子查询。

然后按名称分组。现在我们必须区分两种情况:

  1. name + date在表格中是唯一的。然后你准确地返回你找到的行。 GROUP BY条款将是多余的。
  2. name + date在表格中不是唯一的。但是你select *。这是无效的SQL,因为如果您有一个名称和日期的多行,则不会告诉DBMS要选择哪些值。如果MariaDB让这个漏掉了,那就是DBMS中的一个缺陷。
  3. 根据您的描述,似乎第二种情况适用。您的查询无效。

    第二次查询

    您可以从表格中选择某些记录并对其进行排序,以便应用LIMIT子句。这限制了结果,但DBMS可以自由地以任何顺序输出行,因为您将数据用作子查询。当您按date_modified订购时,您可能会从结果中丢弃一些名称(例如,所有name1和name2的最后一百条记录,然后您当然会忽略name3。

    至于GROUP BY name:关于第一个查询我所说的内容也适用于此。将数据限制为100行没有任何区别。

答案 1 :(得分:0)

这不是你问题的真正答案。请参阅我的其他答案,了解您的查询有什么问题以及您对其行为的假设。

我想你想要的是这个,2017年12月12日每个名字的最新条目:

<击>

<击>
select *
from
(
  select 
    t.*, 
    max(date_modified) over (partition by name) as max_date_modified
  from t
  where name in ('name1', 'name2', 'name3') 
  and date in (date '2017-12-12')
) numbered
where date_modified = max_date_modified
order by name;

<击>

更新:似乎MariaDB还不支持MAX OVERhttps://mariadb.com/kb/en/library/aggregate-functions-as-window-functions/)。因此请改用ROW_NUMBER

select *
from
(
  select 
    t.*, 
    row_number() over (partition by Name order by date_modified desc) as rn
  from t
  where name in ('name1', 'name2', 'name3') 
  and date in (date '2017-12-12')
) numbered
where rn = 1
order by name;