2010-01-18 6 views
1

J'écris actuellement une application Delphi qui exécute des requêtes sur une base de données DB2 à l'aide d'ADO. L'une des conditions est que l'utilisateur puisse définir des requêtes en utilisant des dates, par exemple "montrez-moi toutes les données des 60 derniers jours" ou "montrez-moi toutes les données entre le 20 novembre 2009 et le 18 janvier 2010". Ce ne serait pas un problème, sauf pour deux faits:Algorithme d'intervalle de dates SQL

  1. Les dates sont stockées dans la base de données en utilisant différents champs pour le jour, le mois et l'année.
  2. Les bases de données sont utilisées depuis plusieurs années sur plusieurs sites clients et ne peuvent pas être modifiées. L'application doit donc être exécutée sur les bases de données existantes (pas de modification de la base de données pour stocker les dates). la tâche beaucoup plus simple).

Ce que je dois savoir, c'est s'il existe un algorithme efficace pour construire le SQL requis pour extraire les informations spécifiées de la base de données. Par exemple, aujourd'hui est le 18 Janvier, afin d'extraire toutes les informations du 20 Novembre à aujourd'hui, je besoin d'une instruction SQL qui ressemble à ceci:

SELECT data WHERE 
((day >= 20) AND (month = 11) AND (year = 2009)) OR 
((month = 12) AND (year = 2009)) OR 
((day <= 18) AND (month = 1) AND (year = 2010)) 

Évidemment, cela est un exemple trivial et relativement simple, mais si l'utilisateur voulait récupérer des données à partir de novembre 2008 au lieu de 2009, la requête serait beaucoup plus grande.

Est-ce la seule façon de construire l'instruction SQL, ou existe-t-il un moyen plus efficace de le faire?

+0

Vous ne pouvez pas ajouter une vue pour convertir les parties de date en un objet de date unique et interroger la vue? –

Répondre

1

La réponse fournie par Galghamon SQL Date Interval Algorithm est efficace en termes de code, mais ne sera pas en mesure de tirer parti des index.

Je vous suggère d'effectuer tous les calculs nécessaires à Delphi afin que votre logique peut être conceptuellement réduite à une des opérations suivantes:

(DateCol > @DateVal) 
(DateCol >= @DateVal) 
(DateCol < @DateVal) 
(DateCol <= @DateVal) 
(DateCol = @DateVal) 

Ceux-ci peuvent ensuite être élargis pour votre plutôt malheureux schéma comme suit (en utilisant 1er 2 exemples):

(YearCol > @YearVal OR (YearCol = @YearVal AND MonthCol > @MonthVal) OR (YearCol = @YearVal AND MonthCol = @MonthVal AND DayCol > @DayVal)) 
(YearCol > @YearVal OR (YearCol = @YearVal AND MonthCol > @MonthVal) OR (YearCol = @YearVal AND MonthCol = @MonthVal AND DayCol >= @DayVal)) 

REMARQUE: Vous devez être précis sur l'endroit où l'utilisation inclusive et où utiliser les opérateurs d'inégalité exclusifs.

1

Vous pouvez le construire pour convertir l'année/mois/jour en un type de données de date, mais cela empêcherait l'utilisation d'index, donc la performance pourrait être un problème.

Est-ce que db2 a calculé des colonnes sur lesquelles vous pourriez indexer et seriez-vous en mesure d'ajouter cela? Ou peut-être une vue qui peut avoir indexé/persisté des colonnes calculées?

Si vous avez des index sur l'année/mois/jour cependant, le code que vous avez serait probablement le meilleur pour la performance.

6

Dans DB2, ce qui suit devrait convertir vos colonnes distinctes en un type de date: date (année || mois || jour)

Si vous avez deux dates, vous pouvez utiliser la soustraction pour recevoir le nombre de jours entre les deux, de sorte que votre clause where peut inclure

Date

(année || mois || jour)> CURRENT_DATE - 60

+0

Comment est-ce que j'irais en incluant ceci pourtant dans une requête? Dire par exemple que je voulais récupérer toutes les données de date = 2009-12-31 à aujourd'hui. Comment date() correspond à la chaîne de requête? Ai-je raison de penser que date() prend trois valeurs entières comme paramètres (année, mois, jour)? Où puis-je référencer les champs associés à la date? Certaines des tables de base de données contiennent plus d'une information de date, donc je dois évidemment interroger les champs corrects. – Jeedee

+0

Date() prend une chaîne - Je concatène vos trois champs existants en utilisant le double-pipe || opérateur. Vous devriez pouvoir copier et coller littéralement ma déclaration dans votre clause where pour obtenir les 60 derniers jours. Si vous voulez tout à la fin de l'année dernière (y compris la fin de l'année) alors vous pouvez utiliser "WHERE date (année || mois | date)> = date ('20091231')". Je suppose que vos mois à un chiffre et vos jours sont stockés avec un zéro non significatif, vous devrez donc formater ces colonnes et le pad gauche avec "0" pour obtenir deux chiffres. Pour les comparaisons, vous pouvez supprimer la date(), car le tri alphabétique le fera. – Galghamon

+0

J'ai essayé d'utiliser la fonction DATE() et cela ne fonctionne pas. J'obtiens une erreur ("Argument * N de la fonction CONCAT non valide"), donc évidemment spécifier les champs dans la fonction DATE(), concaténés ensemble, ne fonctionne pas (sauf si j'ai totalement mal compris où c'est que je suis supposé référencer les champs à interroger). Ne pas s'inquiéter - je vais juste aller avec la réponse acceptée. Je pensais que votre réponse valait la peine d'essayer cependant. – Jeedee

0

En MSSQL, je voudrais essayer d'écrire une fonction pour renvoyer le nombre de jours écoulés depuis une la date de vos données. Dans Firebird, je ferais la même chose avec une fonction Delphi définie par l'utilisateur ou au moins une procédure stockée sélectionnable. Je ne sais pas s'il est possible d'étendre DB2 SQL avec l'une ou l'autre de ces deux options, mais si vous pouviez intégrer la logique dans quelque chose comme ça, cela faciliterait beaucoup votre travail. Je vois une mention de DB2 SQL UDF dans les publications connexes sur le côté droit de la page. J'espère que ceci est utile.

+0

Cela doit être l'option la plus compliquée. Vous voulez écrire une fonction qui devra prendre en compte le nombre variable de jours par mois, les années bissextiles par rapport aux années non bissextiles, et les exceptions à la règle de l'année bissextile? –

+0

Je suis d'accord avec vous Craig. Je ne suggérais pas d'aller dans cette direction non plus. Je ne suis pas familier avec DB2 SQL donc je ne savais pas qu'il y avait une fonction qui le rendrait aussi facile que ce que Galghamon a suggéré.J'avais peur qu'il soit plus difficile de construire une date à partir d'un jour, d'un mois et d'une année et de mettre un tas de code dans une fonction ou un UDF rendrait l'utilisation beaucoup plus facile. – jrodenhi

0

Étant donné que vous voulez comparer à une date, vous devez d'abord convertir les valeurs non-date. Cela vous permet de comparer date à date et à partir de là, c'est facile

+0

Identique à la réponse de Galghamon; mais le problème est que vous perdez le bénéfice des index. –

0

En ce qui concerne vos remarques sur les modifications de la base de données. Envisagez d'ajouter une seule colonne pour la date. Cette colonne ne sera écrite que par un déclencheur et si au moins une des colonnes jour, mois et année est mise à jour. Vous avez alors la liberté d'indexer cette colonne et de l'utiliser.

Vous n'aurez aucun impact sur les logiciels existants et vous bénéficierez de la commodité de la colonne de date. Rappelez-vous, le code que vous écrivez aujourd'hui, doit être lisible dans 6 mois par un autre développeur.

Donc, si vous ne pouvez toujours pas modifier le db, pensez à la solution de Galghamon, car elle est facile à comprendre (coûts d'entretien réduits). N'utilisez la solution de Craig Young que si les impacts sur les performances vous forcent à le faire.

+0

La base de données est sur le serveur et tous les logiciels côté serveur (ainsi que la maintenance de la base de données) sont effectués par une autre équipe. Le mandat de mon projet est d'être capable d'exécuter une requête à partir d'un PC sur la base de données existante/structure du programme sur le serveur, donc malheureusement je ne peux même pas ajouter de déclencheurs, etc Ma première pensée était bien sûr d'ajouter un seul colonne de date mais mes mains sont liées à celle-ci, d'où ma question. – Jeedee

Questions connexes