Получить список значений столбцов имен, которые не являются общими в обеих таблицах? - PullRequest
1 голос
/ 08 июля 2019

недавно я дал интервью, где вопрос был, предположим, есть две таблицы в базе данных.Таблица T1 имеет столбец с именем «name» и несколько других столбцов Таблица T2 также имеет имя столбца «name» и несколько других столбцов

предположим, что таблица T1 имеет значения в столбце name как [n1, n2, n3, n4, n5] и значения в столбце «имя» таблицы T2 равны [n2, n4], тогда выходные данные должны быть [n1, n3, n5], так как n2 и n4 являются общими в обеих таблицах

нам нужночтобы найти список имен, которые не являются общими в обеих таблицах.

Решение, которое я предоставил ему, заключалось в использовании соединения в приведенной ниже форме

select name from table1 where name not in (select t1.name from table1 t1 join table2 t2 on t1.name=t2.name)
UNION
select name from table2 where name not in (select t1.name from table1 t1 join table2 t2 on t1.name=t2.name)

Но он сказал, что еще естьлучшее решение.Я не смог придумать другого и более эффективного решения.Какой еще эффективный способ получить список имен, если таковые имеются?

Ответы [ 8 ]

2 голосов
/ 08 июля 2019

Если столбец ИМЯ не имеет значений NULL, также есть

select distinct(coalesce(a.name, b.name)) name
from table1 a
full join table1 b on a.name = b.name
where a.name is null or b.name is null

(исправлено ГДЕ состояние, извините ...)

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

Использовать FULL OUTER JOIN:

SELECT DISTINCT(COALESCE(t1.NAME, t2.NAME)) AS NAME
  FROM TABLE1 t1
  FULL OUTER JOIN TABLE2 t2
    ON t2.NAME = t1.NAME
  WHERE t1.NAME IS NULL OR
        t2.NAME IS NULL

FULL OUTER JOIN похож на LEFT OUTER JOIN, объединенный с RIGHT OUTER JOIN - он возвращает строки, в которых есть данные в первой таблице, но не во второй,или где эти данные существуют во второй таблице, но не в первой.Вы можете получить тот же эффект, используя

SELECT t1.NAME
  FROM TABLE1 t1
  LEFT OUTER JOIN TABLE2 t2
    ON t2.NAME = t1.NAME
  WHERE t2.NAME IS NULL
UNION
SELECT t2.NAME
  FROM TABLE1 t1
  RIGHT OUTER JOIN TABLE2 t2
    ON t2.NAME = t1.NAME
  WHERE t1.NAME IS NULL

, и на самом деле вышесказанное - то, что вам нужно сделать, если вы используете базу данных, которая не поддерживает синтаксис FULL OUTER JOIN (например, MySQL,в последний раз я смотрел).

Смотрите это dbfiddle

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

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

( выберите имя из таблицы1 объединить всех выберите имя из таблицы2 ) минус ( выберите имя из таблицы1 пересекаться выберите имя из таблицы2 ) ;

С уважением Акаша

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

выберите идентификатор из ((выберите идентификатор из таблицы1) объединить всех (выберите идентификатор из таблицы 2)) как t1 сгруппировать по id, имеющему count (id) = 1

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

Еще одно возможное решение:

Найдите те, которые находятся в первой таблице, но не во второй таблице, используя оператор MINUS (который является реализацией стандарта Oracle EXCEPT). Тогда СОЮЗИТЕ что с теми, кто во втором, а не в первом.

(
  select name
  from t1
  minus 
  select name
  from t2
)  
union all
(
  select name
  from t2
  minus 
  select name
  from t1
);

При такой настройке:

create table t1 
(
  name varchar(10)
);
insert into t1 values ('Arthur');
insert into t1 values ('Zaphod');

create table t2 
(
  name varchar(10)
);

insert into t2 values ('Tricia');
insert into t2 values ('Zaphod');

Возвращает:

NAME  
------
Arthur
Tricia
0 голосов
/ 08 июля 2019

Если вы хотите использовать оператор SET, найдите решение, как показано ниже:

CREATE TABLE TABLE1(NAME VARCHAR2(100));
CREATE TABLE TABLE2(NAME VARCHAR2(100));
INSERT INTO TABLE1 VALUES('A');
INSERT INTO TABLE1 VALUES('B');
INSERT INTO TABLE1 VALUES('C');
INSERT INTO TABLE2 VALUES('A');
INSERT INTO TABLE2 VALUES('B');
INSERT INTO TABLE2 VALUES('D');


SELECT
    NAME
FROM
    (
        SELECT
            NAME
        FROM
            TABLE1
        UNION
        SELECT
            NAME
        FROM
            TABLE2
    )
WHERE
    NAME NOT IN (
        SELECT
            NAME
        FROM
            TABLE1
            JOIN TABLE2 USING ( NAME )
    );

Ура !! * * 1004

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

Я не фанат not in с подзапросами, потому что он ведет себя неожиданно со значениями null. И человек, спрашивающий, должен будет объяснить, что значит «лучше». Ваша версия на самом деле разумна.

Возможно, я подойду к этому с помощью агрегации:

select name
from ((select distinct name, 1 as in_table1, 0 as in_table2
       from table1
      ) union all
      (select distinct name, 0 as in_table1, 0\1 as in_table2
       from table2
      )
     ) t
group by name
having max(in_table1) <> max(in_table2);

В реальном мире у вас, вероятно, будет отдельная таблица со всеми именами. Если так:

select n.*
from names n
where (not exists (select 1 from table1 t1 where t1.name = n.name) and
       exists (select 1 from table2 t2 where t2.name = n.name
      ) or
      (exists (select 1 from table1 t1 where t1.name = n.name) and
       not exists (select 1 from table2 t2 where t2.name = n.name
      );

Обычно это самый быстрый подход, поскольку он не включает в себя агрегирование или удаление дубликатов.

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

Объединить таблицы и вернуть значения, в которых нет счетчика 2:

create table t1 (
  c1 int
);
create table t2 (
  c1 int
);

insert into t1 values ( 1 );
insert into t1 values ( 3 );

insert into t2 values ( 2 );
insert into t2 values ( 3 );

commit;

select c1 only_in_one_table 
from   (
  select 'T1' t, c1 from t1
  union 
  select 'T2' t, c1 from t2
)
group  by c1
having count(*) <> 2;

ONLY_IN_ONE_TABLE   
                   1 
                   2 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...