sql >> データベース >  >> RDS >> PostgreSQL

*すべて*の一致するカテゴリを持つアイテムを見つける方法

    ActiveRecord

    ActiveRecordの場合、次のようなメソッドをItemクラスに配置できます。

    def self.with_all_categories(category_ids)
      select(:id).distinct.
        joins(:categories).
        where('categories.id' => category_ids).
        group(:id).
        having('count(categories.id) = ?', category_ids.length)
    end
    

    次に、次のようにクエリをフィルタリングできます。

    category_ids = [1,2,3]
    Item.where(id: Item.with_all_categories(category_ids))
    

    スコープを利用して、もう少し使いやすくすることもできます:

    class Item
      scope :with_all_categories, ->(category_ids) { where(id: Item.ids_with_all_categories(category_ids)) }
    
      def self.ids_with_all_categories(category_ids)
        select(:id).distinct.
          joins(:categories).
          where('categories.id' => category_ids).
          group(:id).
          having('count(categories.id) = ?', category_ids.length)
      end
    end
    
    Item.with_all_categories([1,2,3])
    

    どちらもこのSQLを生成します

    SELECT "items".*
    FROM "items"
    WHERE "items"."id" IN
      (SELECT DISTINCT "items"."id"
       FROM "items"
       INNER JOIN "categories_items" ON "categories_items"."item_id" = "items"."id"
       INNER JOIN "categories" ON "categories"."id" = "categories_items"."category_id"
       WHERE "categories"."id" IN (1, 2, 3)
       GROUP BY "items"."id" 
       HAVING count(categories.id) = 3)
    

    技術的にはdistinctは必要ありません そのサブクエリの一部ですが、パフォーマンスが向上するかどうかはわかりません。

    SQL

    生のSQLにはいくつかのアプローチがあります

    SELECT *
    FROM items
    WHERE items.id IN (
      SELECT item_id
      FROM categories_items
      WHERE category_id IN (1,2,3)
      GROUP BY item_id
      HAVING COUNT(category_id) = 3
    )
    

    これはSQLServerで機能します-Postgresでは構文が少し異なる場合があります。または

    SELECT *
    FROM items
    WHERE items.id IN (SELECT item_id FROM categories_items WHERE category_id = 1)
      AND items.id IN (SELECT item_id FROM categories_items WHERE category_id = 2)
      AND items.id IN (SELECT item_id FROM categories_items WHERE category_id = 3)
    


    1. プロバイダーからのデータの読み取り中にエラーが発生しました。検証手順に従って、リモート証明書が無効です

    2. SQLステートメントはpostgresの原子性を保証しますか

    3. 一時テーブルに新しい列を追加する

    4. oracle plsqlトリガーを使用して誕生日から年齢を計算し、年齢を表に挿入します