我想找到接受所有贷款类型的借款人。
架构:
loan (number (PKEY), type, min_rating)
borrower (cust (PKEY), no (PKEY))
示例表:
number | type | min_rating
------------------------------
L1 | student | 500
L2 | car | 550
L3 | house | 500
L4 | car | 700
L5 | car | 900
cust | no
-----------
Jim | L2
Tom | L1
Tom | L2
Tom | L3
Tom | L4
Tom | L5
Bob | L3
这里的答案是“汤姆”。
我可以简单地计算贷款总数,并将借款人的贷款数量与之比较,但我不允许(这是一项家庭作业),用于本课和学习。
我想使用双重否定,我首先找到没有获得所有贷款的借款人,并找到不在那个套房中的借款人。我想使用NOT EXISTS
嵌套,我首先找到没有获得所有贷款的借款人,但我无法为此创建一个有效的查询。
答案 0 :(得分:3)
一种简单的方法是使用事实:
因此,没有每种贷款类型的人的最低合并贷款数将为空白:
select cust
from borrower b
left join loan l on l.number = b.no
group by cust
having min(coalesce(l.number, '')) > ''
分组式整齐地回避了不止一次选择人的问题(以及经常需要的丑陋子查询),并依赖于一个非常合理的假设,即贷款号永远不会是空白。即使这是可能的,你仍然可以找到一种方法来使这个模式工作(例如将min_rating合并为负数等)。
使用NOT IN
表达式可以重写上述查询,可能更容易阅读:
select distinct cust
from borrower
where cust not in (
select cust
from borrower b
left join loan l on l.number = b.no
where l.number is null
)
通过使用遗漏连接返回所有空值的事实,内部查询的where子句仅保留错过的连接。
您需要使用DISTINCT
来阻止借款人出现两次。
您的架构存在问题 - 借用者和加载之间存在多对多关系,但您的架构处理不当。 borrower
每个人应该有一行,另一个 association 表来记录借款人贷款的事实:
create table borrower (
id int,
name varchar(20)
-- other columns about the person
);
create table borrrower_loan (
borrower_id int, -- FK to borrower
load_number char(2) -- FK to loan
);
这意味着您不需要distinct
运算符(留给您找出原因),但也可以处理现实生活情况,例如两个具有相同名称的借款人。
答案 1 :(得分:1)
我认为良好的第一步是采用借款人和贷款的笛卡尔积*,然后使用where子句过滤到那些不会出现在你的借款人和##中的那些" 34;表。 (虽然我认为那会使用NOT IN而不是NOT EXISTS,所以可能不是你的想法?)
(*需要注意的是笛卡尔产品是一件非常糟糕的事情,在现实生活中你需要仔细考虑性能)
ETA:NOT EXISTS变体可能如下所示: 像以前一样获取笛卡尔积,为借方和贷款的组合做一个相关的子查询,然后使用带有NOT EXISTS条件的WHERE子句过滤该查询是否返回任何行。
答案 2 :(得分:0)
select cust from borrower
except
select t.cust
from (select distinct cust,number
from borrower cross join loan) t
left join borrower b on t.cust = b.cust and t.number = b.num
where b.num is null
从借款人和贷款中借助cross join
客户。然后left join
borrower
表找到没有获得所有贷款的客户。最后,使用except
选择已获得所有贷款的客户。