mar*_*gor 6 sql sqlite relational-division
我想找到所有贷款类型的借款人.
架构:
loan (number (PKEY), type, min_rating)
borrower (cust (PKEY), no (PKEY))
Run Code Online (Sandbox Code Playgroud)
样本表:
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
Run Code Online (Sandbox Code Playgroud)
这里的答案是"汤姆".
我可以简单地计算贷款总数,并将借款人的贷款数量与之比较,但我不允许(这是一项家庭作业),为了这个家庭作业和学习的目的.
我想使用双重否定,我首先找到没有获得所有贷款的借款人,并找到那些不在那里的借款人.我想NOT EXISTS在我第一次找到没有拿到所有贷款的借款人的地方使用嵌套,但是我无法为此创建一个有效的查询.
一个简单的方法是使用事实:
因此,没有每种贷款类型的人的最小合并贷款数量将为空白:
select cust
from borrower b
left join loan l on l.number = b.no
group by cust
having min(coalesce(l.number, '')) > ''
Run Code Online (Sandbox Code Playgroud)
分组巧妙地回避了多次选择人员的问题(以及经常需要的丑陋的子查询),并依赖于贷款号码永远不会为空的相当合理的假设。即使这是可能的,您仍然可以找到一种方法来使该模式发挥作用(例如将 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
)
Run Code Online (Sandbox Code Playgroud)
通过利用错过的联接返回所有空值的事实,内部查询的 where 子句仅保留错过的联接。
您需要使用DISTINCT来阻止借款人出现两次。
您的架构有问题 - 借款人和负载之间存在多对多关系,但您的架构对此处理不佳。borrower每个人应该有一行,还有另一个关联表来记录借款人贷款的事实:
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
);
Run Code Online (Sandbox Code Playgroud)
这意味着您不需要distinct操作员(留给您找出原因),但也可以处理现实生活中的情况,例如两个同名的借款人。
| 归档时间: |
|
| 查看次数: |
649 次 |
| 最近记录: |