Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Как получить информацию о строках, которых нет в таблице? Попал в странную ситуацию

Автор вопроса: HariОтветов: 3

Я попал в странную ситуацию. Вот,

У нас есть таблица с 2 миллионами записей, где MSISDN имеет строковый тип, уникальный и ненулевой. Меня попросили получить информацию о 300 известных MSISDN, поэтому используемый запрос:

select * from table_name
where msisdn in ('msisdn1','msisdn2',......'msisdn300')

но, к сожалению, приведенный выше запрос возвращает только 200. Как узнать те 100, которых нет, из 300, заданных в запросе?

Я могу использовать только запрос выбора из-за ограниченных привилегий.

Пожалуйста посоветуй.

  • Я думаю, вы можете использовать CONNECT BY ypercubeᵀᴹ 21.01.2012

oracleoracle11goracle10g

Ответы

Ответ 1 · рейтинг 4 · Luke Woodward

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

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

На данный момент ваш запрос выглядит примерно так

SELECT * FROM my_table WHERE id IN ('id1','id2','id3','id4','id5','id6')

Предполагая, что ни в одном из ваших MSISDN нет запятых и/или одинарных кавычек, вы можете сделать следующее:

  • возьмите текст IN (...) части вашего запроса,
  • удалить все одинарные кавычки,
  • поставить запятую в начале и в конце,
  • заключить всю строку в одинарные кавычки.

Список из шести id в моем примере выше станет тогда

',id1,id2,id3,id4,id5,id6,'

Со всеми идентификаторами в одной строке мы можем запустить такой запрос:

VARIABLE ids_string VARCHAR2(4000);
EXEC :ids_string := ',id1,id2,id3,id4,id5,id6,';

WITH comma_posns AS (SELECT level AS comma_pos
                       FROM DUAL
                      WHERE SUBSTR(:ids_string, level, 1) = ','
                       CONNECT BY LEVEL <= LENGTH(:ids_string)),
     starts_ends AS (SELECT comma_pos AS start_pos,
                            LEAD(comma_pos, 1, NULL) OVER (ORDER BY comma_pos)
                                      AS end_pos
                       FROM comma_posns),
     ids AS (SELECT SUBSTR(:ids_string, start_pos + 1, end_pos - start_pos - 1)
                    AS id
               FROM starts_ends
              WHERE end_pos IS NOT NULL)
SELECT id
  FROM ids
 WHERE id NOT IN (SELECT id FROM my_table);

Я поместил список идентификаторов в переменную связывания с именем :ids_string, чтобы я мог ссылаться на него несколько раз в запросе.

Подзапрос comma_posns перечисляет все позиции в строке, в которых появляются запятые. starts_ends затем переставляет это в пары позиций запятых, а затем ids использует эти начальную и конечную позиции, чтобы выбрать идентификаторы из строки. Наконец, мы выбираем все идентификаторы, которые есть в этой строке, но не в таблице.

Я выполнил приведенный выше запрос, используя следующие образцы данных:

SQL> select id from my_table;

ID
--------------------
id1
id1a
id4
id6

Когда я выполнил этот запрос, я получил следующий результат:

ID
--------------------------------------------------------------------------------
id2
id3
id5

Если строка вашего идентификатора особенно длинная (т. е. содержит более 4000 символов), возможно, вам придется разделить ее на части длиной 4000 или менее символов.

Ответ 2 · рейтинг 3 · a_horse_with_no_name

Вы можете создать "виртуальную" таблицу со всеми идентификаторами, которые вы ищете, а затем выполнить внешнее соединение с вашей реальной таблицей.

with to_search as (
    select 'msisdn1' as msisdn from dual
    union all
    select 'msisdn1' from dual
    union all
    select 'msisdn2' from dual
    union all
    select 'msisdn2' from dual
    ...
    (you get the picture)
    ...
    select 'msisdn3000' from dual
)
SELECT s.msisdn,
       nvl(mt.msisdn, 'not found')
FROM to_search s
  LEFT JOIN my_table mt ON mt.msisdn = s.msisdn

Для всех идентификаторов, которых нет в my_table, вы увидите "не найдено".

Ответ 3 · vijikumar

Прежде всего, MSISDN - это первичный ключ (уникальный + ненулевой), поэтому нет никаких шансов быть нулевым.

Вы звоните, используя следующий запрос,

Выберите * из имени таблицы, где MSISDN не является нулевым пределом 300;

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы