简体   繁体   English

如果包括且仅当查询不适用于Rails和Postgres时,才使用join进行所有操作

[英]All off with join if includes if and only if query does not work with Rails and Postgres

What I want is to query for all media that only has "fra" language associated through the habtm association. 我想要的是查询仅具有通过habtm关联关联的“ fra”语言的所有媒体。 Currently, this query returns Media instances that include "fra", so eg ["fra", "eng"]. 当前,该查询返回的Media实例包括“ fra”,例如[“ fra”,“ eng”]。 I use Postgres. 我使用Postgres。

So, (1) I want to find the media that has exactly the language 'x' and no other, (2) find the media that has exactly the languages 'x' and 'y', (3) find the media that has exactly the languages 'x', 'y' and 'z' etc. 因此,(1)我想找到完全具有语言“ x”的媒体,而没有其他媒体;(2)找到完全具有语言“ x”和“ y”的媒体,(3)找到具有完全语言的媒体。恰好是语言“ x”,“ y”和“ z”等。

class Media < ActiveRecord::Base
    has_and_belongs_to_many :audio_language_records, :join_table => "audio_languages_media", :class_name => "Language"
end

class Language < ActiveRecord::Base
  attr_accessor :code
end

I have tried this, but it returns all media that includes "fra", but not only "fra" 我已经尝试过了,但是它返回的所有媒体都包括“ fra”,而不仅仅是“ fra”

Media.joins(:audio_language_records).where("languages.code = ? AND languages.code != ?", "fra", "eng")

The following does not work as intended and returns the same result 以下内容无法按预期运行,并返回相同结果

Media.joins(:audio_language_records).where("languages.code IN (?) AND languages.code NOT IN (?)", ["fra"], ["eng"])

So you need to find the Media for which there exists a language.code of 'eng' but no entries in the join table for the same media_id but a different language_id. 因此,您需要找到存在一个language.code为“ eng”的Media,但联接表中没有针对相同media_id但不同language_id的条目。

SELECT * FROM media m1
  JOIN audio_languages_media alm1 ON alm1.media_id = m1.id
  JOIN languages l1 ON alm1.language_id = l1.id 
  WHERE NOT EXISTS(
    SELECT 1 FROM audio_languages_media alm2
    WHERE alm1.language_id != alm2.language_id
    AND alm1.media_id = alm2.media_id
  )
  AND l1.code = 'eng';

Let us know if this is the right db query so we can help with the AREL. 让我们知道这是否是正确的数据库查询,以便我们为AREL提供帮助。

Edit: Query for when you want to find a media that is in at least 'eng' and 'fra' 编辑:查询何时要查找至少在“ eng”和“ fra”中的媒体

SELECT * FROM media m1
  WHERE(
    SELECT count(*) FROM audio_languages_media alm2
    JOIN languages l2 ON alm2.language_id = l2.id
    WHERE l2.code in ('eng','fra')
    AND alm2.media_id = m1.id
  ) > 1;

Edit: Add @chinshr's query 编辑:添加@chinshr的查询

If you want media that has only exactly 'eng' and 'fra' 如果您想要仅具有“ eng”和“ fra”的媒体

SELECT * FROM media m1
  WHERE(
    SELECT count(*) FROM audio_languages_media alm2
    JOIN languages l2 ON alm2.language_id = l2.id
    WHERE l2.code IN ('eng','fra')
    AND alm2.media_id = m1.id
    AND (
      SELECT count(*) FROM audio_languages_media alm2 
      WHERE alm2.media_id = media.id
    ) = 2
  ) = 2;

This query can be tweaked for more or less languages by adding/removing from the IN array, and adjusting the count at the end to be equal to the number of elements in the IN array. 可以通过在IN数组中添加/删除该查询来调整或多或少的语言,并将末尾的计数调整为等于IN数组中的元素数。

For this to work reliably, you must have a unique index on audio_languages_media(media_id, language_id); 为了使它可靠地工作,您必须在audio_languages_media(media_id,language_id)上具有唯一索引;

You only have one value per row so every value that is "fra" can't be "eng" or any other thing. 每行只有一个值,因此每个“ fra”值不能为“ eng”或任何其他值。 You're gonna have to check two rows. 您将不得不检查两行。 It can be done in SQL like this for example: 例如,可以在SQL中完成此操作:

SELECT * 
FROM languages t1
LEFT JOIN languages t2
    ON t1.id=t2.id AND t2.code="eng"
WHERE t1.code="fra" AND t2.code IS NULL;

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

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