Проверьте, что значения во всех столбцах разные в SQL - Oracle - PullRequest
1 голос
/ 08 июля 2010

У меня есть таблица с 14 столбцами в Oracle. Все столбцы имеют целочисленный тип. мне нужно проверить, чтобы в двух строках не было одинакового целого числа. Как я могу сделать это с помощью SQL. Или это возможно сделать только с использованием PL / SQL?

Ответы [ 7 ]

4 голосов
/ 09 июля 2010

Проверьте следующие примеры. Сначала я группирую значения в коллекцию. Я использовал встроенный SYS.DBMS_DEBUG_VC2COLL, но лучше, если вы создадите свой выигрыш. Затем я беру эту коллекцию, а затем выполняю MULTISET UNION DISTINCT с пустой коллекцией того же типа. Это удалит дублированные записи.

select * from
 (select sys.dbms_debug_vc2coll(1,2,3) a, 
         sys.dbms_debug_vc2coll(1,2,3) multiset union distinct sys.dbms_debug_vc2coll() b
 from dual)
where a=b;

select * from
 (select sys.dbms_debug_vc2coll(1,2,3,1) a, 
         sys.dbms_debug_vc2coll(1,2,3,1) multiset union distinct sys.dbms_debug_vc2coll() b
 from dual)
where a=b

Наконец, я сравниваю эту коллекцию DISTINCT с оригинальной коллекцией. Если они совпадают, то коллекция уже имеет только уникальные значения.

4 голосов
/ 08 июля 2010

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

3 голосов
/ 08 июля 2010

Вот еще один способ сделать это в SQL. Этот пример для трех столбцов. Вы просто добавляете больше union all select ... предложений, чтобы добавить больше столбцов к чеку. Он вернет ROWID любой строки, для которой общее количество столбцов больше, чем число различных значений.

Я предполагаю, что ни один из столбцов не может содержать значения NULL. Если это проблема, это может дать вам ложные срабатывания.

select rowid,count(*),count(distinct col)
from (
select rowid,col1 col from the_table
  union all
select rowid,col2 col from the_table
  union all
select rowid,col3 col from the_table
)
group by rowid
having count(distinct col) < count(*)
3 голосов
/ 08 июля 2010

если это ограничение данных - тогда я бы поместил его в триггер - и сравнил каждое значение в PLSQL. (я думаю, что это рекомендуется на основе вашего описания)

если это запрос, то у вас будет довольно большое предложение where, проверяющее каждый столбец на соответствие другим.

редактирование:

что-то вроде:

select * from mytable where
( col1=col2 or col1=col3 or col1=col4 or col1=col5 ... )
or
( col2=col3 or col2=col4 or col2=col5 ... )
or
( col3=col4 or col3=col5 ... )
etc...
0 голосов
/ 09 июля 2010

Еще один подход, который будет работать в 9i.Я не даю никаких гарантий производительности, только то, что это чисто SQL-подход, который работает на 9i, но запуск для 10000 строк с 5 столбцами занимает менее секунды, поэтому это разумно.

create table test (
   uniqueKey number, 
   c1 number,
   c2 number,
   c3 number,
   c4 number,
   c5 number) 

Построить несколько тестовых примеров- каждая 4-я строка плохая - мы используем псевдостолу целых чисел

    insert into test 
    select  r,1,2,3,4,CASE WHEN MOD(r,4)=0 THEN 4 ELSE 5 END
    FROM (SELECT rownum r from dual connect by rownum <= 10000);

Теперь преобразуем значения столбца обратно в строки, используя ту же технику псевдотаблицы над последовательностью целых чисел

SELECT uniqueKey,r from
(
    SELECT rownum r from dual connect by rownum <= 100 
/* 100 is the max value in any of our columns */
) numbers,
  test
WHERE r in (c1,c2,c3,c4,c5)

Это дает набор уникальных номеров для каждой строки.

Чтобы найти недопустимые строки, просто проверьте, меньше ли число столбцов

SELECT uniqueKey  from
(
    SELECT rownum r from dual connect by rownum <= 100 /* Our max potential value */
) numbers,
  test
WHERE r in (c1,c2,c3,c4,c5)
GROUP BY uniqueKey
HAVING COUNT(r) < 5

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

0 голосов
/ 08 июля 2010

Если у вас есть только ОДИН возможный дублированный номер, существуют возможные решения с использованием битовых операторов. Если вы используете Oracle 11, вы можете ОТКЛЮЧИТЬ данные столбца в строки,

Предполагается, что на вашем столе есть уникальный ключ с именем UniqueKey

SELECT  UniqueKey,cvalue
FROM
(SELECT *
FROM yourTable
   UNPIVOT INCLUDE NULLS (cvalue FOR check_values IN (col1, col2, col3, col4))
)
GROUP BY UniqueKey,cvalue HAVING count(cvalue) > 1

Это может быть немного синтаксически, поскольку у меня нет тестовой базы данных Ora 11.

До Oracle 11 единственным способом сделать что-то подобное было бы использование типов объектов и pl / sql (функция, для которой задан Id, возвращает список значений столбцов в этой строке как коллекцию, а затем присоединяет эту функцию к Я бы).

Вероятно, проще сделать это в pl / sql (создайте массив, проиндексированный с помощью Integer, для каждого столбца проверяйте .exists (значение) перед установкой - если он существует, у вас есть дубликат). Вызовите функцию один раз для каждого столбца в строке и сбросьте массив между строками.

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

0 голосов
/ 08 июля 2010

Очень грязный, тупой метод .... но он должен работать с 9i

SELECT *
  FROM ( SELECT keyIdentifierField,
                COUNT(testField) AS fieldCount,
                COUNT(DISTINCT testField) AS distinctFieldCount
           FROM ( SELECT keyIdentifierField,
                         col1 AS testField
                    FROM myTable
                  UNION ALL
                  SELECT keyIdentifierField,
                         col2 AS testField
                    FROM myTable
                  UNION ALL
                  SELECT keyIdentifierField,
                         col3 AS testField
                    FROM myTable
                  ...
                  UNION ALL
                  SELECT keyIdentifierField,
                         col14 AS testField
                    FROM myTable
                )
          GROUP BY keyIdentifierField
       )
 WHERE fieldCount <> distinctFieldCount
...