Ich habe einen etwas besseren Weg gefunden, dies mit einem Anti-Join (Magento 1.9) zu tun.
Vorteile dieses Ansatzes
Dies hat gegenüber der ursprünglichen Antwort den Vorteil, dass Sie keine Fehlalarme erhalten und dadurch schneller und weniger fehleranfällig sind. Angenommen, Sie haben ein einzelnes Produkt:
- Hemd (in Kategorien: 1 | 2)
Sie möchten "alle Produkte finden, die nicht in sind category 3
, und sie dann hinzufügen category 3
" . Sie führen also eine NOT IN
Abfrage aus und es werden zwei Zeilen zurückgegeben (name | category_id)
:
1. "Shirt" | 1
2. "Shirt" | 2
Keine große Sache, Magento gibt immer noch nur das erste Ergebnis zurück, und dann fügen Sie es hinzu. Außer ! Wenn diese Abfrage zum zweiten Mal ausgeführt wird, erhalten Sie dieselben Ergebnisse:
1. "Shirt" | 1
2. "Shirt" | 2
Und Magento wird Ihnen sagen, dass Sie dieses Shirt noch nicht hinzugefügt haben category 3
. Dies liegt daran, dass ein Produkt, das zu mehreren Kategorien gehört, mehrere Zeilen in der Tabelle "catalog_product_entity" enthält . Und so LEFT JOIN
wird a mehrere Ergebnisse zurückgeben.
Dies ist unerwünscht, weil
- Ihre Ergebnismenge ist größer als erforderlich, wodurch mehr Speicher als erforderlich belegt wird. Besonders dann, wenn Sie einen sehr großen Bestand an Tausenden von Artikeln haben.
- Sie müssen eine zusätzliche Überprüfung in PHP durchführen, um festzustellen, ob die Ergebnisse falsch positiv sind (z. B.
in_array($categoryThree, $product->getCategories())
), was bedeutet, dass Sie unnötige Ergebnisse durchlaufen. Dies verlangsamt Ihr Skript / Ihren Code, insbesondere bei großen Lagerbeständen.
Lösung
// 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]
]);
Die generierte SQL-Abfrage sieht folgendermaßen aus:
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`;
Erläuterung:
In Anbetracht der Beziehungstabellen für Produkt und Produktkategorie <=>:
catalog_product_entity
+-----------+
| ENTITY_ID |
+-----------+
| 423 |
| 424 |
| 425 |
+-----------+
catalog_category_product
+-------------+------------+
| CATEGORY_ID | PRODUCT_ID |
+-------------+------------+
| 3 | 423 |
| 123 | 424 |
| 3 | 425 |
+-------------+------------+
Ihre Abfrage lautet: "Geben Sie mir alle Zeilen in " catalog_product_entity " und fügen Sie sie in die Spalte" category_id "von " catalog_category_product "ein . Geben Sie mir dann einfach die Zeilen" category_id = 124 " .
Da es sich um eine Linksverknüpfung handelt, enthält sie immer die Zeilen von "catalog_product_entity" . Für alle Zeilen, die nicht abgeglichen werden können, gilt Folgendes NULL
:
Ergebnis
+-------------+-------------+
| ENTITY_ID | CATEGORY_ID |
+-------------+-------------+
| 423 | NULL |
| 424 | 123 |
| 425 | NULL |
+-------------+-------------+
Von dort sagt die Abfrage dann: "OK, jetzt gib mir alles, wo die category_id NULL ist" .