MySQL - хитрый LIMIT для каждой проблемы WHERE_IN - PullRequest
1 голос
/ 19 ноября 2008

Я хочу сделать следующее (см. Псевдокод); Я хочу выбрать 4 строки для каждого gd.id (7, 11 или 9). Я неправильно использовал лимит, потому что это всего 4 строки. У кого-нибудь есть идея, как изменить этот запрос для достижения моей цели?

SELECT gd.gid, gd.aid, li.ads, li.til
FROM gd
JOIN li ON li.a_id = gd.aid
WHERE gd.gid
IN (
'7', '11', '9'
)
ORDER BY li.timestamp DESC
LIMIT 4 #FOR EACH ;-)

Спасибо!

Ice

p.s. Может быть, что-то типа group_by?

Ответы [ 2 ]

5 голосов
/ 20 ноября 2008

Хорошо, я публикую второй ответ, теперь, когда я понимаю взаимосвязь между вашими таблицами.

CREATE TABLE gd (
  aid INT AUTO_INCREMENT PRIMARY KEY,
  gid INT
);

INSERT INTO gd (gid) VALUES
  (7), (7), (7),                -- fewer than four rows
  (9), (9), (9), (9),           -- exactly four rows
  (11), (11), (11), (11), (11); -- greater than four rows

CREATE TABLE li (
  a_id INT AUTO_INCREMENT PRIMARY KEY,
  ads VARCHAR(10),
  til VARCHAR(10),
  `timestamp` TIMESTAMP
);

INSERT INTO li (ads, til, `timestamp`) VALUES
  ('foo1', 'bar1', '2008-01-01'),
  ('foo2', 'bar2', '2008-02-01'),
  ('foo3', 'bar3', '2008-03-01'),
  ('foo4', 'bar4', '2008-04-01'),
  ('foo5', 'bar5', '2008-05-01'),
  ('foo6', 'bar6', '2008-06-01'),
  ('foo7', 'bar7', '2008-07-01'),
  ('foo8', 'bar8', '2008-08-01'),
  ('foo9', 'bar9', '2008-09-01'),
  ('foo10', 'bar10', '2008-10-01'),
  ('foo11', 'bar11', '2008-11-01'),
  ('foo12', 'bar12', '2008-12-01');

Таким образом, вы хотите, чтобы первые четыре строки имели значение gd.gid, в зависимости от значения timestamp в связанной таблице li.

SELECT g1.gid, g1.aid, l1.ads, l1.til, l1.`timestamp`
FROM gd AS g1
  INNER JOIN li AS l1 ON (g1.aid = l1.a_id)
  LEFT OUTER JOIN (
    gd AS g2 INNER JOIN li AS l2 ON (g2.aid = l2.a_id)
  ) ON (g1.gid = g2.gid AND l1.`timestamp` <= l2.`timestamp`)
WHERE g1.gid IN ('7', '11', '9')
GROUP BY g1.aid
HAVING COUNT(*) <= 4
ORDER BY g1.gid ASC, l1.`timestamp` DESC;

Вывод следующий:

+------+-----+-------+-------+---------------------+
| gid  | aid | ads   | til   | timestamp           |
+------+-----+-------+-------+---------------------+
|    7 |   3 | foo3  | bar3  | 2008-03-01 00:00:00 | 
|    7 |   2 | foo2  | bar2  | 2008-02-01 00:00:00 | 
|    7 |   1 | foo1  | bar1  | 2008-01-01 00:00:00 | 
|    9 |   7 | foo7  | bar7  | 2008-07-01 00:00:00 | 
|    9 |   6 | foo6  | bar6  | 2008-06-01 00:00:00 | 
|    9 |   5 | foo5  | bar5  | 2008-05-01 00:00:00 | 
|    9 |   4 | foo4  | bar4  | 2008-04-01 00:00:00 | 
|   11 |  12 | foo12 | bar12 | 2008-12-01 00:00:00 | 
|   11 |  11 | foo11 | bar11 | 2008-11-01 00:00:00 | 
|   11 |  10 | foo10 | bar10 | 2008-10-01 00:00:00 | 
|   11 |   9 | foo9  | bar9  | 2008-09-01 00:00:00 | 
+------+-----+-------+-------+---------------------+
0 голосов
/ 22 февраля 2010

обычный подход:

(ВЫБРАТЬ * ИЗ таблицы ГДЕ ключ = X ПРЕДЕЛ 4) СОЮЗ ВСЕХ (ВЫБРАТЬ * ИЗ таблицы ГДЕ ключ = Y ПРЕДЕЛ 4) СОЮЗ ВСЕХ (ВЫБРАТЬ * ИЗ таблицы ГДЕ ключ = Z LIMIT 4) ЗАКАЗАТЬ ПО ... ЛИМИТУ ...

, обратите внимание, он материализует каждый подвыбор в искушаемом, поэтому не очень эффективен, если ваш внешний LIMIT низкий, а внутренние высокие.

...