MySQL - определить данные, которые существуют в данном списке, но отсутствуют в таблице - PullRequest
0 голосов
/ 24 августа 2018

У меня есть таблица my_tab:

+--------+
| tab_id |
+--------+
|    1   |
|    2   |
|   ...  |
|   50   |
|   56   |
|   100  |
+--------+

* Обратите внимание, что у меня нет tab_id = 51, 52, 53, 54 or 55

Теперь у меня есть список идентификаторов.1, 2, 3, 4, ..., 50, 51, 52, 53, 54, 55, 56, ..., 100.

Я хочу знать, какой идентификатор из списка идентификаторов не существует в таблице my_tab.Я имею в виду, что желаемый результат должен быть 51, 52, 53, 54 and 55.

Я думал об использовании временной таблицы, сохраняю в ней list и делаю Left JOIN с my_tab.

Но я не имею права делать это (доступ только для чтения).

Ответы [ 3 ]

0 голосов
/ 24 августа 2018

Вот другой способ без использования CTE -

select n+1 from my_tab
right outer join
(select (d1.n*10 + d2.n) n from (select 1 as n 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 0
 ) d1 cross join
 (select 1 as n 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 0
 ) d2) temp_num
on tab_id = n+1
where tab_id is null
order by n

Вот скрипка - http://www.sqlfiddle.com/#!9/4645be/24

0 голосов
/ 24 августа 2018

хочу узнать, какого идентификатора списка идентификаторов не существует в таблице my_tab.Я имею в виду, что желаемый вывод должен быть 51, 52, 53, 54 и 55.

Я предполагаю, что с текущим примером данных и списком номеров желаемый вывод будет

| number |
|--------|
|      3 |
|      4 |
|     51 |
|     52 |
|     53 |
|     54 |
|     55 | 

Этот запрос допускает пропуски как в списке номеров, так и в табличных данных, как вы видите.

Запрос

SELECT  
 number_list.number
FROM (

  SELECT 
   1 AS number
  UNION 
   SELECT 
     2 AS number   
  UNION
  SELECT 
   3 AS number
  UNION 
  SELECT 
     4 AS number 
  # ...
  # ...
  UNION
  SELECT 
    50 AS number
  UNION 
  SELECT 
    51 AS number 
  UNION
  SELECT 
    52 AS number
  UNION 
  SELECT 
    53 AS number 
  UNION
  SELECT 
    54 AS number
  UNION 
  SELECT 
    55 AS number 
  UNION
  SELECT 
    56 AS number
  UNION 
  # ...
  # ...  
  SELECT 
    100 AS number 

) AS number_list
LEFT JOIN 
 Table1
ON
 number_list.number = Table1.tab_id
WHERE
  Table1.tab_id IS NULL

Результат

| number |
|--------|
|      3 |
|      4 |
|     51 |
|     52 |
|     53 |
|     54 |
|     55 |

см. Демонстрацию http://sqlfiddle.com/#!9/31956e/13

Обновление из-за отсутствия комментариев.

Не думаете ли вы, что список номеров увеличится до 1000, почти невозможно сгенерироватьсписок с использованием только Select или до 10000 в любом случае, в котором я почти уверен, что это будет.

Для более динамичного запроса требуются генератор чисел MySQL и вложенные функции подиндексов.

Запрос генератора чисел, который генерирует числа от 1 до 100.Таким образом, запрос работает только для списка номеров до 100 номеров.Если вам нужно больше, просто добавьте новый

CROSS JOIN ( SELECT 1 AS n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10 ) AS record_<number>

Запрос

SELECT 
 (@row_number := @row_number + 1) AS row_number
FROM (
 SELECT 1 AS n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
) AS record_1
CROSS JOIN (
 SELECT 1 AS n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
) AS record_2
CROSS JOIN (SELECT @row_number := 0) AS init_user_param

см. Демонстрацию http://sqlfiddle.com/#!9/31956e

Используйте вложенные функции SUBSTRING_INDEX для разделения элементов из строки в MySQL.

Запрос

SELECT  
 SUBSTRING_INDEX(
   SUBSTRING_INDEX(
      '1,2,3,4,50,51,52,53,54,55,56,100'
     ,',', 1
   )
   , ','
   , -1
 ) AS number

см. Демонстрацию http://sqlfiddle.com/#!9/340e01/528

Использованиедва метода и получение нужных вам результатов.

Запрос

SELECT 
 number_list.number
FROM ( 

  SELECT
   DISTINCT 
   SUBSTRING_INDEX(
     SUBSTRING_INDEX(
        '1,2,3,4,50,51,52,53,54,55,56,100' #this is the number list
       ,',', number_generator.row_number
     )
     , ','
     , -1
 ) AS number
  FROM ( 
    SELECT 
     (@row_number := @row_number + 1) AS row_number
    FROM (
     SELECT 1 AS n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
    ) AS record_1
    CROSS JOIN (
     SELECT 1 AS n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
    ) AS record_2
    CROSS JOIN (SELECT @row_number := 0) AS init_user_param
  ) AS number_generator 
) AS number_list
LEFT JOIN 
 Table1
ON
 number_list.number = Table1.tab_id
WHERE
  Table1.tab_id IS NULL

см. Демонстрацию http://sqlfiddle.com/#!9/31956e/35

0 голосов
/ 24 августа 2018

Если ваша версия mysql поддерживает cte, вы можете попробовать CTE Recursion создать полную таблицу, используя NOT exists, чтобы проверить, что значение не существует в my_tab таблице.

Вот небольшой пример для вас.

Схема (MySQL v8.0)

create table my_tab(
    tab_id int
);

insert into my_tab values (1);
insert into my_tab values (2);
insert into my_tab values (3);
insert into my_tab values (4);
insert into my_tab values (5);
insert into my_tab values (9);
insert into my_tab values (10);
insert into my_tab values (20);

Запрос # 1

WITH RECURSIVE  cte AS (
  SELECT MIN(tab_id) fromVal,MAX(tab_id) toVal
  FROM my_tab
  UNION ALL
  SELECT (fromVal+1),toVal
  FROM cte
  WHERE fromVal < toVal
)
SELECT fromVal
FROM cte c
WHERE NOT exists
(
  SELECT 1 
  FROM my_tab t1
  WHERE t1.tab_id = c.fromVal
);

| fromVal |
| ------- |
| 6       |
| 7       |
| 8       |
| 11      |
| 12      |
| 13      |
| 14      |
| 15      |
| 16      |
| 17      |
| 18      |
| 19      |

Просмотр на БД Fiddle

ПРИМЕЧАНИЕ

mysql CTE RECURSIVE Глубина по умолчанию 1000.

если вам нужно использовать больше 1000, вы можете попробовать установить значение @@ cte_max_recursion_depth .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...