如何连接具有相同主键名称但不同值的两个表

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
;