2009-04-28 8 views
1

je pense que je suis coincé avec cette situation particulière:
sélectionner des lignes dans une à de nombreuses situations

Voici mes tableaux:

item_table:
id | article
1:
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 qui est associé avec attr = 1 et 3. La réponse devrait être 'B' seulement. De même, si je demande un élément associé à attr = 1 et 2, je ne devrais obtenir que 'A'. Le fait est que attr_table peut potentiellement avoir beaucoup de lignes et je souhaite faire 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 malin pouvait me donner un coup de main ...

Répondre

2

L'exemple est écrit pour SQLServer, mais la requête doit travailler dans une base MySQL comme wel. Clé est l'instruction HAVING COUNT étant égale à la quantité d'attributs qui doivent correspondre. Si les attributs doivent être (1, 2, 5), vous devrez changer le nombre à 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 
+0

Ne pas faire une jointure interne équivaut à une seconde sélection? –

+0

Ceci est fragile, en utilisant le 'count =', car il ne fonctionnera pas à moins qu'il y ait exactement deux lignes attr correspondant à l'objet avec les attributs spécifiés. Mais pire, il échoue s'il y a deux lignes attr avec item_id = 1 et attr = 1 - donc cela ramène un faux positif, un item sans attr = 3. Et il ajoute le coût d'un groupe par. – tpdi

+0

@Blank Xavier, je suis désolé mais je ne comprends pas ce que vous essayez d'obtenir. –

0
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; 

Fondamentalement, il fait le vous attendez correspondant et se termine avec une tonne de rows - mais le mot-clé distinct fonctionne, de sorte que vous obtenez l'ensemble unique minimal de lignes comme résultat final.

(J'espère que c'est plus efficace, mais ne vous souciez pas de faire la liste complète des lignes correspondantes).

+1

Ne fonctionne pas car il n'y a pas de ligne unique où "attr = 1 et attr = 2" est vrai. –

+0

Je ne comprends pas. Le '2' est-il une faute de frappe? devrait-il être «3»? –

1
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); 

Est-ce que le travail de retour d'une ligne pour le point B.

1
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: Retrouve 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 le premier attr spécifié et où il existe au moins une ligne de attr_table qui a l'ID de cette ligne et le second attr spécifié.

0

Ceci est probablement trop tard, mais je suggère d'utiliser quelques jointures 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 

Voilà comment je le fais.

Questions connexes