PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Jak znaleźć przedmioty ze *wszystkimi* pasującymi kategoriami?

ActiveRecord

W przypadku ActiveRecord możesz umieścić taką metodę w swojej klasie 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

Następnie możesz filtrować swoje zapytania w następujący sposób:

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

Możesz także skorzystać z zakresów, aby uczynić go trochę bardziej przyjaznym:

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

Oba wytworzą ten 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)

Z technicznego punktu widzenia nie potrzebujesz distinct część tego podzapytania, ale nie jestem pewien, czy z lub bez byłoby lepsze dla wydajności.

SQL

W surowym SQL jest kilka podejść

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
)

To zadziała w SQL Server - składnia może być nieco inna w Postgresie. Lub

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Postgresql Utwórz unikalny indeks

  2. PostgreSQL przekazuje dane z rekurencyjnego CTE do funkcji

  3. Konwertuj dzień juliański na datę w PostgreSQL

  4. Funkcja jako parametr innej funkcji w Postgresie

  5. Aktualizacja do PostgreSQL 11 z replikacją logiczną