2010-01-12 4 views
1

J'ai une table « défauts » dans le format suivant:simple requête dans apparemment Pl Sql

id status stat_date line div area 
1 Open 09/21/09 F  A cube 
1 closed 01/01/10 F  A cube 
2 Open 10/23/09 B  C Back 
3 Open 11/08/09 S  B Front 
3 closed 12/12/09 S  B Front 

Mon problème est que je veux écrire une requête qui vient d'extraire les défauts « Open ». Si j'écris une requête pour extraire simplement tous les défauts ouverts, alors j'obtiens le mauvais résultat parce qu'il y a quelques défauts, qui ont 2 enregistrements qui lui sont associés. Par exemple, avec la requête que j'ai écrite, j'obtiendrais les ID de défaut 1 et 3 dans mon résultat, même s'ils sont fermés. J'espère avoir bien expliqué mon problème. Je vous remercie.

+0

Est-ce un problème avec vos données? Devrait-il y avoir deux entrées avec le même identifiant? – Paddy

+0

Le problème est définitivement avec les données mais c'est ce qu'ils me donnent donc je dois essayer de travailler avec. – jen

Répondre

0

Cela devrait obtenir ce que vous voulez. Je n'aurais pas de dossier pour ouvrir et fermer un défaut, mais juste un seul enregistrement pour suivre un seul défaut. Mais ce n'est peut-être pas quelque chose que vous pouvez changer facilement.

SELECT id FROM defects 
WHERE status = 'OPEN' AND id NOT IN 
(SELECT id FROM defects WHERE status = 'closed') 
+0

Cela ne fonctionne pas si le défaut a été rouvert par la suite. – RedFilter

+0

Merci. Cela fonctionne très bien. Je suis étonné de voir combien de façons différentes d'obtenir les bons résultats. Merci encore. Les défauts ne sont pas autorisés à être rouverts, au moins je n'ai pas à m'inquiéter à ce sujet. Merci encore! – jen

1
Select * 
from defects d 
where status = 'Open' 
and not exists (
    select 1 from defects d1 
    where d1.status = 'closed' 
    and d1.id = d.id 
    and d1.stat_date > d.stat_date 
) 
+1

Cela ne fonctionne pas si le défaut a été rouvert par la suite. – RedFilter

+0

OK, édité pour vérifier la date d'état Ouvert> fermé –

1

Donc, vous voulez obtenir la dernière ligne par id et de ceux-ci, ne sélectionnez ceux qui sont ouverts. Ceci est une variation du problème commun greatest-n-per-group.

je le ferais de cette façon:

SELECT d1.* 
FROM defects d1 
LEFT OUTER JOIN defects d2 
    ON (d1.id = d2.id AND d1.stat_date < d2.stat_date) 
WHERE d2.id IS NULL 
    AND d1.status = 'Open'; 
+0

Diriez-vous que cela fonctionne généralement mieux que le groupe par la méthode? Mes instincts me disent non, comme vous devez faire une comparaison de date sur chaque disque, mais n'ont pas testé cela. – RedFilter

+0

Cela fonctionne très bien. Merci un million car je travaillais là-dessus depuis quelques jours et j'étais vraiment frustré. – jen

+1

@OrbMan: La solution qui fonctionne le mieux dépend de la mise en œuvre du SGBDR et de votre jeu de données spécifique. Vous devez donc vérifier les deux requêtes sur les données réelles. J'espère que le SGBDR peut comparer deux dates efficacement, surtout si elles sont indexées. –

2

Utilisation:

SELECT t.* 
    FROM DEFECTS t 
    JOIN (SELECT d.id, 
       MAX(d.stat_date) 'msd' 
      FROM DEFECTS d 
     GROUP BY d.id) x ON x.id = t.id 
         AND x.msd = t.stat_date 
WHERE t.status != 'closed' 
  1. La jointure devient de la date la plus récente pour chaque valeur id.
  2. Rejoindre la table d'origine sur la base de la id et date afin d'obtenir seulement les lignes les plus récentes.
  3. Filtrer sur ces lignes avec l'état fermé à savoir celles qui sont actuellement ouverts
0

Cette requête gère plusieurs ouvre/ferme/ouvre, et ne fait qu'une seule passe à travers les données (c.-à-pas d'auto-jointures) :

SELECT * FROM 
(SELECT DISTINCT 
     id 
     ,FIRST_VALUE(status) 
     OVER (PARTITION BY id 
       ORDER BY stat_date desc) 
     as last_status 
     ,FIRST_VALUE(stat_date) 
     over (PARTITION BY id 
       ORDER BY stat_date desc) 
     AS last_stat_date 
     ,line 
     ,div 
     ,area 
FROM defects) 
WHERE last_status = 'Open';