SQL-запрос с несколькими «IN» для одной и той же таблицы «многие ко многим» - PullRequest
0 голосов
/ 12 июля 2009

У меня такие отношения в м2м:

#main table
CREATE TABLE products_product (
    id integer NOT NULL,
    company_id integer,
    user_id integer,
    type_id integer NOT NULL,
    name character varying(100) NOT NULL,
    description character varying(200) NOT NULL,
    tags character varying(255) NOT NULL,
    image character varying(200) NOT NULL
);
#intermediate table
CREATE TABLE products_ingridientbound (
    id integer NOT NULL,
    ingridient_id integer NOT NULL,
    company_id integer NOT NULL,
    price double precision NOT NULL,
    active boolean NOT NULL,
    "asTopping" boolean NOT NULL
);
#final m2m table
CREATE TABLE products_ingridientproductbound (
    id integer NOT NULL,
    product_id integer NOT NULL,
    ingridient_id integer NOT NULL,
    "optionValue" integer NOT NULL,
    CONSTRAINT "products_ingridientproductbound_optionValue_check" CHECK (("optionValue" >= 0))
);

Все, что я хочу сделать, это получить продукты, которые имеют 2 (в данном примере) группы ингредиентов, одну с идентификатором в диапазоне (16, 17, 18, 19), а другую в диапазоне (43, 44, 45) , Я хочу, чтобы Ingridient ID был в обеих группах одновременно.

Мой запрос выглядит так (на самом деле он сгенерирован django orm):

SELECT "products_product"."id","products_product"."name",
FROM "products_product"
INNER JOIN "products_ingridientproductbound" 
ON ("products_product"."id" = "products_ingridientproductbound"."product_id")
WHERE ("products_ingridientproductbound"."ingridient_id" IN (16, 17, 18, 19)
AND "products_ingridientproductbound"."ingridient_id" IN (43, 44, 45)) LIMIT 21

Это дает мне 0 результатов, но если я запускаю запрос только с одной группой запросов IN, то это работает!

Вот данные в моей таблице "products_ingridientproductbound". Я думал, что мой запрос может вернуть продукт 3, как и в обеих группах (16 и 45), но теперь я немного запутался. Снимок экрана phpPgAdmin

Ответы [ 4 ]

1 голос
/ 12 июля 2009

txwikinger прав. Если вы хотите отфильтровать продукт, который имеет две взаимосвязанные внутренние составляющие, вам нужно иметь в запросе два JOIN:

SELECT "products_product"."id","products_product"."name",
FROM "products_product"
INNER JOIN "products_ingridientproductbound" ig1
ON ("products_product"."id" = ig1."product_id")
INNER JOIN "products_ingridientproductbound" ig2
ON ("products_product"."id" = ig2."product_id")
WHERE (ig1."ingridient_id" IN (16, 17, 18, 19)
AND ig2."ingridient_id" IN (43, 44, 45)) 
LIMIT 21
1 голос
/ 12 июля 2009

В двух предложениях IN вы спрашиваете, что одно и то же поле находится в двух наборах без общих элементов. Следовательно, вы всегда получите false в одном из пунктов, следовательно, ваше AND будет false.

0 голосов
/ 12 июля 2009

В SQL Server вы можете использовать INTERSECT, как это

SELECT "products_product"."id","products_product"."name",
FROM "products_product"
INNER JOIN "products_ingridientproductbound" 
ON ("products_product"."id" = "products_ingridientproductbound"."product_id")
WHERE ("products_ingridientproductbound"."ingridient_id" IN (16, 17, 18, 19)

INTERSECT 

SELECT "products_product"."id","products_product"."name",
FROM "products_product"
INNER JOIN "products_ingridientproductbound" 
ON ("products_product"."id" = "products_ingridientproductbound"."product_id")
WHERE ("products_ingridientproductbound"."ingridient_id" IN (43, 44, 45)

Значение возвращаемых строк, которые есть в обоих запросах. Проверьте, есть ли у вашей БД такая опция.

0 голосов
/ 12 июля 2009

Если я понимаю, что вы после этого, ВНУТРЕННЕЕ СОЕДИНЕНИЕ - это не то, что вы ищете, я бы вместо этого использовал подзапрос .

Вы хотите, чтобы идентификатор продукта и название имели оба ингредиента, верно?

Я не проверял это утверждение, но оно должно выглядеть примерно так:

SELECT "products_product"."id","products_product"."name",
FROM "products_product"
WHERE (
    EXISTS (SELECT 1 FROM "products_ingridientproductbound" WHERE "products_product"."id" = "products_ingridientproductbound"."product_id" AND "products_ingridientproductbound"."ingridient_id" IN (16, 17, 18, 19))
        AND
    EXISTS (SELECT 1 FROM "products_ingridientproductbound" WHERE "products_product"."id" = "products_ingridientproductbound"."product_id" AND "products_ingridientproductbound"."ingridient_id" IN (43, 44, 45))
)
LIMIT 21

Редактировать: удалить глупое замечание по поводу объединения, спасибо jvanderh.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...