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

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

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

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

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

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

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


person Hari    schedule 21.01.2012    source источник
comment
Я думаю, вы можете использовать CONNECT BY   -  person ypercubeᵀᴹ    schedule 21.01.2012


Ответы (3)


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

Во-первых, я не верю, что есть какой-то способ найти, какие элементы в предложении 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 или менее символов.

person Luke Woodward    schedule 21.01.2012

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

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, вы увидите «не найдено».

person a_horse_with_no_name    schedule 21.01.2012

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

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

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

person vijikumar    schedule 21.01.2012
comment
Предлагаемый запрос не дает требуемых результатов - person Hari; 21.01.2012