2010-11-06 5 views
0

J'ai un à plusieurs relation qui ressemble à ceci:requête SQL relation enfant aide

| Parent | | Child | 
| id | | id | 
|  | |parentID| 
|  | | date | 

Et je suis en train de structurer une requête telle que je reçois tous les parents qui ont des enfants des dossiers qui ont tous une date avant une date spécifiée.

Quelque chose comme ça

SELECT * FROM parent 
JOIN child on child.parentid = parent.id 
WHERE child.date <= '10/13/2010' 

Mais le problème est que je reçois des parents qui ont des enfants avec une date antérieure à la date indiquée et avoir des enregistrements enfants avec une date postérieure à la date indiquée, quand je veux seulement le les parents d'enfants ayant une date antérieure à la date donnée.

Quelqu'un at-il des suggestions sur la façon de gérer ce cas?

Merci!

Répondre

2

Utilisation:

SELECT p.* 
    FROM PARENT p 
WHERE EXISTS(SELECT NULL 
       FROM CHILD c 
       WHERE c.parentid = p.id 
       AND c.date <= '2010-10-13') 
    AND NOT EXISTS(SELECT NULL 
        FROM CHILD c 
        WHERE c.parentid = p.id 
        AND c.date > '2010-10-13') 

Tout le monde vous dira d'utiliser JOIN « parce qu'ils sont plus rapides », mais généralement, ils ne sont pas conscients de l'impact de en utilisant les - si vous ne le faites pas besoin de l'information d'une table de soutien, vous ne devriez pas vous joindre à elle. En effet, plus d'un enfant dans cette situation produirait des enregistrements PARENT en double. Le compromis entre un JOIN et un DISTINCT ou un GROUP BY par rapport à IN ou EXISTS est probablement le même, mais sans les tracas de traiter correctement les données dupliquées.

+0

Ne serait-ce encore tirer les parents qui ont des enfants à la fois un date avant la date donnée et une date après? Je ne veux que les parents avec un enfant avant chaque fois – Jimmy

+0

@Jimmy: Voir la mise à jour de la réponse. –

+0

Vous êtes un champion, ne connaissiez pas l'existence de l'opérateur et en sélectionnant null en sql auparavant. Merci beaucoup l'homme! – Jimmy

2
SELECT 
    * 
FROM 
    Parent 
WHERE 
    EXISTS (SELECT * FROM Child WHERE Child.ParentId = Parent.Id AND [date] <= '2010-10-13') 
    AND 
    NOT EXISTS (SELECT * FROM Child WHERE Child.ParentId = Parent.Id AND [date] > '2010-10-13') 
0

Je lis votre question à fond et résumés ci-dessous:

  • lignes enfants peuvent exister avant, sur, ou après la date X
  • Je veux que tous les parents qui des enfants ont tous une date/avant Date X

Voir le code ci-dessous. Nous utilisons la déclaration d'avoir à faire que les enfants ne sont pas une date après X.

SELECT P.* 
FROM Parent P 
WHERE P.id IN 
(
    SELECT C.parentID 
    FROM Child C 
    GROUP BY C.parentID 
    HAVING MAX(CASE WHEN date > '2010-10-13' THEN 1 ELSE 0 END) = 0 
    /* do not return children that have a date after 2010-10-13 */ 
) 

Schéma de l'échantillon pour ceux qui veulent jouer le long. (SQL Server)

("date" est appelée "mydate" pour éviter d'avoir à échapper au mot réservé.)

CREATE TABLE Parent (id INT PRIMARY KEY); 
CREATE TABLE Child (id INT IDENTITY PRIMARY KEY, parentID INT NOT NULL REFERENCES Parent(id), mydate DATE); 

INSERT INTO Parent VALUES (1); 
INSERT INTO Parent VALUES (2); 
INSERT INTO Parent VALUES (3); 
INSERT INTO Parent VALUES (4); 

INSERT INTO Child (parentID, mydate) VALUES (1,'2010-10-11') 
INSERT INTO Child (parentID, mydate) VALUES (1,'2010-10-12') 
INSERT INTO Child (parentID, mydate) VALUES (1,'2010-10-13') 

INSERT INTO Child (parentID, mydate) VALUES (2,'2010-10-12') 
INSERT INTO Child (parentID, mydate) VALUES (2,'2010-10-13') 
INSERT INTO Child (parentID, mydate) VALUES (2,'2010-10-14') 

INSERT INTO Child (parentID, mydate) VALUES (3,'2010-10-14') 
INSERT INTO Child (parentID, mydate) VALUES (3,'2010-10-15') 
INSERT INTO Child (parentID, mydate) VALUES (3,'2010-10-16') 
+0

Dois-je noter qu'il s'agit d'un seul passage dans la table enfant? – beach