2012-04-02 2 views
0

je reçois une erreur quand je fais ce qui suit:erreur corrélation des champs

SELECT * 
from cGift c1 left join 
    (select c2.gidnumb, "t" new from cGift c2 where c2.gidnumb = 
     (select c3.gidnumb from cgift c3 where c3.id = c2.id and c3.date = 
      (select min(c4.date) from cgift c4 where c2.id == c4.id))) tNew 
    on tNew.gidnumb = c1.gidnumb 

Fondamentalement j'ai la table cgift une liste de dons sur elle. J'ai besoin d'une requête qui retourne cgift avec une colonne supplémentaire contenant "t" ou null. Le premier don (cgift.date) de chaque donneur (cgift.id) devrait être "t", le reste étant nul.

Exemple:

gidnumb..id....date......new 
10.......1.....2/1/2010..null 
11.......2.....1/1/2010..t 
12.......3.....1/1/2010..t 
13.......1.....3/1/2010..null 
14.......2.....2/1/2010..null 
15.......4.....1/1/2010..t 
16.......1.....1/1/2010..t 

Les valeurs nulles pourrait être blancs ou f ou WTVR.

Quelqu'un peut-il me dire quel est le problème avec ma requête, il me rend fou.

Répondre

2

Je pense que les éléments suivants devraient travailler dans à peu près tous les produits SQL:

SELECT 
    cGift.gidnumb, 
    cGift.id, 
    cGift.date, 
    first.isfirst 
FROM cGift 
LEFT JOIN (
    SELECT id, MIN(date) AS date, 't' AS isfirst 
    FROM cGift 
    GROUP BY id 
) first ON cGift.id = first.id AND cGift.date = first.date 

MISE À JOUR (portant sur des critères supplémentaires):

Si une personne peut donner plus d'une fois sur MIN(date) et que vous voulez un don à marquer avec t, vous pouvez, par exemple, faites ceci:

SELECT 
    cGift.gidnumb, 
    cGift.id, 
    cGift.date, 
    first.isfirst 
FROM cGift 
LEFT JOIN (
    SELECT 
     MIN(g.gidnumb) AS g.gidnumb, 
     g.id, 
     g.date, 
     't' AS isfirst 
    FROM cGift g 
    INNER JOIN (
     SELECT id, MIN(date) AS date 
     FROM cGift 
     GROUP BY id 
    ) f ON g.id = f.id AND g.date = f.date 
    GROUP BY g.id, g.date 
) first ON cGift.id = first.id AND cGift.date = first.date 

C'est, la requête la plus interne trouve jours minimum pour chaque personne, comme dans la solution précédente, mais il détaille également la liste avec des valeurs spécifiques gidnumb, en s'assurant que seulement une ligne par personne correspondra à cette liste dans la table cGift.

Cette requête doit toujours pouvoir être exécutée dans n'importe quel SGBD. Il pourrait bien être moins efficace, étant donné le double groupement. Voici une alternative qui utilise uniquement SQL standard, pas de fonctionnalités spécifiques au fournisseur (il devrait aussi être un peu plus flexible que la requête précédente) aussi:

SELECT 
    gidnumb, 
    id, 
    date, 
    CASE 
     WHEN NOT EXISTS (
      SELECT * 
      FROM cGift 
      WHERE id = g.id 
       AND (
        date < g.date OR 
        date = g.date AND gidnumb < g.gidnumb 
       ) 
     ) 
     THEN 't' 
    END AS isfirst 
FROM cGift g 

Comme vous pouvez le voir, on calcule la colonne isfirst à l'aide d'un auto-test sur la table: s'il n'y a pas de ligne dans ce tableau avec la même id et soit la date antérieure ou, si la date est la même, moins gidnumb, cette ligne doit être marquée comme t.En l'absence de ELSE une partie des CASE, ELSE NULL est implicite. Vous pouvez, si vous aimez ajouter quelque chose comme ELSE 'f'. Cependant, votre produit SQL peut posséder des fonctionnalités dont vous pourriez bénéficier en construisant une requête peut-être plus simple et plus efficace. Certains produits, par exemple, prennent en charge les fonctions de classement (qui font partie de la norme SQL trop déjà, il est juste qu'ils ne sont pas encore universellement pris en charge), et voici ce que vous pourriez faire avec une fonction de classement appelé ROW_NUMBER():

SELECT 
    gidnumb, 
    id, 
    date, 
    CASE ROW_NUMBER() OVER (PARTITION BY id ORDER BY date, gidnumb) 
     WHEN 1 
     THEN 't' 
    END AS isfirst 
FROM cGift g 

Cette requête classe les lignes en les partitionnant par id et en triant d'abord par date, puis par gidnumb. Chaque ligne avec le classement de 1 dans ce cas devient celui qui devrait être distingué avec t.

+0

merci, cela a fonctionné parfaitement – slicedtoad

+0

OK, une chose a mal tourné. Apparemment, certaines personnes ont donné deux fois ou plus le même jour, ce qui a eu pour résultat que les gens ont plusieurs personnes. Puis-je utiliser gidnumb (toujours unique) comme deuxième critère pour min()? J'ai essayé mais j'ai des problèmes avec le groupage et la jointure. note: je ne peux pas utiliser 'min (gidnumb)' au lieu de 'min (date)' car gidnumb n'est pas toujours dans l'ordre des dates. – slicedtoad

+0

@slicedtoad: S'il vous plaît voir ma mise à jour. –

1

Je ne vois aucune erreur dans votre requête.

Mais je recommande une légère modification à votre requête.

Cela renverra premier don pour chaque id

SELECT id, gidnymb, date, "t" As new_column 
FROM cGift 
GROUP BY id 
HAVING date = MIN(date); 

Cela renverra les dons suivants

SELECT id, gidnymb, date, null AS new_column 
FROM cGift 
LEFT JOIN (
    SELECT id, gidnymb, date, "t" As new_column 
    FROM cGift 
    GROUP BY id 
    HAVING date = MIN(date) 
) USING(id) 
WHERE new_column IS NULL 

Maintenant, intégrez l'aide UNION.

(SELECT id, gidnymb, date, "t" As new_column 
FROM cGift 
GROUP BY id 
HAVING date = MIN(date)) 

UNION 

(SELECT id, gidnymb, date, null AS new_column 
FROM cGift 
LEFT JOIN (
    SELECT id, gidnymb, date, "t" As new_column 
    FROM cGift 
    GROUP BY id 
    HAVING date = MIN(date) 
) USING(id) 
WHERE new_column IS NULL) 

Je ne l'ai pas testé, mais vous avez l'idée.

+0

à droite, vous pouvez mettre min après la clause having, totalement oublié à ce sujet. Cela devrait le rendre beaucoup plus simple. – slicedtoad

+0

pas sûr si c'est ma plate-forme, mais toute variation de ce résultat entraîne des erreurs. Je vais utiliser la solution d'Andriy, merci. – slicedtoad

0

Dans SQL Server 2005+ vous pouvez le faire

SELECT 
    gidnumb, 
    id, 
    Date, 
    CASE RANK() OVER (PARTITION BY id ORDER BY Date) 
     WHEN 1 Then 't' 
     ELSE Null 
    END 
FROM 
    cGift 
Questions connexes