sql >> Database >  >> RDS >> PostgreSQL

Artikelen vinden met *alle* overeenkomende categorieën

ActiveRecord

Voor ActiveRecord zou je een methode als deze in je Item-klasse kunnen plaatsen:

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

Vervolgens kunt u uw zoekopdrachten als volgt filteren:

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

Je zou ook scopes kunnen gebruiken om het wat vriendelijker te maken:

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])

Beide zullen deze SQL produceren

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)

Technisch gezien heb je de distinct niet nodig onderdeel van die subquery, maar ik weet niet zeker of met of zonder beter zou zijn voor de prestaties.

SQL

Er zijn een paar benaderingen in onbewerkte 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
)

Dat werkt in SQL Server - de syntaxis kan in Postgres iets anders zijn. Of

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. Hoe datum en tijd te extraheren uit een String Timestamp in java

  2. JdbcTemplate - Oracle BLOB invoegen of bijwerken met SQL MERGE

  3. Hoe som je alle triggers op in een MySQL-database?

  4. Gebruikersnaam, Wachtwoord, Salting, Encrypting, Hash - Hoe werkt het allemaal?