MySQL получает только первое совпадение условий между 3 столбцами

#javascript #mysql #node.js #json #greatest-n-per-group

#javascript #mysql #node.js #json #наибольшее-n-на-группу

Вопрос:

Я работаю с API REST (NodeJS), которые имеют доступ к базе данных MySQL. В этой базе данных есть таблица, которая выглядит следующим образом (назовем ее Table_01):

 | C_0| C_1| C_2| C_3| 
|  1 | A1 | B1 |  1 |
|  2 | A1 | B2 |  0 |
|  3 | B1 | A1 |  0 |
|  4 | A2 | B1 |  0 |
|  5 | B2 | A1 |  1 |
|  6 | B1 | A1 |  0 |
|  7 | B3 | A1 |  0 |
|  8 | A1 | B3 |  1 |
|  9 | A3 | B1 |  0 |
| 10 | A1 | B3 |  1 |
| 11 | A1 | B1 |  0 |
  

Моя цель — получить первое совпадение значения = 1 на C_3 для пары значений в C_1 и C_2.

Давайте приведем пример.

Я хочу знать, в каких случаях A_1 в C_1 имеет 1 в C_3 (только первое совпадение)

Итак, в этом случае результат должен быть:

 A1 B1 1
A1 B3 1
  

В формате JSON:

 result = [
  {
    "C_1": "A1",
    "C_2": "B1",
    "C_3": "1",
  },
  {
    "C_1": "A1",
    "C_2": "B3",
    "C_3": "1",
  }
];  

Я не хочу получать в два раза больше второго, поскольку A1 B3 = 1 включается в таблицу 2 раза.

Я могу получить результат, выполнив это:

 db.query('SELECT * FROM `Table_01` WHERE (`C_1` = A1 AND `C_2` = ' db.escape(value) ') AND `C_3` = 1',
  (err, res) => {
    ..
  }
);  

Но это дало бы мне третью запись с дублированным A1 B3 1.

Очевидно, что в этом примере это не очень важно.. Но с таблицей, полной строк, это важно, чтобы избежать очень больших ответов и последующего фильтра JS.

Комментарии:

1. Термин «первое совпадение» существует только тогда, когда определен (уникальный) порядок. Вам нужен порядок по возрастанию C_0 ?

2. C_0 является ли мой инкрементный уникальный. Я не понимаю, почему это должно быть условием для «первого совпадения». Спасибо

3. Представьте себе, например, неупорядоченную кучу кирпичей. Какой кирпич в этой куче является первым?

4. Хорошо, я понимаю. Я думал, что SQL был упорядочен по умолчанию.

5. Строго назад.

Ответ №1:

Один из подходов использует коррелированный подзапрос для фильтрации:

 select t.*
from table_01 t
where t.id = (
    select min(t1.id) 
    from table_01 t1 
    where t1.c_1 = t.c_1 and t1.c_2 = t.c_2 and t1.c_3 = 1 
)
  

Вы также можете использовать оконные функции, если вы используете MySQL 8.0:

 select *
from (
    select t.*,
        row_number() over(partition by c_1, c_2 order by id) rn
    from mytable t
    where c_3 = 1
) t
where rn = 1
  

Комментарии:

1. Работает идеально. Спасибо. Что касается оконных функций, они быстрее (по производительности), чем первый?

2. Вам нужно будет сравнить это с вашими фактическими данными. Первое решение будет использовать индекс on (c_1, c_2, c_3) .