3

I have a table containing calendar items; in my web application, I have two views:

  1. View 1: primary view that shows the next 10 items, starting from now
  2. View 2: view that shows the previous/next 10 items based on the timestamp of the first/last item in view 1. This is the troublemaker.

On the bottom of the page, previous/next links are shown that lead to view 2.

The problem:

How do I retrieve the previous set of 10 items without knowing what date they are?

At first, this seemed quite simple to me, but apparently, it is not.

Database table:

+-------------+------------------+------+-----+---------+----------------+
| Field       | Type             | Null | Key | Default | Extra          |
+-------------+------------------+------+-----+---------+----------------+
| id          | int(11) unsigned | NO   | PRI | NULL    | auto_increment |
| name        | varchar(255)     | YES  | MUL | NULL    |                |
| start_time  | datetime         | YES  |     | NULL    |                |
| end_time    | datetime         | YES  |     | NULL    |                |
| created     | datetime         | NO   |     | NULL    |                |
| updated     | datetime         | YES  |     | NULL    |                |
| deleted     | tinyint(1)       | NO   |     | 0       |                |
+-------------+------------------+------+-----+---------+----------------+

SQL query for showing next 10 items starting from now (no problems here):

SELECT ci.*
FROM `calendar_item` AS `ci` 
WHERE ci.end_time >= NOW()
GROUP BY `ci`.`id` 
ORDER BY `ci`.`end_time` ASC
LIMIT 10

SQL query for showing previous 10 items, based on timestamp of the 1st item in the primary view:

SELECT ci.*
FROM `calendar_item` AS `ci` 
WHERE (ci.id IN (
    SELECT id FROM calendar_item 
    WHERE (end_time < FROM_UNIXTIME(1334667600))
    ORDER BY end_time DESC
))
GROUP BY `ci`.`id` 
ORDER BY `ci`.`end_time` ASC
LIMIT 10

The timestamp is passed via the URL; in view 1 the subquery is not shown at all. The problem lies in the fact that items should be sorted ascending; this would result in the earliest items in the database being returned, instead of the nearest to timestamp. To counter this problem, I created a subquery that sorts descendingly. This subquery works fine when I run it as a normal query, but when contained by the above query, it simply displays the same results as would the following:

SELECT ci.*
FROM `calendar_item` AS `ci` 
WHERE ci.end_time <= 1334667600
GROUP BY `ci`.`id` 
ORDER BY `ci`.`end_time` ASC
LIMIT 10

I am most likely overlooking something, so I could use your help. Thanks in advance.

4

1 に答える 1

1

これは単純なものです。サブクエリを制限します

SELECT ci.*
FROM `calendar_item` AS `ci` 
WHERE (ci.id IN (
    SELECT id FROM calendar_item 
    WHERE (end_time < FROM_UNIXTIME(1334667600))
    ORDER BY end_time DESC
    LIMIT 10
))
GROUP BY `ci`.`id` 
ORDER BY `ci`.`end_time` ASC
LIMIT 10

サブクエリに制限がない場合、タイムスタンプがFROM_UNIXTIMESTAMP未満のすべての行を選択します。次に、ASCを並べ替えて、最初の10、つまり最初の10を選択します。

サブクエリを制限すると、FROM_UNIXTIMEを満たす最高の10が取得され、外部からそれらを選択できます。

別の方法(そして私の好み)は次のとおりです。サブクエリはデータを取得し、外部クエリはデータを吐き出す前にデータを並べ替えるだけです。

SELECT i.*
FROM (
    SELECT ci.*
    FROM calendar_item AS ci
    WHERE ci.end_time < FROM_UNIXTIME(1334667600)
    ORDER BY ci.end_time DESC
    LIMIT 10
) AS i
ORDER BY i.`end_time` ASC
于 2012-04-17T10:26:49.810 に答える