我想将表
T1
与列T2
上的a,b,c
左连接。
我首先尝试加入所有三列,但它们没有加入,所以现在作为后备,我加入列
a,b
。
我该如何实施?
示例
T1:
+---+---+---+-------+
| a | b | c | mycol |
+---+---+---+-------+
| 1 | 2 | 3 | john |
| 1 | 3 | 4 | cena |
+---+---+---+-------+
T2:
+---+---+---+-------+
| a | b | c | value |
+---+---+---+-------+
| 1 | 2 | 3 | 10 |
| 1 | 3 | | 20 |
+---+---+---+-------+
加入后:
+---+---+---+-------+-------+
| a | b | c | mycol | value |
+---+---+---+-------+-------+
| 1 | 2 | 3 | john | 10 |
| 1 | 3 | 4 | cena | 20 |
+---+---+---+-------+-------+
大概,您需要两个左连接和条件逻辑
select t1.*, coalesce(t20.a, t21.a) a2, coalesce(t20.b, t21.b) b2, coalesce(t20.c, t21.c) c2
from t1
left join t2 t20
on t20.a = t1.a and t20.b = t1.b and t20.c = t1.c
left join t2 t21
on t20.a is null and t21.b = t1.b and t21.c = t1.c
第一个左连接尝试在三列上进行匹配。第二个连接仅在前两列上连接,并且仅当第一个连接返回空时才连接。然后,您可以在
coalesce()
子句中使用 select
来带来相关值。
select t1.*, coalesce(
(select t20.value from t20 where t20.a = t1.a and t20.b = t1.b and t20.c = t1.c),
(select t21.value from t21 where t21.a = t1.a and t21.b = t1.b )) as "value"
from t1
对于第二个内部选择,您必须确保它获得唯一的结果。因此,您可能必须将结果限制为 1,但如何执行此操作取决于您选择的数据库(您没有提及)。
SELECT t1.a, t1.b, t1.c, t1.mycol, t2.value
FROM t1
INNER JOIN t2 ON t1.a=t2.a AND t1.b=t2.b;
另一个简单地根据 t1 连接所有记录的选项:
SELECT t1.a, t1.b, t1.c, t1.mycol, t2.value
FROM t1
LEFT JOIN t2 ON t1.pk=t2.pk;
嗯 - 我通过“加入后备表”来到这里,在更技术性的背景(流量)中寻找有点类似的挑战。就我而言,受此启发的(谢谢大家:-))解决方案可能看起来有点复杂,但唯一正确的解决方案(待定)。抱歉,我会稍微重写(简化?)模型。关键是,您需要一种基于可为空键的“唯一查找”。好的,我的“处理程序”映射是一个“元信息”(准静态查找),在 3 维(不完整矩阵)上具有“权重”(分析信息)。这实际上比OP多了一个,但它显示了方向......对于查找表,您当然希望它有一个主键。但是你只能有一个(部分)唯一键,因为维度是可以为空的(**即将到来?对此的特别评论,避免了退化的零键造成的混乱)。您从一开始就应该有单独的查找表!至少我相信,我的分析师会更好地管理:为我提供(在我的情况下数百万)元数据“包括后备”,并为所有组合代码继承提供主要跳到第 49 行(待定):“不,而是分开的......”
drop schema if exists fallback_join cascade;
create schema fallback_join;
set search_path to fallback_join;
/*
-- https://stackoverflow.com/questions/63702857/sql-join-when-column-is-available-else-join-with-remaining-columns
T1 :
+---+---+---+-------+
| a | b | c | mycol |
+---+---+---+-------+
| 1 | 2 | 3 | john |
| 1 | 3 | 4 | cena |
+---+---+---+-------+
*/
create table trips_weighable( -- just like Informants in the OP, sorry for the renaming.
a integer,
b integer,
c integer,
name text,
primary key(name) -- assumably, but not necessary
);
insert into trips_weighable(a,b,c,name) values
(1,2,3,'john'),
(1,2,4,'cena');
/* deprecated
T2:
+---+---+---+-------+
| a | b | c | value |
+---+---+---+-------+
| 1 | 2 | 3 | 10 |
| 1 | 3 | | 20 |
+---+---+---+-------+
create table trips_weights(
a integer,
b integer,
c integer,
value integer,
-- primary key(?name) -- nope, because NULLABLE, however, we will overcome this, see (*) below
unique (a,b,c)
);
insert into trips_weights(a,b,c,value) values
(1,2,3,10),
(1,2,null,20);
-- nope, rather separate weights_fallback({x}), x in {abc} - all(almost?) combinations
CREATE VIEW trips_weights_abc AS
SELECT * FROM trips_weights WHERE a IS NOT NULL AND b IS NOT NULL AND c IS NOT NULL;
-- ... as a workaround, if it just comes like that, but
-- i rather expect my analyst to "know" whether some "weight" data is fallback on one or more keys:
*/ -- "normal weights"
CREATE TABLE trips_weights_abc(
a integer,
b integer,
c integer,
value integer,
primary key(a,b,c)
-- unique (a,b,c) -- nope, we have something better now
);
insert into trips_weights_abc(a,b,c,value) values
(1,2,3,10);
/* deprecated
CREATE VIEW trips_weights_ab AS
SELECT * FROM trips_weights WHERE a IS NOT NULL AND b IS NOT NULL;
*/
CREATE TABLE trips_weights_ab(
a integer,
b integer,
--! c integer,
value integer,
primary key(a,b) --wo/c
);
insert into trips_weights_ab(a,b,value) values
(1,2,20);
CREATE VIEW trips_weighed AS
SELECT t.*,wabc.value wabc,wab.value AS wab,
--, util.some_fallback_functionality1(wabc,wab,wac,wbc,wa,wb,wc,w(?)), e.g.
COALESCE(wabc.value,wab.value)
FROM trips_weighable t
LEFT JOIN trips_weights_abc wabc ON wabc.a = t.a AND wabc.b = t.b AND wabc.c = t.c
LEFT JOIN trips_weights_ab wab ON wab.a = t.a AND wab.b = t.b
;
select * from trips_weighed;
/*
a | b | c | name | wabc | wab | coalesce
---+---+---+------+------+-----+----------
1 | 2 | 3 | john | 10 | 20 | 10
1 | 2 | 4 | cena | | 20 | 20
*/