Anti-join (Magento 1.9) kullanarak bunu yapmanın biraz daha iyi bir yolunu buldum.
Bu yaklaşımın faydaları
Bunun orijinal yanıta göre yararı, yanlış pozitifler elde etmemeniz ve sonuç olarak daha hızlı ve daha az hataya yatkın olmasıdır. Örneğin, tek bir ürününüz olduğunu varsayalım:
- Gömlek (kategorilerde: 1 | 2)
Sen istiyoruz "değil tüm ürünleri bulmak category 3
, sonra bunları eklemek category 3
" . Böylece bir NOT IN
sorgu çalıştırırsınız ve iki satır döndürür (name | category_id)
:
1. "Shirt" | 1
2. "Shirt" | 2
Önemli değil, Magento yine de sadece ilk sonucu döndürecek ve sonra ekleyeceksiniz. Dışında ! Bu sorgu ikinci kez çalıştırıldığında aynı sonuçlara sahip olursunuz:
1. "Shirt" | 1
2. "Shirt" | 2
Ve Magento hala bu gömleği henüz eklemediğini söyleyecek category 3
. Bunun nedeni, bir ürün birden çok kategoriye ait olduğunda, "catalog_product_entity" tablosunda birden çok satıra sahip olmalarıdır . Ve böylece a LEFT JOIN
birden çok sonuç döndürür.
Bu istenmeyen bir durum çünkü
- Sonuç kümeniz gerekenden daha büyük olacak ve bu da gerektiğinden daha fazla bellek kullanacak. Özellikle binlerce öğeden oluşan çok büyük bir envanteriniz varsa.
- Sonuçların yanlış pozitif olup olmadığını belirlemek için PHP'de ek bir kontrol
in_array($categoryThree, $product->getCategories())
yapmanız gerekecektir (örn. ), Yani gereksiz sonuçlara göz atacaksınız. Bu, özellikle büyük envanterlerde komut dosyanızı / kodunuzu yavaşlatır.
Çözüm
// All products not in this category ID
$notInThisCatId = '123';
$filteredProducts = Mage::getModel('catalog/product')->getCollection();
$filteredProducts
->joinField('category_id', 'catalog_category_product', 'category_id', 'product_id=entity_id', ['category_id'=>$notInThisCatId], 'left');
$filteredProducts
->addAttributeToFilter('category_id', [
['null' => true]
]);
Oluşturulan SQL sorgusu şöyle görünecektir:
SELECT
DISTINCT `e`.*, `at_category_id`.`category_id`
FROM `catalog_product_entity` AS `e`
LEFT JOIN `catalog_category_product` AS `at_category_id`
ON (at_category_id.`product_id`=e.entity_id) AND (at_category_id.category_id = '123')
WHERE (at_category_id.category_id IS NULL)
GROUP BY `e`.`entity_id`;
Açıklama:
Ürün ve ürün <=> kategori ilişki tabloları göz önüne alındığında:
catalog_product_entity
+-----------+
| ENTITY_ID |
+-----------+
| 423 |
| 424 |
| 425 |
+-----------+
catalog_category_product
+-------------+------------+
| CATEGORY_ID | PRODUCT_ID |
+-------------+------------+
| 3 | 423 |
| 123 | 424 |
| 3 | 425 |
+-------------+------------+
Sorgu, diyor "bana tüm satırları vermek catalog_product_entity '' ve yapıştırmak 'category_id' dan kolona catalog_category_product '' . Ardından yalnızca bu category_id = 124 me satırları vermek" .
Bu bir sol birleşim olduğu için, her zaman "catalog_product_entity" satırları olacaktır . Eşleştirilemeyen satırlar için NULL
:
Sonuç
+-------------+-------------+
| ENTITY_ID | CATEGORY_ID |
+-------------+-------------+
| 423 | NULL |
| 424 | 123 |
| 425 | NULL |
+-------------+-------------+
Oradan, sorgu "tamam, şimdi bana category_id NULL olduğu her şeyi ver" diyor .