Как получить детали для строк, которых нет в таблице?Оказавшись в странной ситуации - PullRequest
1 голос
/ 21 января 2012

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

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

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

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

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

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

Ответы [ 3 ]

4 голосов
/ 21 января 2012

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

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

3 голосов
/ 21 января 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, вы увидите "not found"

0 голосов
/ 21 января 2012

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

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

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

...