Получите лучшие строки на основе нескольких столбцов в MySQL - PullRequest
0 голосов
/ 30 мая 2019

У меня есть таблица, которая выглядит следующим образом:

id | title | value | language
---+-------+-------+---------
1  | a     | 1800  |    NULL
2  | a     | 1900  |    NULL
3  | b     | 1700  |    NULL
4  | b     | 1750  |    NULL 
5  | b     | 1790  |    1
6  | c     | 1892  |    NULL
7  | c     | 1900  |    1
8  | c     | 1910  |    2
9  | d     | 3020  |    NULL

Хотелось бы получить следующий результат:

id | title | value | language
---+-------+-------+---------
2  | a     | 1900  |    NULL
4  | b     | 1750  |    NULL 
5  | b     | 1790  |    1
6  | c     | 1892  |    NULL
7  | c     | 1900  |    1
8  | c     | 1910  |    2
9  | d     | 3020  |    NULL

Смысл в том, чтобы выбрать наибольшее значение в столбце значений для каждого языка каждого заголовка, причем самое большое - самое последнее. Во-вторых, я хотел бы избежать использования агрегатных функций, таких как MAX, DISTINCT или GROUP-BY, поскольку я строю MySQL View с использованием алгоритма MERGE и не хочу в конечном итоге создавать временную таблицу (см. Нижний раздел https://dev.mysql.com/doc/refman/5.6/en/view-algorithms.html).

Пока это работает, но возвращает только наибольшую строку для заголовка:

SELECT t1.title
FROM table t1
LEFT OUTER JOIN table t2
  ON t1.title = t2.title
        AND t1.value < t2.value
WHERE t2.title IS NULL

Как я могу создать тот, который принимает во внимание язык как результаты выше? Thanx.

Ответы [ 3 ]

1 голос
/ 30 мая 2019

Это должно дать вам то, что вы хотите.

SELECT t1.title, t1.value, t1.language
FROM [Table] t1
LEFT OUTER JOIN [Table] t2 ON 
     t1.title = t2.title AND
     (IFNULL(t1.language, '') = IFNULL(t2.language, ''))
WHERE 
     t1.value > t2.value;
1 голос
/ 30 мая 2019

Вы можете сделать это с помощью NOT EXISTS:

select t.*
from tablename t
where not exists (
  select 1 from tablename
  where 
    title = t.title and 
    coalesce(language, 0) = coalesce(t.language, 0) and 
    value > t.value
)

См. Демоверсию .
Результаты:

| id  | title | value | language |
| --- | ----- | ----- | -------- |
| 2   | a     | 1900  | NULL     |
| 4   | b     | 1750  | NULL     |
| 5   | b     | 1790  | 1        |
| 6   | c     | 1892  | NULL     |
| 7   | c     | 1900  | 1        |
| 8   | c     | 1910  | 2        |
| 9   | d     | 3020  | NULL     |
1 голос
/ 30 мая 2019

Этот ответ предполагает, что вы используете MySQL 8+, в котором ваш запрос становится очень простым. MySQL 8 и более поздние версии поддерживают аналитические функции, которые были добавлены с целью решения таких проблем, как эта.

Мы можем попробовать использовать ROW_NUMBER здесь:

WITH cte AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY title, language ORDER BY value DESC) rn
    FROM yourTable
)

SELECT id, title, value, language
FROM cte
WHERE rn = 1;

Демо

Есть способ справиться с этим с более ранними версиями MySQL, но он требует пользовательских переменных и имеет тенденцию быть очень уродливым. Поэтому, возможно, стоит подумать об обновлении, если ожидается, что у вас будет много запросов, похожих на этот.

...