2016-11-11 4 views
1

У меня есть таблица:GROUP_BY, MAX() и only_full_group_by

ID ACCOUNT BALANCE TIME 
1 Bill  10  1478885000 
2 Bill  10  1478885001 
3 James 5  1478885002 
4 Ann  20  1478885003 
5 Ann  15  1478885004 

Я хочу, чтобы получить последнюю версию (в зависимости от времени) баланс нескольких счетов. То есть:

ACCOUNT BALANCE 
Bill  10 
Ann  15 

Я пытаюсь использовать этот SQL:

SELECT ACCOUNT, BALANCE, max(TIME) 
FROM T1 
WHERE ACCOUNT IN ('Bill', 'Ann') 
GROUP BY ACCOUNT 

Я получаю сообщение об ошибке:

1055 - Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'BALANCE' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

Я понимаю ошибку и пробовал разные SQLs, но до сих пор не понимаю, как для извлечения необходимых данных без нескольких запросов.

P.S. Я использую MySQl 5,7

ответ

2
SELECT T1.ACCOUNT, T1.BALANCE, T1.TIME 
FROM T1 
JOIN (SELECT ACCOUNT, max(TIME) as m_time 
     FROM T1 
     WHERE T1.ACCOUNT IN ('Bill', 'Ann') 
     GROUP BY ACCOUNT) T2 
    ON T1.ACCOUNT = T2.ACCOUNT 
AND T1.TIME = T2.m_time 
WHERE T1.ACCOUNT IN ('Bill', 'Ann') 

EDIT: для многократного изменения времени лучше использовать переменные

SQL DEMO: изменить дату Ann быть такой же

SELECT ACCOUNT, BALANCE, TIME 
FROM (
     SELECT ACCOUNT, BALANCE, TIME, 
      @rn := if(ACCOUNT = @acc, 
         @rn + 1, 
         if(@acc := ACCOUNT, 1, 1) as rn     
     FROM T1, (SELECT @rn := 0, @acc:= '') P 
     WHERE ACCOUNT IN ('Bill', 'Ann') 
     ORDER BY ACCOUNT, TIME desc, BALANCE desc 
    ) T 
WHERE T.rn = 1 

OUTPUT

| ACCOUNT | BALANCE |  TIME | 
|---------|---------|------------| 
| Bill |  10 | 1478885001 | 
|  Ann |  20 | 1478885003 | 
+0

@Matt Что относительно размещения на обоих? 'JOIN' быстрее, потому что производная таблица не имеет индекса –

+0

У меня был тот же SQL, но TIME не уникален в моей таблице. Из-за логики приложения я могу иметь несколько строк с тем же временем для учетной записи. в этом случае мне нужна еще одна обертка SELECT с «group_by (ACCOUNT)» и «max (BALANCE)». Есть ли более элегантное решение? –

+0

@VictorMezrin, если TIME может быть дублирующимся, тогда я бы использовал переменные для создания номера строки. Или, может быть, вместо времени ID будет уникальным и всегда будет представлять собой более поздний момент? – Matt

0

У вас есть столбец в вашем отборном, что не в группе

или добавить все столбцы не в агрегированной функции

SELECT ACCOUNT, BALANCE, max(TIME) 
FROM T1 
WHERE ACCOUNT IN ('Bill', 'Ann') 
GROUP BY ACCOUNT, BALANCE 

или изменить sql_mode с помощью

SET sql_mode = '' 

или

SELECT ACCOUNT, BALANCE, TIME 
    FROM T1 
    where id In (
      select id from T1 where (account, time) in (
         select account, max(time) 
         from t1 
         WHERE ACCOUNT IN ('Bill', 'Ann') group by account)) 
+0

Я получу несколько результатов для счета –

+0

@VictorMezrin. в mysql 5.7 использование асимметричной группы по (столбец в элементе select, а не в группе) - это изменение, вы можете превратить mysql в предыдущее поведение, когда значение sql_mode равно ''; как в моем ответе .. в вашей консоли или в вас просто выполните SET sql_mode = ''; – scaisEdge

+0

Я также добавляю запрос для выбора нужных строк – scaisEdge

0

Ошибка довольно ясна. Если вы хотите, последний баланс для каждого счета, вот один из способов:

select t1.* 
from t1 
where t1.time = (select max(tt1.time) from t1 tt1 where t1.account = tt1.account); 

Вы можете добавить where во внешнем запросе фильтрации для определенных учетных записей.

Смежные вопросы