2013-03-04 4 views
5

У меня есть таблица, из которой я пытаюсь получить самую последнюю позицию для каждой ценной бумаги:Groupwise максимум

Таблица:

Мой запрос для создания таблицы: SELECT id, security, buy_date FROM positions WHERE client_id = 4

+-------+----------+------------+ 
| id | security | buy_date | 
+-------+----------+------------+ 
| 26 | PCS  | 2012-02-08 | 
| 27 | PCS  | 2013-01-19 | 
| 28 | RDN  | 2012-04-17 | 
| 29 | RDN  | 2012-05-19 | 
| 30 | RDN  | 2012-08-18 | 
| 31 | RDN  | 2012-09-19 | 
| 32 | HK  | 2012-09-25 | 
| 33 | HK  | 2012-11-13 | 
| 34 | HK  | 2013-01-19 | 
| 35 | SGI  | 2013-01-17 | 
| 36 | SGI  | 2013-02-16 | 
| 18084 | KERX  | 2013-02-20 | 
| 18249 | KERX  | 0000-00-00 | 
+-------+----------+------------+ 

I возились с версиями запросов на основе this page, но я не могу получить результат, который я ищу.

Вот что я пытался:

SELECT t1.id, t1.security, t1.buy_date 
FROM positions t1 
WHERE buy_date = (SELECT MAX(t2.buy_date) 
        FROM positions t2 
        WHERE t1.security = t2.security) 

Но это просто возвращает меня:

+-------+----------+------------+ 
| id | security | buy_date | 
+-------+----------+------------+ 
| 27 | PCS  | 2013-01-19 | 
+-------+----------+------------+ 

Я пытаюсь получить максимальную/последнюю дату покупки для каждой ценной бумаги, так результаты будут иметь одну строку для каждой безопасности с самой последней датой покупки. Любая помощь приветствуется.

EDIT: Идентификатор позиции должен быть возвращен с максимальной датой покупки.

+0

@Hogan Наверное так. У меня не было такого требования какое-то время, ваше, конечно, гораздо правильнее. –

+0

Пожалуйста, отредактируйте этот вопрос со всеми подробностями, которые вы указали в комментариях. Это сделало бы это немного яснее. – Marian

ответ

13

Вы можете использовать этот запрос. Вы можете добиться результатов на 75% меньше времени. Я проверил с большим набором данных. Суб-запросы занимают больше времени.

SELECT p1.id, 
     p1.security, 
     p1.buy_date 
     FROM positions p1 
left join 
      positions p2 
       on p1.security = p2.security 
        and p1.buy_date < p2.buy_date 
     where 
     p2.id is null; 

SQL-Fiddle link

+1

Насколько я понимаю, это лучший ответ, и хотя предыдущий, как и ответ, более эффективен. Хорошая работа. –

+0

Спасибо @Grep за ваши приятные слова :) Его всегда приятно слышать такое поощрение. :) –

+0

@VishalZanzrukia Ваш ответ лучший, и я обновил выбранный ответ на ваш, учитывая тот же результат с гораздо большей эффективностью. – Tomanow

1
select security, max(buy_date) group by security from positions; 

все, что нужно, чтобы получить максимальную дату покупки для каждой ценной бумаги (когда вы говорите вслух, что вы хотите от запроса и включить фразу «для каждого х», вы, вероятно, хотите группу, по й)

Если вы используете group by, все столбцы в выбранном вами столбце должны быть либо столбцами, которые были сгруппированы, либо объединены, поэтому, если, например, вы хотели включить идентификатор, вам, вероятно, придется использовать подобный подзапрос к тому, что у вас было до этого, поскольку, похоже, не существует какой-либо совокупности, которую вы можете разумно использовать для идентификаторов, а другая группа даст вам слишком много строк.

+2

Какую таблицу вывести? – hjpotter92

+1

lol, это было бы важно! – Colleen

+1

@Colleen - теперь неправильный порядок :( – Hogan

5

Это делается простой группой. Вы хотите группировать по ценным бумагам и получать максимальную сумму buy_date. SQL:

SELECT security, max(buy_date) 
from positions 
group by security 

Заметим, что это быстрее, чем bluefeet's answer, но не отображает идентификатор.

+1

@Tomanow Вы также хотите вернуть 'id'? – Taryn

+1

Это не возвращает тот же формат вывода, что и OP. – Marian

+0

@Marian - этот вывод был показан как неправильный результат, а не желаемый результат. – Hogan

9

Вы можете использовать подзапрос, чтобы получить результат:

SELECT p1.id, 
    p1.security, 
    p1.buy_date 
FROM positions p1 
inner join 
(
    SELECT MAX(buy_date) MaxDate, security 
    FROM positions 
    group by security 
) p2 
    on p1.buy_date = p2.MaxDate 
    and p1.security = p2.security 

См SQL Fiddle with Demo

Или вы можете использовать следующее с WHERE пункта:

SELECT t1.id, t1.security, t1.buy_date 
FROM positions t1 
WHERE buy_date = (SELECT MAX(t2.buy_date) 
        FROM positions t2 
        WHERE t1.security = t2.security 
        group by t2.security) 

См SQL Fiddle with Demo

+0

Это тоже очень полезно. Спасибо за вход @bluefeet – Tomanow

+1

@Tomanow Разница в том, что это вернет 'id', который связан с' max (buy_date) ' – Taryn

+0

@bluefeet. Я фильтрую client_id = 4, о котором я не упоминал, поскольку таблица возвратите тысячи строк, если я этого не сделаю. Когда я добавляю свой фильтр к вашим запросам, я все равно получаю только одну запись, которая представляет собой строку PCS из моего исходного сообщения. – Tomanow

2

Ответ от @bluefeet есть еще два способа получить желаемые результаты - и первый, вероятно, будет более эффективен, чем ваш запрос.

Я не понимаю, почему вы говорите, что ваш запрос не работает. Это выглядит очень хорошо и возвращает ожидаемый результат.Испытано на SQL-Fiddle

SELECT t1.id, t1.security, t1.buy_date 
FROM positions t1 
WHERE buy_date = (SELECT MAX(t2.buy_date) 
        FROM positions t2 
        WHERE t1.security = t2.security) ; 

Если проблемы появляется, когда вы добавляете условие client_id = 4, то это потому, что вы добавляете его только в одном WHERE пункте в то время как вы должны добавить его в обоих:

SELECT t1.id, t1.security, t1.buy_date 
FROM positions t1 
WHERE client_id = 4 
    AND buy_date = (SELECT MAX(t2.buy_date) 
        FROM positions t2 
        WHERE client_id = 4 
        AND t1.security = t2.security) ; 
Смежные вопросы