sql >> Databasteknik >  >> RDS >> PostgreSQL

Hur man hittar föremål med *alla* matchande kategorier

ActiveRecord

För ActiveRecord kan du lägga till en sådan metod i din Item-klass:

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

Sedan kan du filtrera dina frågor så här:

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

Du kan också använda scopes för att göra det lite mer vänligt:

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

Båda kommer att producera denna 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)

Du behöver tekniskt sett inte distinct en del av den underfrågan, men jag är inte säker på om med eller utan skulle vara bättre för prestanda.

SQL

Det finns ett par tillvägagångssätt i rå 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
)

Det kommer att fungera i SQL Server - syntaxen kan vara något annorlunda i Postgres. Eller

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. Hur kontrollerar jag om kolumnen inte finns med PHP, PDO, MySQL?

  2. Hur lägger man till några restriktioner i en fråga?

  3. PHP/MySQL - Öka variabelnamnet för att loopa för data

  4. Ställ in en standard LIMIT i PDO/MySQL när ingen LIMIT är inställd