#mysql
#mysql
Вопрос:
У меня есть такой запрос:
select id from users where id in (1,2,3,4,5)
У меня есть пользователь с идентификаторами 1,3 и 4. То, что я пытаюсь сделать, это получить результаты не найденных идентификаторов. Пример, если у меня есть идентификаторы 1,3 и 4 в таблице, я ожидаю, что будут возвращены 2 и 5, поскольку эти идентификаторы не существуют. Я надеюсь, что это имеет смысл и возможно.
Комментарии:
1. Итак, вы хотите вернуть что-то, чего не существует? Вы можете добиться этого с помощью таблицы чисел.
Ответ №1:
Да, вы можете это сделать. Создайте таблицу и вставьте в нее идентификаторы, которые вы хотите перечислить, следующим образом:
create table enumerate_ids (eid int not null primary key);
insert into enumerate_ids values (1),(2),(3),(4),(5);
Затем выполните объединение с вашей таблицей users, чтобы найти, какой из них не существует.
select eid from enumerate_ids e
where not exists (
select 1 from users where id = e.eid
)
Или вы можете сделать это:
select eid
from enumerate_ids e
left join users u on u.id = e.eid
where u.id is null
Пример: https://dbfiddle.uk/?rdbms=mysql_5.7amp;fiddle=5e1e138aacf5f41a3d5d28e999993ccc
Если вы делаете все это динамически, вы используете код своего приложения для создания временной таблицы, вводите идентификаторы, которые хотите перечислить, или сверяете с таблицей users, выполняете запрос, подобный приведенному выше, получаете результаты, а затем удаляете временную таблицу.
Я думаю, вы могли бы сделать это и с помощью хранимой процедуры, чтобы вы могли передавать ей свои значения, и она выдает идентификаторы, которые не существуют.
Ответ №2:
Мы можем использовать WITH recursive для генерации набора увеличивающихся идентификаторов, а затем выполнить not in operation для таблицы пользователя.
WITH recursive numbers AS (
select 1 as id
union all
select id 1
from numbers
where id < (select max(id) from user))
select id from numbers where id not in (select distinct(id) from user);
Комментарии:
1. Если пользовательская таблица содержит более 1000 строк, вы можете установить
@@cte_max_recursion_depth
более высокое соответствующее число.2. Это хороший пример поиска недостающих данных в последовательном наборе идентификаторов. Очень аккуратно.
Ответ №3:
Сначала создайте числовые представления (или выберите нужный вам размер):
CREATE OR REPLACE VIEW generator_16
AS SELECT 0 n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL
SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL
SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL
SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL
SELECT 12 UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL
SELECT 15;
CREATE OR REPLACE VIEW generator_256
AS SELECT ( ( hi.n << 4 ) | lo.n ) AS n
FROM generator_16 lo, generator_16 hi;
CREATE OR REPLACE VIEW generator_4k
AS SELECT ( ( hi.n << 8 ) | lo.n ) AS n
FROM generator_256 lo, generator_16 hi;
CREATE OR REPLACE VIEW generator_64k
AS SELECT ( ( hi.n << 8 ) | lo.n ) AS n
FROM generator_256 lo, generator_256 hi;
CREATE OR REPLACE VIEW generator_1m
AS SELECT ( ( hi.n << 16 ) | lo.n ) AS n
FROM generator_64k lo, generator_16 hi;
И присоединяет его к таблице users:
SELECT n AS unused_id
FROM generator_16 number
LEFT JOIN users ON users.id=number.n
WHERE users.id IS NULL AND number.n < (SELECT MAX(users.id) FROM test)
Результатом являются строки с неиспользуемыми идентификаторами.
Одно примечание: Вы хотели вернуть несуществующий номер, превышающий максимальный существующий идентификатор, в приведенном выше запросе я увеличил до максимального существующего номера. Вы можете изменить это на const, если хотите.