如何连接具有相同主键名称但不同值的两个表
How to join two tables with same primary key name but different values
我今天了解了“独家实体”。我有以下 ER 图:
拥有 2 个专属实体。当我通过 power designers 创建工具创建物理数据模型时,它解析为
现在我想将两者合二为一 table 并显示 id 和 room_name
我要得到的结构是:
room_id | room_name
房间和卧室的room_id不一样。例如,卧室的 ID 为 1-10,厨房的 ID 为 11-20。
我觉得我的设计可能不好,因为我尝试的连接没有得到我想要的结果。
我最好的猜测是使用像*
这样的自然连接
SELECT room_id, room_name
FROM bedroom
NATURAL JOIN kitchen;
这 returns 格式正确,但结果为空。
此外,我希望获得格式为 table 的
room_id | roon_name | bedCount | chairCount
您可以将两个表合并在一起,例如:
select room_id, room_name
from bedroom
union
select room_id,room_name
from kitchen
您不能加入他们,因为您在加入 table 的 table 之间没有任何共同点。您需要做的是为 table 提供一个它们可以加入的公共列;例如一个房间将在建筑物中,因此创建一个 buildings
table 然后每个 rooms
应该包含一个指向包含建筑物的外键。
即
CREATE TABLE buildings (
id INT
GENERATED ALWAYS AS IDENTITY
CONSTRAINT buildings__id__pk PRIMARY KEY,
name VARCHAR2(20)
NOT NULL
);
CREATE TABLE rooms (
id INT
GENERATED ALWAYS AS IDENTITY
CONSTRAINT rooms__id__pk PRIMARY KEY,
building_id INT
NOT NULL
CONSTRAINT rooms__building_id__fk REFERENCES buildings (id),
room_name VARCHAR2(20)
NOT NULL,
CONSTRAINT rooms__id__rn__u UNIQUE ( id, room_name )
);
CREATE TABLE kitchens (
id INT
CONSTRAINT kitchens__id__pk PRIMARY KEY,
room_name VARCHAR2(20)
GENERATED ALWAYS AS ( 'kitchen' )
NOT NULL,
chairCount INT,
CONSTRAINT kitchens__id__rn__fk
FOREIGN KEY ( id, room_name ) REFERENCES rooms ( id, room_name )
);
CREATE TABLE bedrooms (
id INT
CONSTRAINT bedrooms__id__pk PRIMARY KEY,
room_name VARCHAR2(20)
GENERATED ALWAYS AS ( 'bedroom' )
NOT NULL,
bedCount INT,
CONSTRAINT bedrooms__id__rn__fk
FOREIGN KEY ( id, room_name ) REFERENCES rooms ( id, room_name )
);
那么,如果您:
INSERT INTO buildings ( id, name ) VALUES ( DEFAULT, 'Building1' );
INSERT INTO rooms ( id, building_id, room_name ) VALUES ( DEFAULT, 1, 'kitchen' );
INSERT INTO rooms ( id, building_id, room_name ) VALUES ( DEFAULT, 1, 'bedroom' );
INSERT INTO kitchens ( id, chairCount ) VALUES ( 1, 42 );
INSERT INTO bedrooms ( id, bedCount ) VALUES ( 2, 13 );
然后:
SELECT b.id AS building_id,
b.name AS building_name,
rk.id AS kitchen_id,
k.chairCount,
rb.id AS bedroom_id,
br.bedCount
FROM buildings b
LEFT OUTER JOIN rooms rk
ON ( b.id = rk.building_id AND rk.room_name = 'kitchen' )
LEFT OUTER JOIN kitchens k
ON ( rk.id = k.id AND rk.room_name = k.room_name )
LEFT OUTER JOIN rooms rb
ON ( b.id = rb.building_id AND rb.room_name = 'bedroom' )
LEFT OUTER JOIN bedrooms br
ON ( rb.id = br.id AND rb.room_name = br.room_name )
输出:
BUILDING_ID | BUILDING_NAME | KITCHEN_ID | CHAIRCOUNT | BEDROOM_ID | BEDCOUNT
----------: | :------------ | ---------: | ---------: | ---------: | -------:
1 | Building1 | 1 | 42 | 2 | 13
db<>fiddle here
您可以使用完全外部联接完全按照您的要求执行操作:
select room_id, room_name, b.bedcount, k.chaircount
from bedroom b full outer join kitchen k using (room_id, room_name)
;
这几乎等同于您尝试的查询 - 但您需要 natural FULL OUTER join
而不是您尝试的(内部)natural join
。但是请注意,出于各种原因,许多(大多数?)从业者对 natural join
语法持怀疑态度;我上面演示的 using
子句似乎更容易被接受。 (当然,即使使用自然连接,您最好仍然在输出中专门命名您想要的列。)
虽然对于这种情况更常见的方法是直接 union all
:
select room_id, room_name, bedcount, cast (null as number) as chaircount
from bedroom
UNION ALL
select room_id, room_name, null , chaircount
from kitchen
;
我今天了解了“独家实体”。我有以下 ER 图:
拥有 2 个专属实体。当我通过 power designers 创建工具创建物理数据模型时,它解析为
现在我想将两者合二为一 table 并显示 id 和 room_name
我要得到的结构是:
room_id | room_name
房间和卧室的room_id不一样。例如,卧室的 ID 为 1-10,厨房的 ID 为 11-20。
我觉得我的设计可能不好,因为我尝试的连接没有得到我想要的结果。
我最好的猜测是使用像*
这样的自然连接SELECT room_id, room_name
FROM bedroom
NATURAL JOIN kitchen;
这 returns 格式正确,但结果为空。
此外,我希望获得格式为 table 的
room_id | roon_name | bedCount | chairCount
您可以将两个表合并在一起,例如:
select room_id, room_name
from bedroom
union
select room_id,room_name
from kitchen
您不能加入他们,因为您在加入 table 的 table 之间没有任何共同点。您需要做的是为 table 提供一个它们可以加入的公共列;例如一个房间将在建筑物中,因此创建一个 buildings
table 然后每个 rooms
应该包含一个指向包含建筑物的外键。
即
CREATE TABLE buildings (
id INT
GENERATED ALWAYS AS IDENTITY
CONSTRAINT buildings__id__pk PRIMARY KEY,
name VARCHAR2(20)
NOT NULL
);
CREATE TABLE rooms (
id INT
GENERATED ALWAYS AS IDENTITY
CONSTRAINT rooms__id__pk PRIMARY KEY,
building_id INT
NOT NULL
CONSTRAINT rooms__building_id__fk REFERENCES buildings (id),
room_name VARCHAR2(20)
NOT NULL,
CONSTRAINT rooms__id__rn__u UNIQUE ( id, room_name )
);
CREATE TABLE kitchens (
id INT
CONSTRAINT kitchens__id__pk PRIMARY KEY,
room_name VARCHAR2(20)
GENERATED ALWAYS AS ( 'kitchen' )
NOT NULL,
chairCount INT,
CONSTRAINT kitchens__id__rn__fk
FOREIGN KEY ( id, room_name ) REFERENCES rooms ( id, room_name )
);
CREATE TABLE bedrooms (
id INT
CONSTRAINT bedrooms__id__pk PRIMARY KEY,
room_name VARCHAR2(20)
GENERATED ALWAYS AS ( 'bedroom' )
NOT NULL,
bedCount INT,
CONSTRAINT bedrooms__id__rn__fk
FOREIGN KEY ( id, room_name ) REFERENCES rooms ( id, room_name )
);
那么,如果您:
INSERT INTO buildings ( id, name ) VALUES ( DEFAULT, 'Building1' );
INSERT INTO rooms ( id, building_id, room_name ) VALUES ( DEFAULT, 1, 'kitchen' );
INSERT INTO rooms ( id, building_id, room_name ) VALUES ( DEFAULT, 1, 'bedroom' );
INSERT INTO kitchens ( id, chairCount ) VALUES ( 1, 42 );
INSERT INTO bedrooms ( id, bedCount ) VALUES ( 2, 13 );
然后:
SELECT b.id AS building_id,
b.name AS building_name,
rk.id AS kitchen_id,
k.chairCount,
rb.id AS bedroom_id,
br.bedCount
FROM buildings b
LEFT OUTER JOIN rooms rk
ON ( b.id = rk.building_id AND rk.room_name = 'kitchen' )
LEFT OUTER JOIN kitchens k
ON ( rk.id = k.id AND rk.room_name = k.room_name )
LEFT OUTER JOIN rooms rb
ON ( b.id = rb.building_id AND rb.room_name = 'bedroom' )
LEFT OUTER JOIN bedrooms br
ON ( rb.id = br.id AND rb.room_name = br.room_name )
输出:
BUILDING_ID | BUILDING_NAME | KITCHEN_ID | CHAIRCOUNT | BEDROOM_ID | BEDCOUNT ----------: | :------------ | ---------: | ---------: | ---------: | -------: 1 | Building1 | 1 | 42 | 2 | 13
db<>fiddle here
您可以使用完全外部联接完全按照您的要求执行操作:
select room_id, room_name, b.bedcount, k.chaircount
from bedroom b full outer join kitchen k using (room_id, room_name)
;
这几乎等同于您尝试的查询 - 但您需要 natural FULL OUTER join
而不是您尝试的(内部)natural join
。但是请注意,出于各种原因,许多(大多数?)从业者对 natural join
语法持怀疑态度;我上面演示的 using
子句似乎更容易被接受。 (当然,即使使用自然连接,您最好仍然在输出中专门命名您想要的列。)
虽然对于这种情况更常见的方法是直接 union all
:
select room_id, room_name, bedcount, cast (null as number) as chaircount
from bedroom
UNION ALL
select room_id, room_name, null , chaircount
from kitchen
;