Как выбрать всю запись при использовании MAX () с GROUP BY - PullRequest
3 голосов
/ 19 декабря 2009

Используя MYSQL, я хотел бы провести рефакторинг следующего оператора SELECT, чтобы получить всю запись , содержащую самые новые invoice_date:

> SELECT id, invoice, invoice_date
  FROM invoice_items
  WHERE lot = 1047

id    invoice_id   invoice_date
-----------------------------------
3235    1047         2009-12-15 11:40:00
3295    1047         2009-12-15 16:00:00
3311    1047         2009-12-15 09:30:00
3340    1047         2009-12-15 13:50:00

Использование агрегатной функции MAX () и предложения GROUP BY помогает мне в этом:

> SELECT id, invoice_id, max(invoice_date)
  FROM invoice_items
  WHERE invoice_id = 1047
  GROUP BY invoice_id


id    invoice_id   invoice_date
-----------------------------------
3235    1047         2009-12-15 16:00:00

Обратите внимание, что запрос, кажется, правильно получает MAX(invoice_date), но возвращаемое id (3235) - это не id записи, содержащей MAX(invoice_date) (3295), это id Первая запись в начальном запросе.

Как мне провести рефакторинг этого запроса, чтобы получить полную запись , содержащую MAX(invoice_date)?

Решение должно использовать предложение GROUP BY, потому что мне нужно получить новейшие invoice_date для каждого счета.

Ответы [ 5 ]

7 голосов
/ 19 декабря 2009

Это часто повторяемая проблема "наибольший n на группу".

Вот как бы я решил это в MySQL:

SELECT i1.*
FROM invoice_items i1
LEFT OUTER JOIN invoice_items i2
  ON (i1.invoice_id = i2.invoice_id AND i1.invoice_date < i2.invoice_date)
WHERE i2.invoice_id IS NULL;

Объяснение: для каждой строки i1 попытайтесь найти строку i2 с той же invoice_id и большей датой. Если ничего не найдено (т. Е. i2 - все нули из-за внешнего соединения), то i1 должна быть строкой с наибольшей датой для invoice_id.

Это решение, использующее объединение, работает лучше для MySQL, что плохо при оптимизации как GROUP BY, так и подзапросов.

3 голосов
/ 19 декабря 2009

Я предполагаю, что, поскольку имя таблицы - invoice_items, для данного счета будет несколько строк, поэтому вам, вероятно, следует использовать что-то вроде этого:

SELECT * FROM invoice_items 
WHERE invoice_date IN (SELECT MAX(invoice_date) FROM invoice_items)

Если вас не интересуют две записи с одинаковой датой выставления счета, вы можете просто сделать это:

SELECT * FROM invoice_items
ORDER BY invoice_date DESC
LIMIT 1
2 голосов
/ 19 декабря 2009

Вот моя попытка:

SELECT t1.*
FROM INVOICE_ITEMS t1,
   (SELECT INVOICE_ID, MAX(INVOICE_DATE) as invoice_date2
      FROM INVOICE_ITEMS
     GROUP BY INVOICE_ID) t2
WHERE t1.invoice_id = t2.invoice_id
AND t1.invoice_date = t2.invoice_date2
2 голосов
/ 19 декабря 2009

почти так же, как вы говорите по-английски

«Получите мне счет с последней датой выставления счета»

Select * From invoice_items
Where invoice_date =
   (Select Max(invoice_date)
    From invoice_items)

Но что-то не так в вашей схеме, я думаю. Поскольку существует несколько строк с одним и тем же Invoice_Id, это выглядит как таблица деталей счета-фактуры или таблицы позиций счета-фактуры (а не таблица счетов-фактур). И если да, то как у каждой позиции в одном и том же счете-фактуре могут быть разные «InvoiceDates»? Если они разные, то они не являются датами счета-фактуры, они являются датами детализации счета-фактуры (что бы это ни значило) и должны иметь такую ​​маркировку ... 1006 *

0 голосов
/ 19 декабря 2009
SELECT * 
FROM invoice_items
WHERE lot = 1047
ORDER BY invoice_date desc LIMIT 1

или лучше, если ваш идентификатор является вашим основным ключом и постоянно растет

SELECT * 
FROM invoice_items
WHERE lot = 1047
ORDER BY id desc LIMIT 1
...