2017-01-25 13 views
0

を除外するために参加し、私はlaravelアプリケーションで以下のテーブルがあります:basket_itemsテーブルでSQL - インナー行

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が多型の関係ですが。例えば。ユーザは、プレミアム製品リストである自分のバスケットにジョブを追加することができる。この場合のpurchaseable_idは、ジョブテーブルからのジョブのIDであり、purchaseable_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をリストが、purchaseable_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() 
+0

質問を編集し、サンプルデータと希望する結果を提供してください。 –

答えて

0

有効期限が切れている場合、それはすべての行を除外結合条件によっては、NULLです。この場合、basket_itemsからjobsへの参加が結合条件と一致しない場合、jobsから引き出されたフィールドはすべてNULLです。 t3.expiry_dt > now()t3.expiry_dtNULLの場合は常にfalseを返しますので、そのレコードを戻すことはできません。

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

ジョブテーブルに参加しないでください:ところで、その周り

はNULLが許可するようにWHERE句を変更することです。あなたは唯一の基準としてそれを使用したいので、それは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; 

+0

あなたのソリューションは非効率な2つのクエリを実行しています。バスケットは、バスケットに仕事項目がある場合には左結合を行うだけです。それはもっと読みやすいかもしれませんが効率は低くなります。私が何千人もの雇用を持っていると想像してください。 – adam78

+0

いいえ。クエリはまったく同じです。したがって、DBMSは実際に同じ実行計画を使用できます。これは、DBMSが内部的にどのように処理するかにかかっています。これについてはあまり想定してはいけません(特に、これはバージョンによって異なる可能性があります)。ジョブサブクエリは一度だけ実行されなければならず、その結果はpurchaseable_type = 'App \ Job'を持つユーザ1のほんの少数のレコードに対して検索されなければならない。それは速くなければならない。可能な限り読みやすいようにあなたの質問を書いてください。あなたが実際に問題を抱えている場合にのみ、それらの周りに(半分の反結合などの)方法を試してみてください。 –

+0

パフォーマンスの観点からは、外部結合により必要なレコードが増えます(where句で解消します)。したがって、DBMSが直接指示(内部的には必要ない)に従うなら、必要以上に中間結果が大きくなります。これは回避すべきものです。しかし、前述のように、DBMSのオプティマイザは、クエリを判断し、リスクを見て、最良の実行計画を決定できる必要があります。 –