Domanda

Ho un elenco di ID prodotto e voglio scoprire quali ordini contengono tutti quei prodotti.La tabella degli ordini è strutturata come questa:

order_id | product_id
----------------------
1        | 222
1        | 555
2        | 333
.

Ovviamente posso farlo con alcuni looping in PHP, ma mi stavo chiedendo se c'è un modo elegante per farlo puramente in mysql. La mia query fantasy ideale sarebbe qualcosa come:

SELECT order_id
FROM orders
WHERE (222,555) IN GROUP_CONCAT(product_id)
GROUP BY order_id
.

C'è qualche speranza o dovrei leggere Tolkien?:) Inoltre, dalla curiosità, se non possibile in mysql, c'è qualche altro database che ha questa funzionalità?

È stato utile?

Soluzione

Sei stato vicino

SELECT order_id
FROM orders
WHERE product_id in (222,555) 
GROUP BY order_id
HAVING COUNT(DISTINCT product_id) = 2
.

Per quanto riguarda la domanda "fuori dalla curiosità" in algebra relazionale, questo si ottiene semplicemente con divisione .AFAIK No RDBMS ha implementato qualsiasi estensione che lo rende semplice in SQL.

Altri suggerimenti

Ho una preferenza per aver fatto confronti di set solo nella clausola AVANDE:

select order_id
from orders
group by order_id
having sum(case when product_id = 222 then 1 else 0 end) > 0 and
       sum(case when product_id = 555 then 1 else 0 end) > 0
.

Cosa sta dicendo è: prendi me tutti gli ordini in cui l'ordine ha almeno un prodotto 222 e almeno un prodotto 555.

Preferisco questo per due motivi.Il primo è la generalizzazione.È possibile organizzare condizioni più complicate, come 222 o 555 (solo cambiando "e" a e "o").O, 333 e 555 o 222 senza 555.

Secondo, quando si crea la query, è necessario solo mettere le condizioni in un unico posto, nella clausola having.

Supponendo che il tuo database sia normalizzato correttamente, cioè non c'è prodotto duplicato su un determinato ordine

mysqlism:

select order_id
from orders
group by order_id
having sum(product_id in (222,555)) = 2
.

SQL standard:

select order_id
from orders
group by order_id
having sum(case when product_id in (222,555) then 1 end) = 2
.


.

Se ha duplicati:

CREATE TABLE tbl
    (`order_id` int, `product_id` int)
;

INSERT INTO tbl
    (`order_id`, `product_id`)
VALUES
    (1, 222),
    (1, 555),
    (2, 333),
    (1, 555)
;
.

Fai questo, quindi:

select order_id
from tbl
group by order_id
having count(distinct case when product_id in (222,555) then product_id end) = 2
.

Test live: http://www.sqlfiddle.com/#!2/FA1AD/ 5

CREATE TABLE orders
        ( order_id INTEGER NOT NULL
        , product_id INTEGER NOT NULL
        );
INSERT INTO orders(order_id,product_id) VALUES
 (1, 222 ) , (1, 555 ) , (2, 333 )
, (3, 222 ) , (3, 555 ) , (3, 333 ); -- order#3 has all the products

CREATE TABLE products AS (SELECT DISTINCT product_id FROM orders);

SELECT *
FROM orders o1
   --
   -- There should not exist a product
   -- that is not part of our order.
   --
WHERE NOT EXISTS (
        SELECT *
        FROM products pr
        WHERE 1=1
           -- extra clause: only want producs from a literal list
        AND pr.product_id IN (222,555,333)
           --  ... that is not part of our order...
        AND NOT EXISTS ( SELECT *
                FROM orders o2
                WHERE o2.product_id = pr.product_id
                AND o2.order_id = o1.order_id
                )
        );
.

Risultato:

 order_id | product_id 
----------+------------
        3 |        222
        3 |        555
        3 |        333
(3 rows)
.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top