查询而不使用子查询或显式联接

时间:2018-12-30 18:22:22

标签: sql

我需要重新编写此代码而不使用子查询和显式联接。.help,请找一会儿

SELECT snum, pnum, shipdate
FROM supply as b
WHERE EXISTS (SELECT pname, pnum FROM parts as a WHERE b.pnum = a.pnum);

3 个答案:

答案 0 :(得分:1)

我相信您已经收到了一个棘手的问题。答案是这样。

SELECT snum, pnum, shipdate
FROM supply

原因是,在设计良好的数据库中,您要检查的 条件应该是不可能的

让我们看看原始查询在做什么。

SELECT snum, pnum, shipdate
FROM supply as b
WHERE EXISTS (
    SELECT pname, pnum FROM parts as a WHERE b.pnum = a.pnum
);

supply中的每一行都在parts中有对应的部分。在没有联接的查询中如何做到这一点?您不必一开始就这样做。相反,您应该依靠 referential integrity

引用完整性是表设计良好的属性,它表示 所有引用都是有效的 。无需检查supply中的每个部分是否在parts中存在,因为这样的条件应该是不可能的。您可以使用精心设计的架构来做到这一点,并适当使用外键和not null约束。

(我的示例在Postgres中完成。您数据库的语法可能有所不同。)

create table parts(
    pnum integer primary key,
    pname text not null
);

create table supply(
    snum integer primary key,
    pnum integer references parts(pnum) not null,
    shipdate date not null
);

通过将supply.pnum声明为references parts(pnum),我们已经告诉数据库这是一个外键,并且{strong> 必须 1}}。添加parts可以保证not null中的每一行都必须提供有效的部分。数据库自动执行这些约束。

(请注意,MySQL takes a little more convincing会强制使用外键约束。因为MySQL是非标准的,所以它会养成学习它的不良习惯。请改用Postgres或SQLite。)

您还可以使用supply将约束添加到现有表中。

alter table

例如,假设我们有这些部分。

test=> alter table supply alter pnum set not null;
ALTER TABLE
test=> alter table supply add constraint pnum_fk foreign key (pnum) references parts(pnum);
ALTER TABLE

我们可以在其中一个零件的供应中插入一行。

test=> select * from parts;
 pnum |  pname  
------+---------
    1 | flange
    2 | thingy
    3 | whatsit

但是,如果我们尝试插入不存在的部分,则会收到错误消息。

test=> insert into supply (pnum, shipdate) values (3, '2018-02-03');
INSERT 0 1

或者零件号为空的一个...

test=> insert into supply (pnum, shipdate) values (99, '2018-02-03');
ERROR:  insert or update on table "supply" violates foreign key constraint "supply_pnum_fkey"
DETAIL:  Key (pnum)=(99) is not present in table "parts".

您现在无法测试的条件。没必要。答案是:

test=> insert into supply (pnum, shipdate) values (null, '2018-02-03');
ERROR:  null value in column "pnum" violates not-null constraint
DETAIL:  Failing row contains (1, null, 2018-02-03).

答案 1 :(得分:0)

一种方法是if let randomIndex = deck.indices.randomElement() { let newCard = deck.remove(at: randomIndex) dealtCards.append(newCard) } else { // Deck is empty. } (列列表仅限于普通列表):

INTERSECT

使用SEMIJOIN

SELECT pnum
FROM supply
INTERSECT
SELECT pnum
FROM parts;

答案 2 :(得分:0)

子查询可以由INNER JOIN替换,如下所示:

SELECT b.snum, b.pnum, b.shipdate
FROM 
    supply as b
    INNER JOIN parts as a ON b.pnum = a.pnum
GROUP BY b.snum, b.pnum, b.shipdate

您也可以进行隐式连接,但是我不建议您这样做,因为它的可读性和到目前为止都不受欢迎:

SELECT b.snum, b.pnum, b.shipdate
FROM 
    supply as b,
    parts as a
WHERE b.pnum = a.pnum
GROUP BY b.snum, b.pnum, b.shipdate