簡體   English   中英

Rails Postgres查詢可排除連接中包含三個記錄之一的任何結果

[英]Rails Postgres query to exclude any results that contain one of three records on join

這是一個很難描述的問題,但是我在聯接另一個表的地方有Rails查詢,並且想排除聯接表包含以下三個條件之一的任何結果。

我有一個與CarUserRole模型/記錄相關的Device模型。 在該CarUserRole記錄中,它將包含三個:role role-“所有者”,“監視器”,“驅動程序”之一。 我想在沒有相關的CarUserRole記錄的情況下返回任何結果,其中role: "owner" 我該怎么做?

這是我的第一次嘗試-

Device.joins(:car_user_roles).where('car_user_roles.role = ? OR car_user_roles.role = ? AND car_user_roles.role != ?', 'monitor', 'driver', 'owner') 

這是SQL-

"SELECT \"cars\".* FROM \"cars\" INNER JOIN \"car_user_roles\" ON \"car_user_roles\".\"car_id\" = \"cars\".\"id\" WHERE (car_user_roles.role = 'monitor' OR car_user_roles.role = 'driver' AND car_user_roles.role != 'owner')"

更新

我應該提到一台設備有時具有多個CarUserRole記錄。 設備可以具有“所有者”和“驅動程序” CarUserRole。 我還要注意,他們只能有一個所有者。

Anwser

我最終通過聊天使用了@Reub的解決方案-

where(CarUserRole.where("car_user_roles.car_id = cars.id").where(role: 'owner').exists.not)

由於car_user_roles表可以有多個具有相同car_id的記錄,因此內部聯接可能導致聯接表對cars表中的每一行都具有多行。 因此,對於在car_user_roles表中具有3條記錄(監視,所有者和駕駛員)的汽車,聯接表中將有3條記錄(每個記錄具有不同的作用)。 您的查詢將過濾出角色為所有者的行,但它將與其他兩個匹配,即使該查詢具有記錄為“所有者”的汽車,也會由於查詢而返回該汽車。

首先讓我們嘗試為所需的結果形成一個sql查詢。 然后,我們可以將其轉換為Rails查詢。

SELECT * FROM cars WHERE NOT EXISTS (SELECT id FROM car_user_roles WHERE role='owner' AND car_id = cars.id);

如果您想要沒有角色為“所有者”的car_user_role的設備,則以上內容就足夠了。 但這也可以為您提供在car_user_roles中沒有相應記錄的設備。 如果要確保設備在car_user_roles中至少有一條記錄,可以將以下內容添加到上述查詢中。

AND EXISTS (SELECT id FROM car_user_roles WHERE role IN ('monitor', 'driver') AND car_id = cars.id);

現在,我們需要將其轉換為Rails查詢。

Device.where(
     CarUserRole.where("car_user_roles.car_id = cars.id").where(role: 'owner').exists.not
).where(
     CarUserRole.where("car_user_roles.car_id = cars.id").where(role: ['monitor', 'driver']).exists
).all

如果您的Rails版本支持exists?您也可以嘗試以下方法exists?

Device.joins(:car_user_roles).exists?(role: ['monitor', 'driver']).exists?(role: 'owner').not.select('cars.*').distinct
  • 選擇不同的汽車

     SELECT DISTINCT (cars.*) FROM cars 
  • 使用LEFT JOIN拉入car_user_roles

     LEFT JOIN car_user_roles ON cars.id = car_user_roles.car_id 
  • 僅選擇不包含“所有者” car_user_role的汽車

     WHERE NOT EXISTS(SELECT NULL FROM car_user_roles WHERE cars.id = car_user_roles.car_id AND car_user_roles.role = 'owner') 
  • 僅選擇包含“駕駛員”或“監視器”的汽車car_user_role

     AND (car_user_roles.role IN ('driver','monitor')) 

放在一起:

SELECT DISTINCT (cars.*) FROM cars LEFT JOIN car_user_roles ON cars.id = car_user_roles.car_id WHERE NOT EXISTS(SELECT NULL FROM car_user_roles WHERE cars.id = car_user_roles.car_id AND car_user_roles.role = 'owner') AND (car_user_roles.role IN ('driver','monitor'));

編輯:

  • 直接從Rails執行查詢,僅返回找到的對象ID

     ActiveRecord::Base.connection.execute(sql).collect { |x| x['id'] } 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM