Объединение, заменяющее строку, если идентификатор совпадает

#sql #oracle #oracle12c

Вопрос:

У меня есть 2 разные таблицы с одинаковой структурой данных, таблицы A и B, можно ли получить значения из A, а затем из B, где, если запись идентификатора существует в B, она заменяет значение, полученное в A?

Пример:

 select '1' as id, 'Bob' as "user" from dual
union
select '1' as id, 'Alice' as "user" from dual
 

Это возвращает:

 1   Bob
1   Alice
 

Если id то же самое во втором выборе, я хотел бы иметь только одну строку:

 1   Alice
 

Комментарии:

1. Для меня это звучит как что-то вроде внешнего соединения, а не союза.

2. Выполните ОБЪЕДИНЕНИЕ с обновлением.

3. если ваша таблица такова user , нет смысла выполнять union операцию, чтобы получить все идентификаторы с вашим состоянием. Что это значит в первую очередь и во вторую очередь для вас?

4. @Джеймс «пользователь» — это не таблица, это имя столбца. Две таблицы представлены в примере встроенными операторами select, выбирающими из «dual», поскольку Oracle не разрешает оператор select без таблицы.

Ответ №1:

Вместо ОБЪЕДИНЕНИЯ вам нужно «ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ», которое даст вам три типа строк:

  • Строки, в которых обе таблицы имеют совпадающий идентификатор со значениями из обеих таблиц (строки, которые вернет ВНУТРЕННЕЕ СОЕДИНЕНИЕ)
  • Строки, в которых только таблица A имеет этот идентификатор, с нулем для столбцов таблицы B (дополнительные строки, которые вернет ЛЕВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ)
  • Строки, где только таблица B имеет этот идентификатор, с нулем для столбцов таблицы A (дополнительные строки, которые вернет ПРАВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ)

Затем вы можете использовать COALESCE для получения значений из B, если они присутствуют (первый и второй типы строк), и A, если нет (третий тип строк).

Так что для вашего примера:

 Select
    Coalesce(B.id, A.id) as id,
    Coalesce(B."user", A."user") as "user"
From
    (select '1' as id, 'Bob' as "user" from dual) as A
Full Outer Join
    (select '1' as id, 'Alice' as "user" from dual) as B
    On B.id = A.id
 

Который возвращает:

ID пользователь
1 Алиса

(Примечание: протестировано на SQL Server, удалив «из dual», потому что у меня нет базы данных Oracle для тестирования.)

Ответ №2:

Один из способов сделать это -:

 select '1' as id, 'Bob' as "user" from table_A
where id not in (select id from table_B)
union all
select '1' as id, 'Alice' as "user" from table_B
 

Ответ №3:

Вы можете попробовать этот способ, используя ROW_NUMBER() над (РАЗДЕЛ ПО порядку идентификаторов по вкладке), где «вкладка» — это имя таблицы, в этом примере данные из table_a получат приоритет и будут собраны.

 create table table_a as 
(
select '1' as id, 'Bob' as "user" from dual
UNION
select '2' as id, 'Jack' as "user" from dual
) ;

create table table_b as 
(
select '1' as id, 'Alice' as "user" from dual -- table 
UNION
select '3' as id, 'John' as "user" from dual -- table
) ;

select * from (
select ROW_NUMBER() over (PARTITION BY id order by tab) rnum,id, "user"
 from( 
select id, "user", 'A' tab from table_a 
union all
select id, "user", 'b' tab from table_b  
) 
) WHERE RNUM = 1;