1 votes

sélectionner des lignes dans une situation de "un à plusieurs".

Je pense que je suis coincé avec cette situation particulière :

Voici mes tableaux :

item_table :
id | article
1 : A
2 : B
3 : C

attr_table :
attr | item_id
1 : 1
1 : 2
2 : 1
2 : 3
3 : 2
3 : 3
Je voudrais savoir s'il est techniquement possible de récupérer tout élément associé à attr = 1 et 3. La réponse devrait être "B" uniquement. De même, si je demande un élément qui est associé à attr = 1 et 2, je ne devrais obtenir que 'A'.

Le problème est qu'attr_table peut potentiellement contenir un grand nombre de lignes et que je souhaite n'effectuer qu'une seule requête.

Cette question semble facile et je suis assez contrarié de ne pas pouvoir y répondre.

J'espérais que quelqu'un de plus intelligent pourrait me donner un coup de main...

2voto

Lieven Keersmaekers Points 32396

L'exemple est écrit pour SQLServer mais la requête devrait également fonctionner avec mysql.

La clé est que l'instruction HAVING COUNT est égale au nombre d'attributs qui doivent correspondre. Si les attributs doivent être (1, 2, 5), vous devrez changer le compte à 3.

DECLARE @item_table TABLE (ID INTEGER PRIMARY KEY, Item CHAR(1))
DECLARE @attr_table TABLE (Attr INTEGER, Item_ID INTEGER)

INSERT INTO @item_table VALUES (1, 'A')
INSERT INTO @item_table VALUES (2, 'B')
INSERT INTO @item_table VALUES (3, 'C')

INSERT INTO @attr_table VALUES (1, 1)
INSERT INTO @attr_table VALUES (1, 2)
INSERT INTO @attr_table VALUES (2, 1)
INSERT INTO @attr_table VALUES (2, 3)
INSERT INTO @attr_table VALUES (3, 2)
INSERT INTO @attr_table VALUES (3, 3)

SELECT Item
FROM @item_table i
     INNER JOIN @attr_table a ON a.Item_ID = i.ID
WHERE a.Attr IN (1, 3)
GROUP BY Item
HAVING COUNT(a.Attr) = 2

1voto

James Anderson Points 18253
   SELECT * From attr_table a, item_table i
   where a.item_id = i.id
   and a.attr = 1
   and a.item_id  in (select item_id from attr_table where  attr = 3);

Fait le travail en retournant une ligne pour l'élément B.

1voto

tpdi Points 18427
select * from item_table a 
where exists ( select * from attr_table b 
               where b.item_id = a.id and b.attr = 1)
and exists ( select * from attr_table c 
             where c.item_id = a.id and c.attr = 3);

Notez que cette requête dit exactement ce que votre spécification dit : obtenez-moi toutes les lignes de item_table où il existe au moins une ligne de attr_table qui a l'id de cette ligne et la première attr spécifiée et où il existe au moins une ligne de attr_table qui a l'id de cette ligne et le deuxième attr spécifié.

0voto

select distinct item_table.item from item_table, attr_table
where item_table.id = attr_table.item_id
and attr_table.attr = 1 and attr_table.attr = 3;

En gros, il effectue la correspondance à laquelle on peut s'attendre et se retrouve avec une tonne de lignes - mais ensuite le mot-clé distinct opère, de sorte que vous obtenez l'ensemble unique minimal de lignes comme résultat final.

(Entre nous, j'espère que c'est plus efficace, mais je ne m'embête pas à faire la liste complète des lignes correspondantes).

0voto

jelofson Points 61

C'est probablement trop tard, mais je vous suggère d'utiliser un couple de joints comme ceci :

select i.item, b.item_id, c.item_id 
from item_table i 
join attr_table b on i.id=b.item_id and b.item_id=1
join attr_table c on i.id=c.item_id and c.item_id=2

C'est comme ça que je fais.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X