简体   繁体   English

Rails Postgres查询可排除连接中包含三个记录之一的任何结果

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

This is a hard problem to describe but I have Rails query where I join another table and I want to exclude any results where the join table contain one of three conditions. 这是一个很难描述的问题,但是我在联接另一个表的地方有Rails查询,并且想排除联接表包含以下三个条件之一的任何结果。

I have a Device model that relates to a CarUserRole model/record. 我有一个与CarUserRole模型/记录相关的Device模型。 In that CarUserRole record it will contain one of three :role - "owner", "monitor", "driver". 在该CarUserRole记录中,它将包含三个:role role-“所有者”,“监视器”,“驱动程序”之一。 I want to return any results where there is no related CarUserRole record where role: "owner" . 我想在没有相关的CarUserRole记录的情况下返回任何结果,其中role: "owner" How would I do that? 我该怎么做?

This was my first attempt - 这是我的第一次尝试-

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

Here is the sql - 这是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')"

Update 更新

I should mention that a device sometimes has multiple CarUserRole records. 我应该提到一台设备有时具有多个CarUserRole记录。 A device can have an "owner" and a "driver" CarUserRole. 设备可以具有“所有者”和“驱动程序” CarUserRole。 I should also note that they can only have one owner. 我还要注意,他们只能有一个所有者。

Anwser Anwser

I ended up going with @Reub's solution via our chat - 我最终通过聊天使用了@Reub的解决方案-

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

Since the car_user_roles table can have multiple records with the same car_id, an inner join can result in the join table having multiple rows for each row in the cars table. 由于car_user_roles表可以有多个具有相同car_id的记录,因此内部联接可能导致联接表对cars表中的每一行都具有多行。 So, for a car that has 3 records in the car_user_roles table (monitor, owner and driver), there will be 3 records in the join table (each record having a different role). 因此,对于在car_user_roles表中具有3条记录(监视,所有者和驾驶员)的汽车,联接表中将有3条记录(每个记录具有不同的作用)。 Your query will filter out the row where the role is owner, but it will match the other two, resulting in that car being returned as a result of your query even though it has a record with role as 'owner'. 您的查询将过滤出角色为所有者的行,但它将与其他两个匹配,即使该查询具有记录为“所有者”的汽车,也会由于查询而返回该汽车。

Lets first try to form an sql query for the result that you want. 首先让我们尝试为所需的结果形成一个sql查询。 We can then convert this into a Rails query. 然后,我们可以将其转换为Rails查询。

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

The above is sufficient if you want devices which do not have any car_user_role with role as 'owner'. 如果您想要没有角色为“所有者”的car_user_role的设备,则以上内容就足够了。 But this can also give you devices which have no corresponding record in car_user_roles. 但这也可以为您提供在car_user_roles中没有相应记录的设备。 If you want to ensure that the device has at least one record in car_user_roles, you can add the following to the above query. 如果要确保设备在car_user_roles中至少有一条记录,可以将以下内容添加到上述查询中。

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

Now, we need to convert this into a Rails query. 现在,我们需要将其转换为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

You could also try the following if your Rails version supports exists? 如果您的Rails版本支持exists?您也可以尝试以下方法exists? :

Device.joins(:car_user_roles).exists?(role: ['monitor', 'driver']).exists?(role: 'owner').not.select('cars.*').distinct
  • Select the distinct cars 选择不同的汽车

     SELECT DISTINCT (cars.*) FROM cars 
  • Use a LEFT JOIN to pull in the car_user_roles 使用LEFT JOIN拉入car_user_roles

     LEFT JOIN car_user_roles ON cars.id = car_user_roles.car_id 
  • Select only the cars that DO NOT contain an 'owner' car_user_role 仅选择不包含“所有者” 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') 
  • Select only the cars that DO contain either a 'driver' or 'monitor' car_user_role 仅选择包含“驾驶员”或“监视器”的汽车car_user_role

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

Put it all together: 放在一起:

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'));

Edit: 编辑:

  • Execute the query directly from Rails and return only the found object IDs 直接从Rails执行查询,仅返回找到的对象ID

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

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

相关问题 查询以“ The”开头的记录,并将“ The”移至字符串的末尾,并在Rails Postgres中加入逗号 - Query for Records beginning with “The” and move “The” the end of a string and join with a comma in Rails Postgres Postgres加入Rails查询 - Postgres Join Query on Rails 如何在 Rails 中的一个查询中在连接表中创建多条记录? - How to create many records in join table in one query in Rails? 如何在rails中查询查询结果(使用rails和postgres查询'DISTINCT ON'的结果 - How to query the results of a query in rails (query the results of a 'DISTINCT ON' with rails & postgres 在Rails中查询不返回任何记录 - Query in Rails not returning any records Rails Postgres查询无法返回新记录 - Rails Postgres Query Fails to Return New Records Rails:如何排除联接表中具有条目的记录? - Rails: How do I exclude records with entries in a join table? SQL JOIN查询和读取数组中的结果(rails) - SQL JOIN query and read results in array (rails) Rails AR查询使用postgres json数据类型过滤记录 - rails AR query filtering records using postgres json data type 如何查询作用域“上一个”和“下一个”记录(ActiveRecord和PostGres)rails 4.2 - How to query scoped 'previous' and 'next' records (ActiveRecord & PostGres) rails 4.2
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM