União de duas tabelas com número diferente de colunas

106

Eu tenho duas tabelas (Tabela A e Tabela B).

Eles têm um número diferente de colunas - digamos que a Tabela A tem mais colunas.

Como posso unir essas duas tabelas e obter null para as colunas que a Tabela B não possui?

Jack Kada
fonte

Respostas:

215

Adicione colunas extras como nulas para a tabela com menos colunas como

Select Col1, Col2, Col3, Col4, Col5 from Table1
Union
Select Col1, Col2, Col3, Null as Col4, Null as Col5 from Table2
Kangkan
fonte
6
Existe uma maneira de preencher um valor padrão para a coluna Null?
Hans
3
@Hans: Você pode fazer algo como isnull (ColumnName, 0) como ColumnName ou isnull (ColumnName, '-') como ColumnName ou algo semelhante.
Kangkan
3
Percebi que essa solução também funciona sem ter que listar todas as colunas. Portanto, em vez de Select Col1, Col2, Col3, Null as Col4, Null as Col5 from Table2, também se pode fazer Select *, Null as Col4, Null as Col5 from Table2,.
Pratik Patel
Para o valor nulo, este hack funcionou para mim: 'SomeString' as DummyColumn. Basicamente, você apenas substitui NULL por algum valor. Isso também funcionou quando usado com groupby.
Saurabh Jain
8

Eu vim aqui e segui a resposta acima. Mas a incompatibilidade na ordem do tipo de dados causou um erro. A descrição abaixo de outra resposta será útil.

Os resultados acima são iguais à sequência de colunas da sua tabela? porque oracle é estrito na ordem das colunas. este exemplo abaixo produz um erro:

create table test1_1790 (
col_a varchar2(30),
col_b number,
col_c date);

create table test2_1790 (
col_a varchar2(30),
col_c date,
col_b number);

select * from test1_1790
union all
select * from test2_1790;

ORA-01790: a expressão deve ter o mesmo tipo de dados da expressão correspondente

Como você pode ver, a causa raiz do erro está na ordem de coluna incompatível que está implícita no uso de * como especificador de lista de coluna. Esse tipo de erro pode ser facilmente evitado inserindo a lista de colunas explicitamente:

selecione col_a, col_b, col_c de test1_1790 union all selecione col_a, col_b, col_c de test2_1790; Um cenário mais frequente para esse erro é quando você inadvertidamente troca (ou muda) duas ou mais colunas na lista SELECT:

select col_a, col_b, col_c from test1_1790
union all
select col_a, col_c, col_b from test2_1790;

OU se o acima não resolver seu problema, que tal criar um ALIAS nas colunas como esta: (a consulta não é a mesma que a sua, mas o ponto aqui é como adicionar um alias na coluna).

SELECT id_table_a, 
       desc_table_a, 
       table_b.id_user as iUserID, 
       table_c.field as iField
UNION
SELECT id_table_a, 
       desc_table_a, 
       table_c.id_user as iUserID, 
       table_c.field as iField
Anand Varkey Philips
fonte
Tive que usar a mesma coisa, mas adicionei a.col_name e b.col_name para colunas não nulas. Para colunas nulas, tive que usar: NULL AS nome_coluna1, NULL AS nome_coluna2, etc
Scott R
1
note SELECT * UNION pode ser encadeado várias vezes; observe que os filtros WHERE podem ser usados ​​em todas as cláusulas SELECT
mirekphd
1

Normalmente, você precisa ter o mesmo número de colunas ao usar operadores baseados em conjuntos, então a resposta de Kangkan está correta.

SAS SQL tem um operador específico para lidar com esse cenário:

SAS (R) 9.3 Guia do usuário do procedimento SQL

CORRESPONDING (CORR) Palavra-chave

A palavra-chave CORRESPONDING é usada apenas quando um operador de conjunto é especificado. CORR faz com que PROC SQL corresponda às colunas em expressões de tabela por nome e não por posição ordinal. As colunas que não correspondem por nome são excluídas da tabela de resultados, exceto para o operador OUTER UNION.

SELECT * FROM tabA
OUTER UNION CORR
SELECT * FROM tabB;

Para:

+---+---+
| a | b |
+---+---+
| 1 | X |
| 2 | Y |
+---+---+

OUTER UNION CORR

+---+---+
| b | d |
+---+---+
| U | 1 |
+---+---+

<=>

+----+----+---+
| a  | b  | d |
+----+----+---+
|  1 | X  |   |
|  2 | Y  |   |
|    | U  | 1 |
+----+----+---+

U-SQL oferece suporte a conceitos semelhantes:

UNIÃO EXTERNA POR NOME EM (*)

EXTERIOR

requer a cláusula BY NAME e a lista ON. Ao contrário das outras expressões definidas, o esquema de saída de OUTER UNION inclui as colunas correspondentes e não correspondentes de ambos os lados. Isso cria uma situação em que cada linha proveniente de um dos lados tem "colunas ausentes" que estão presentes apenas no outro lado. Para tais colunas, os valores padrão são fornecidos para as "células ausentes". Os valores padrão são nulos para tipos anuláveis ​​e o valor padrão .Net para os tipos não anuláveis ​​(por exemplo, 0 para int).

POR NOME

é necessário quando usado com OUTER. A cláusula indica que a união está combinando valores não com base na posição, mas no nome das colunas. Se a cláusula BY NAME não for especificada, a correspondência é feita posicionalmente.

Se a cláusula ON incluir o símbolo “*” (ele pode ser especificado como o último ou único membro da lista), então as correspondências de nomes extras além daquelas na cláusula ON são permitidas e as colunas do resultado incluem todas as colunas correspondentes na ordem eles estão presentes no argumento esquerdo.

E código:

@result =    
    SELECT * FROM @left
    OUTER UNION BY NAME ON (*) 
    SELECT * FROM @right;

EDITAR:

O conceito de união externa é suportado por KQL :

tipo:

interno - o resultado possui o subconjunto de colunas que são comuns a todas as tabelas de entrada.

externo - o resultado contém todas as colunas que ocorrem em qualquer uma das entradas. As células que não foram definidas por uma linha de entrada são definidas como nulas.

Exemplo:

let t1 = datatable(col1:long, col2:string)  
[1, "a",  
2, "b",
3, "c"];
let t2 = datatable(col3:long)
[1,3];
t1 | union kind=outer t2;

Resultado:

+------+------+------+
| col1 | col2 | col3 |
+------+------+------+
|    1 | a    |      |
|    2 | b    |      |
|    3 | c    |      |
|      |      |    1 |
|      |      |    3 |
+------+------+------+

demo

Lukasz Szozda
fonte
Alguma ideia de como conseguir isso no SQL ??
KetanVaghasiya
@KetanVaghasiya Até onde eu sei, apenas SAS SQL e U-SQL suportam esse conceito.
Lukasz Szozda
-1

se apenas 1 linha, você pode usar join

Select t1.Col1, t1.Col2, t1.Col3, t2.Col4, t2.Col5 from Table1 t1 join Table2 t2;
Sai Sai
fonte
Uma união de duas tabelas de 1 linha (duas relações multiset, cada uma com uma tupla) teria duas linhas (tuplas) na relação resultante. Na álgebra relacional (que não é o SQL), o resultado da união pode ser uma linha, embora apenas se as duas relações de entrada contiverem uma tupla idêntica, por exemplo. auto-união de uma relação de uma tupla.
Robert Monfera