[英]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_id
和purchaseable_type
在basket_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_items
到jobs
不匹配连接条件的领域从拉动jobs
都NULL
。 由于如果t3.expiry_dt
为NULL
,则表达式t3.expiry_dt > now()
将始终返回false
,因此您将不会获得这些记录。
解决该问题的一种方法是更改WHERE子句以允许NULL:
where t1.user_id = 1 and ( t3.expiry_dt > now() OR t3.expiry_dt IS NULL)
不要加入工作表。 您只想将其用作条件,因此它属于WHERE
或ON
:
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.