繁体   English   中英

SQL-内部联接以排除行

[英]SQL - Inner join to exclude rows

我在laravel应用程序中具有以下表格:

basket
------
id  PK
user_id FK
coupon_id FK

basket_items
------------
id PK
basket_id FK
product_id FK
quantity 
purchaseable_id   
purchaseable_type -- e.g. App\Job, App\CV

products
--------
id PK
name  -- e.g. standard job listing, premium job listing, cv download
price

jobs
----
id PK
product_id FK
title
start_dt
expiry_dt
description

cvs
------
id PK
name

purchaseable_idpurchaseable_typebasket_items表是多态的关系。 例如,用户可以将一个工作添加到他们的购物篮中,这是一个高级产品列表-在这种情况下,purchableable_id将是作业表中工作的ID,而buyable_type将是App\\Job basket_items表中的示例行可能如下所示:

id | basket_id | product_id | quantity | purchaseable_id | purchaseable_type
----------------------------------------------------------------------------
1  | 1         |  1         |   1      |     1           | App\Job   
2  | 1         |  3         |   1      |     1           | App\CV

我希望列出用户的所有basket_items,但如果purchableable_type为App\\Job并且工作已过期,则排除项目。

我尝试了以下方法,但如果作业已过期,则它排除了所有行,即它排除了每个Purchaseable_type的项目

select t1.*, t2.* 
from baskets t1
inner join basket_items t2 on t2.basket_id = t1.id
left join jobs t3 on t3.id = t2.purchaseable_id and t2.purchaseable_type = 'App\\Job' 
where t1.user_id = 1 and t3.expiry_dt > now()  

使用左联接时,表中所有与联接条件不匹配的字段均为NULL 所以在这种情况下,当你从加入basket_itemsjobs不匹配连接条件的领域从拉动jobsNULL 由于如果t3.expiry_dtNULL ,则表达式t3.expiry_dt > now()将始终返回false ,因此您将不会获得这些记录。

解决该问题的一种方法是更改​​WHERE子句以允许NULL:

where t1.user_id = 1 and ( t3.expiry_dt > now() OR t3.expiry_dt IS NULL)

不要加入工作表。 您只想将其用作条件,因此它属于WHEREON

select *
from baskets b
join basket_items bi 
  on bi.basket_id = b.id
  and not
  (
    bi.purchaseable_type = 'App\Job' and
    bi.purchaseable_id in (select id from jobs where expiry_dt > now())
  )
where b.user_id = 1;

这使您的查询更具可读性,从而减少了(未来)错误的发生,即提供了更好的可维护性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM