Как исключить значения в Oracle-SQL-Table, которые означают одно и то же? - PullRequest
3 голосов
/ 13 августа 2010

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

ID  |  Val1  |  Val2
---------------------
1   |    1   |   2
2   |    1   |   3
3   |    2   |   1
4   |    2   |   3
5   |    3   |   1
6   |    3   |   2

Теперь моя проблема в том, что 1 - 2 означает то же самое, что и 2 - 1 (посмотрите @ ID 1 и ID 3, например), и яЯ хочу исключить все записи, где значение 1 - значение 2 означает то же самое, что значение 2 - значение 1 (надеюсь, вы могли бы следовать моей логике здесь).

Ответы [ 4 ]

2 голосов
/ 14 августа 2010

Как насчет этого:

DELETE t
 WHERE ID IN 
       (SELECT t1.id
          FROM t t1 JOIN t t2 
                      ON (t1.val1 = t2.val2 AND 
                          t1.val2 = t2.val1 AND 
                          t1.id < t2.id));

Я произвольно сохранил строку с наибольшим значением идентификатора.

Пример:

SQL> CREATE TABLE t (ID INTEGER, val1 INTEGER, val2 INTEGER);

Table created
SQL> INSERT INTO t VALUES(1,1,2);

1 row inserted
SQL> INSERT INTO t VALUES(2,1,3);

1 row inserted
SQL> INSERT INTO t VALUES(3,2,1);

1 row inserted
SQL> INSERT INTO t VALUES(4,2,3);

1 row inserted
SQL> INSERT INTO t VALUES(5,3,1);

1 row inserted
SQL> INSERT INTO t VALUES(6,3,2);

1 row inserted
SQL> INSERT INTO t VALUES(7,4,4);

1 row inserted
SQL> INSERT INTO t VALUES(8,4,4);

1 row inserted
SQL> SELECT * FROM t;

 ID VAL VAL
--- --- ---
  1   1   2
  2   1   3
  3   2   1
  4   2   3
  5   3   1
  6   3   2
  7   4   4
  8   4   4

8 rows selected
SQL> DELETE t
  2   WHERE ID IN (SELECT t1.id
  3                  FROM t t1 JOIN t t2 ON (t1.val1 = t2.val2 AND t1.val2 = t2.val1 AND t1.id < t2.id));

4 rows deleted
SQL> SELECT * FROM t;

 ID VAL VAL
--- --- ---
  3   2   1
  5   3   1
  6   3   2
  8   4   4

SQL> 

Легко адаптируется для сохранения разных строкНапример,

DELETE t
 WHERE ID IN 
       (SELECT t1.id
          FROM t t1 JOIN t t2 
                      ON (t1.val1 = t2.val2 AND 
                          t1.val2 = t2.val1 AND 
                          (t2.val1 < t1.val1 OR (t2.val1 = t1.val1 AND t2.id > t1.id))));

ОБНОВЛЕНИЕ: Не могу придумать действительно умного пути, поэтому вот метод грубой силы, чтобы ответить на вопрос в вашем комментарии:

CREATE TABLE t (ID INTEGER, val1 INTEGER, val2 INTEGER, val3 INTEGER);

INSERT INTO t VALUES (1, 1, 2, 3);
INSERT INTO t VALUES (2, 1, 3, 2);
INSERT INTO t VALUES (3, 2, 1, 3);
INSERT INTO t VALUES (4, 2, 3, 1);
INSERT INTO t VALUES (5, 3, 1, 2);
INSERT INTO t VALUES (6, 3, 2, 1);
INSERT INTO t VALUES (7, 1, 2, 4);
INSERT INTO t VALUES (8, 1, 3, 5);
INSERT INTO t VALUES (9, 1, 4, 2);
INSERT INTO t VALUES (10, 1, 1, 1);
INSERT INTO t VALUES (11, 1, 1, 1);
INSERT INTO t VALUES (12, 1, 3, 5);

SQL> select * from t order by id;

 ID VAL VAL VAL
--- --- --- ---
  1   1   2   3
  2   1   3   2
  3   2   1   3
  4   2   3   1
  5   3   1   2
  6   3   2   1
  7   1   2   4
  8   1   3   5
  9   1   4   2
 10   1   1   1
 11   1   1   1
 12   1   3   5

12 rows selected

DELETE FROM t 
 WHERE ID IN (SELECT t1.ID FROM t t1 JOIN t t2 ON (t1.val1 = t2.val1 AND 
                                                   t1.val2 = t2.val2 AND 
                                                   t1.val3 = t2.val3 AND t1.id < t2.id)
              UNION ALL
              SELECT t1.ID FROM t t1 JOIN t t2 ON (t1.val1 = t2.val1 AND 
                                                   t1.val2 = t2.val3 AND 
                                                   t1.val3 = t2.val2 AND t1.id < t2.id)
              UNION ALL 
              SELECT t1.ID FROM t t1 JOIN t t2 ON (t1.val1 = t2.val2 AND 
                                                   t1.val2 = t2.val1 AND 
                                                   t1.val3 = t2.val3 AND t1.id < t2.id)
              UNION ALL 
              SELECT t1.ID FROM t t1 JOIN t t2 ON (t1.val1 = t2.val2 AND 
                                                   t1.val2 = t2.val3 AND 
                                                   t1.val3 = t2.val1 AND t1.id < t2.id)
              UNION ALL 
              SELECT t1.ID FROM t t1 JOIN t t2 ON (t1.val1 = t2.val3 AND 
                                                   t1.val2 = t2.val1 AND 
                                                   t1.val3 = t2.val2 AND t1.id < t2.id)
              UNION ALL 
              SELECT t1.ID FROM t t1 JOIN t t2 ON (t1.val1 = t2.val3 AND 
                                                   t1.val2 = t2.val2 AND 
                                                   t1.val3 = t2.val1 AND t1.id < t2.id));

select * from t order by id;

 ID VAL VAL VAL
--- --- --- ---
  6   3   2   1
  9   1   4   2
 11   1   1   1
 12   1   3   5
0 голосов
/ 13 августа 2010

Я не помню, действителен ли этот синтаксис в Oracle или нет (в основном это использование псевдонима для субъекта DELETE), но вы можете попробовать это:Столбцы, кажется, не имеют значения, я бы принял произвольное решение и добавил бы к таблице ограничение, чтобы проверить, что val1

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

0 голосов
/ 13 августа 2010
delete from YourTable
   where (Val1, Val2)
      in (select Val2, Val1 from YourTable where Val1 > Val2)

Здесь есть угловой шкаф, с которым плохо разбираются Это тот случай, когда Val1 и Val2 равны. Удалить все вхождения таких строк, кроме одного, немного сложнее. У кого-нибудь есть идеи?

0 голосов
/ 13 августа 2010

Если удалить означает, что не показывает, попробуйте это, это не будет возвращать строки для этих условий

...