2010-01-29 6 views
0

Fondamentalement j'ai la requête suivante qui fonctionne mais ne donne pas les bonnes données:opérations de table SQL TO_DATE

SELECT a.* FROM 
    (SELECT a.*, rownum rnum FROM ( 

    SELECT 

     edate.expiration_date 

     FROM 
     ... 

     (SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') expiration_date 
     FROM ...) edate 
) a WHERE rownum <= 20) 
a WHERE rnum >= 1 AND 
expiration_date < to_date('1/29/2010', 'MM/DD/YYYY HH24:MI:SS') 

La raison pour laquelle il ne fonctionne pas est que parce que les évaluations rownum/RNUM sont fait en même temps que le contrôle de date, il ne reçoit que les rownums (par exemple) 1, 4, 6, 9 qui ont des dates antérieures au 29/01/2010, au lieu des 20 premières dates qui ont une date inférieure à 1/29/2010.

Donc, fondamentalement, la zone

expiration_date < to_date('1/29/2010', 'MM/DD/YYYY HH24:MI:SS') 

doit être mis à l'intérieur des SELECTs internes, mais chaque fois que j'essaie de le faire je reçois une erreur mois invalide . Comment puis-je convertir les sélections ou les sous-requêtes en to_date s pour que cela fonctionne?

+0

"J'ai la requête suivante qui fonctionne mais ne donne pas les bonnes données" est une définition intéressante d'une requête qui fonctionne;) – APC

+1

Toutes vos valeurs de données sont-elles des dates valides? – PenFold

Répondre

1

Sur la base des informations contenues dans votre question, les trois 1ères réponses et commentaires ultérieurs, il semble en fait que cela n'a rien à voir avec les 20 premières valeurs, c'est un hareng rouge. Il semble que cela puisse avoir à voir avec la logique cachée dans la sélection la plus interne. Je crois que quelque chose là-dedans supprime les enregistrements de la table C afin que le TO_DATE sur C.Value ne se produise pas sur les champs qui ne sont pas des dates valides, mais lorsque vous ajoutez le To_Date (c.Valeur, 'MM/JJ/AAAA HH24: MI: SS') < to_date ('1/29/2010', 'MM/JJ/AAAA') à votre SQL le plus interne il se produit sur tous les champs dans le tableau C . vous devriez pouvoir éviter cela en changeant simplement votre extérieur et première clauses intégrées OU

SELECT a.* FROM 
    (SELECT a.*, rownum rnum FROM 

     (SELECT 

       edate.expiration_date 

     FROM 
     ... 

      (SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') expiration_date 
      FROM ...) edate 
    ) a 
    WHERE expiration_date < to_date('1/29/2010', 'MM/DD/YYYY HH24:MI:SS') 
) a 
WHERE rnum >= 1 AND 
     rownum <= 20 

Si cela est impossible en raison d'une autre logique qui ne peut pas être changé, vous devriez être en mesure d'ajouter une clause WHERE à l'intérieur du plus "a" pour expiration_date < TO_DATE ('1/29/2010', 'MM/JJ/AAAA')

Personnellement, j'essaierais de réparer les données si elles ne sont pas valides, donc vous ou d'autres ne rencontrent pas encore cela dans le futur, mais vous pouvez aussi utiliser la fonction d'APC quand acce ssing ce domaine dans le futur.

+0

Merci. Cela semble utile et je vais essayer. – Rio

+0

Avez-vous de la chance de le faire fonctionner ou de trouver de mauvaises données? – Craig

1

Ainsi, en laissant de côté tous les trucs liés autour pagination voulez-vous cette requête:

SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') expiration_date 
    FROM ... 
WHERE To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') 
     < to_date('1/29/2010', 'MM/DD/YYYY') 

Juste en cours d'exécution qui lui-même, est-il échoué?

+0

Oui c'est le cas. Il revient avec une erreur "mois non valide". – Rio

+1

Peut-être que certaines valeurs de valeurs contiennent de mauvaises données, par ex. '99/01/2010 '? Pourquoi cette date est-elle conservée dans un VARCHAR2? –

2

Il me semble probable que c.value contient des valeurs qui ne sont pas des dates. C'est juste qu'aucun d'entre eux ne se trouve dans les vingt premières rangées. La requête réussit donc lorsque le TO_DATE() est appliqué dans la requête externe, car la conversion est uniquement appliquée aux vingt premières valeurs. Toutefois, appliquer la conversion dans la requête interne signifie essayer de convertir toutes les lignes, y compris celles qui contiennent des valeurs qui ne sont pas des dates.

C'est l'un des pièges de l'utilisation d'une conception de base de données qui contient des données dans des colonnes de chaînes génériques au lieu d'utiliser les types de données pertinents.

Que faire à ce sujet? Évidemment, vous pouvez changer votre modèle de données afin que les dates soient conservées dans des colonnes définies avec le type de données DATE, mais je suppose que cela pourrait être plus de travail que ce que vous recherchez. L'alternative serait d'utiliser une bidouille comme celui-ci

create or replace function is_a_date 
    (p_str in varchar2 
    , p_mask in varchar2 := 'MM/DD/YYYY HH24:MI:SS') 
    return date 
is 
    return_value date; 
begin 
    begin 
     return_value := to_date(p_str, p_mask); 
    exception 
     when others then 
      return_value := null; 
    end; 
    return return_value; 
end; 
/

Cela prend une chaîne et tente de le convertir à une date en utilisant le masque de format. Si elle est une date dans le format approprié, il renvoie la date, sinon il retourne null:

SQL> select is_a_date('01/01/2000 23:56:07') from dual 
    2/

IS_A_DATE 
--------- 
01-JAN-00 

SQL> select is_a_date('APC is not a date') from dual 
    2/

IS_A_DATE 
--------- 


SQL> 
+0

Cela semble plausible. Est-ce que je ne peux pas simplement utiliser un enveloppement NVL autour de la déclaration? – Rio

+0

Une chose qui réfute l'hypothèse que c.value contient des valeurs qui ne sont pas des dates est que la requête pour N nombres de lignes (où N> 20) fonctionne. Le seul problème est que je ne peux pas limiter ces requêtes avec succès, de sorte que les "vingt premières lignes" finissent par devenir comme "les lignes 1, 4, 6, 9, 18". – Rio

+0

@Rio - alors quelles données * avez-vous dans 'c.value'? Vous pouvez réellement interroger la table de sorte que, contrairement à nous, vous n'avez pas à faire d'hypothèse. – APC

0

Je recommande vraiment vous fixer le modèle de données et les valeurs de date de magasin dans une colonne séparée. A défaut, vous pourriez essayer d'ajouter

where ltrim(substr(c.value,1,3),'0 ') in ('1/','2/',...'12/') 

Si la valeur entrante est « 31/01/2010 » plutôt que « 31/01/2010 » ou « 31/01/2010 » vous devez changer le filtre en conséquence. Regardez la correspondance REGEX.

Mais à moins que vous résoudre ce modèle, vous allez perdre beaucoup plus de temps sur ce