MySQL - 如何只选择具有相同字段值的前X行?

时间:2012-03-18 19:05:26

标签: mysql datetime limit

这是一个简单的表格,用于描述日历中的事件:

Event
--------------------
Id      int
DayId   int         # Foreign key to Day table
Title   varchar(32)
Start   datetime
Finish  datetime

获取一些结果集的任意SELECT语句:

select
    Id,
    DayId,
    Title,
    Start,
    Finish
from Event
where Start > now()
order by Start

上述选择查询将来会返回所有事件,这是不受欢迎的。但是使用limit意味着您需要知道要限制的数量。

我希望能够选择具有相同DayId值的前X行


有助于更好地解释这种情况的一些例子:

示例结果:

Id: 26,   DayId: 08,   Title: "Foo",    Start: "2012-03-19 23:00:00"
Id: 27,   DayId: 08,   Title: "Bar",    Start: "2012-03-20 00:00:00"
Id: 28,   DayId: 09,   Title: "Baz",    Start: "2012-03-21 09:00:00"
Id: 29,   DayId: 10,   Title: "Barbaz", Start: "2012-03-22 11:00:00"
Id: 30,   DayId: 09,   Title: "Fooboo", Start: "2012-03-25 15:00:00"

假设上面的查询返回了这样的结果集,我正在寻找的查询只返回前两个行,因为它们是下一个发生的事件大卫·

但是,在3月19日之后,Start > now()条件将返回不同的结果集:

Id: 28,   DayId: 09,   Title: "Baz",    Start: "2012-03-21 09:00:00"
Id: 29,   DayId: 10,   Title: "Barbaz", Start: "2012-03-22 11:00:00"
Id: 30,   DayId: 09,   Title: "Fooboo", Start: "2012-03-25 15:00:00"

在这种情况下,结果应该只返回第一个行。请注意(出于解释目的),最后一个结果 具有相同的DayId,但由于它由不同的DayId分隔,因此应该忽略它。

5 个答案:

答案 0 :(得分:1)

这可能不是达到预期结果的最佳方式,但它可以起作用:

select
    Id,
    DayId,
    Title,
    Start,
    Finish
from Event
where Start > now(), AND DayId IN (SELECT DayId FROM Event WHERE Start > now() ORDER BY Start)
order by Start

刚才意识到你不能在子查询上使用LIMIT,现在这个答案将不起作用

答案 1 :(得分:1)

尝试一下:

select id, dayid, title start from (
  select id,
    @equal := @equal and dayId = @dayId ShouldReturn,
    @dayId := dayId as dayId,
    title,
    start
  from t, (
    select @dayId := dayid, @equal := true from t
    where start = (
      select min(start) from t
      where start > now()
    )) init
  where start > now()
  order by start
) as final
where ShouldReturn

答案 2 :(得分:1)

据我所知,你希望所有的行都带有"第一个"大卫·。那怎么样呢

SELECT
  e1.Id,
  e1.DayId,
  e1.Title,
  e1.Start,
  e1.Finish
FROM Event e1.
    LEFT JOIN Event e2 ON e2.DayId>e1.DayId AND e2.Start<e1.Start
WHERE e1.DayId = (
    SELECT MIN(DayId) FROM Event WHERE Start > now()
  )
  AND e2.id IS NULL

因此,您将在子查询的所有未来事件中获得第一个DayId,然后获取具有该DayId的所有事件。

答案 3 :(得分:0)

Chevi的答案几乎是完美的。它应该工作,但MySQL有一个限制,即无法在子查询中使用limit。但是一个简单的解决方法是可能的:

select
    Id,
    DayId,
    Title,
    Start,
    Finish
from Event
where Start > now(), 
    and DayId in (

    -- Prepare yourself for a mega-hack!

        select * from (
            select `DayId`
            from Event
            where Start > now
            order by Start
            limit 1

            -- You are allowed a limit here for some reason

        ) alias
    )
order by Start

这个 工作,但是作为表别名的子查询似乎不是一个非常理想的解决方案,所以这个答案不会被标记为已回答,以防有人可以帮助回答问题更好。

答案 4 :(得分:0)

SELECT 
    e.*
FROM 
        Event AS e
    JOIN
        ( SELECT DayId
          FROM Event
          WHERE Start > NOW()
          ORDER BY Start
          LIMIT 1
        ) AS good
      ON  e.Start > NOW()
      AND e.Start < COALESCE(
            ( SELECT Start
              FROM Event
              WHERE Start > NOW()
                AND DayId <> good.DayId
              ORDER BY Start
              LIMIT 1
            )
            , '9999-12-31') 
ORDER BY 
    e.Start

或:

SELECT 
    e.*
FROM 
        Event AS e
    CROSS JOIN
        ( SELECT Start
          FROM 
                Event AS ee
            CROSS JOIN
              ( SELECT DayId
                FROM Event 
                WHERE Start > NOW()
                ORDER BY Start
                LIMIT 1
              ) AS good
          WHERE Start > NOW()
            AND ee.DayId <> good.DayId
          ORDER BY Start
          LIMIT 1
        ) AS bad
WHERE 
    e.Start > NOW()
  AND 
    e.Start < COALESCE(bad.Start, '9999-12-31') 
ORDER BY 
    e.Start