2009-10-06 7 views
0

Je suis en cours d'exécution Access 2003. Je l'aide du commutateur pour sélectionner des champs de date basée sur un critère booléen:Access 2003 SQL Switch casse les types de données?

Switch(<criterion>, Date1, 1, Date2) 

à savoir si « critère » est vrai, puis revenez Date1, sinon revenir Date2.

Date1 et Date2 sont des colonnes de type Date/Heure dans un tableau. Le problème est que Switch les renvoie en tant que texte - et non en date/heure!

Existe-t-il un moyen de les forcer dans Date-ness? J'ai essayé

Switch(<criterion>, #Date1#, 1, #Date2#) 

Et

Switch(<criterion>, Val(Date1), 1, Val(Date2)) 

qui deux échouent avec un message d'erreur ou d'une autre.

Des idées?

Répondre

2

Je pense que la fonction immédiate Si [IIf()] est une meilleure correspondance pour ce que vous essayez de faire:

IIf(<criterion>, Date1, Date2) 

Mais la fonction Switch() ne doit pas briser les types de données, et non incompatible avec les types de données date/heure. Considérez cette fonction:

Public Function trySwitch(ByVal pWhichDay As String) As Variant 
    Dim varOut As Variant 
    varOut = Switch(pWhichDay = "yesterday", Date - 1, _ 
     pWhichDay = "today", Date, _ 
     pWhichDay = "tomorrow", Date + 1) 
    trySwitch = varOut 
End Function 

trySwitch ("aujourd'hui") retours 10/6/2009 et TypeName (trySwitch ("aujourd'hui")) retours date

+0

Je suis d'accord essayez IIF() – CRice

+0

David's et unedayquand, malgré les explications intrigantes, le IIf a fonctionné (et j'aurais vraiment dû l'utiliser en premier lieu.) Voir mon commentaire onedaywhen la réponse pour plus de détails de la différence , mais pour l'instant, je vais juste utiliser IIf: – mikeh

1

Il y a quelque chose d'étrange avec votre exemple. Le commutateur accepte les paires d'expression, et si le premier est évalué comme vrai, sa valeur appariée est renvoyée, sinon, il passe à la seconde et évalue cet argument.

Vous semblez être traiter 1 vrai, qu'il est parce que ce n'est pas Fales, mais vous seriez mieux avec:

Switch(<criterion>, Date1, True, Date2) 

Mais c'est une réplique de la fonctionnalité de l'immédiat Si la fonction , IIf() et IIf() prend moins d'arguments.

Mais il a le même problème, en ce qu'il renvoie une variante. Mais vous devriez pouvoir le contraindre à un type de données pouvant être formaté en tant que date.

Mais que cette variante soit implicitement contrainte ou que vous deviez le faire explicitement, cela dépend de l'endroit où vous l'utilisez. Dans un résultat de requête, vous pouvez trier la sortie de IIf ([critère], Date1, Date2) comme une date, car la colonne est convertie en type date.Si vous devez exécuter la contrainte de manière explicite, CDate() est la fonction à utiliser - vous enveloppez la fonction externe qui produit la sortie Variant avec la fonction CDate() afin d'être certain que la sortie de la variante est explicitement sous la contrainte de type Date:

CDate(IIf(<criterion>, Date1, Date2)) 

Mais je pourrais très bien être manque quelque chose d'important ici, comme je semble être hors sur une piste complètement différente ...

+0

Intéressant: quand j'emballe Date2 dans un CDate() dans le Switch, Access traite la colonne resultset comme un type non-date (voir mon commentaire sur onedaywhen). Enveloppe toute l'instruction Switch dans CDate, elle traite la colonne comme un type Date (selon les mêmes critères de tri/justification de cellule) ie "Commutateur (, Date1, Vrai, CDate (Date2))" n'est pas équivalent à " CDate (Commutateur (, Date1, Vrai, Date2)) ". [Note: le IIf est encore meilleur ici, car il retournera Null lorsque Date1 est Null, tandis que Switch voit un Null Date1 et retourne un # Error #, salir le resultset] – mikeh

+0

Je ne suggérais pas de contraindre les arguments passés, car ceux-ci ont évidemment le bon type de données à ce moment-là. Ce que vous devez contraindre au bon type de données est la sortie Variant de Switch() ou IIf(), comme vous l'avez découvert. Je vais modifier pour le rendre plus clair. –

1

Pouvez-vous envoyer un code et des données reproduire le problème, s'il vous plaît? Comme cela est SWITCH() dans le code SQL, alors je pense que SQL DDL (CREATE TABLE etc) et DML (INSERT INTO pour ajouter des données) seraient les plus appropriés :)

[Point Picky: base de données Access SQL ne dispose pas d'un type de données 'boolean' . Il a un type de données YESNO qui peut être la valeur NULL; logique à trois valeurs est non booléenne]

Voici quelques SQL DML (ANSI-92 Query Mode syntaxe) pour montrer comment il fonctionne comme prévu pour moi.

SELECT TYPENAME 
     (
      SWITCH 
      (
      NULL, #2009-01-01 00:00:00#, 
      FALSE, #2009-06-15 12:00:00#, 
      TRUE, #2009-12-31 23:59:59# 
     ) 
     ); 

Modifiez les valeurs « critère » et la valeur est toujours retourné en tant que 'Date' ie de type DATETIME.


MISE À JOUR:

Cette fonction TYPENAME est un excellent outil ... L'accès semble interpréter la "colonne" entière du resultset différemment

En effet. Étant donné qu'une colonne ne peut être qu'un type de données, les résultats de TYPENAME() sur la ligne peuvent être trompeurs. Les valeurs de ligne de types mixtes doivent être «promues» à un type de données supérieur. Comme d'habitude avec le moteur de base de données Access, le processus est entièrement opaque et la documentation sur le sujet est complètement absente, donc vous devez juste le sucer et voir par exemple.

SELECT #2009-01-01 00:00:00# AS row_value, 
     TYPENAME(#2009-01-01 00:00:00#) AS row_type 
    FROM Customers 
UNION ALL 
SELECT 0.5, 
     TYPENAME(0.5) AS row_type 
    FROM Customers 

rendements Date »et « décimal » respectivement, mais ce sera la colonne être? Apparemment, la réponse est:

SELECT DT1.row_value, TYPENAME(DT1.row_value) AS column_type 
    FROM (
     SELECT DISTINCT #2009-01-01 00:00:00# AS row_value 
      FROM Customers 
     UNION ALL 
     SELECT DISTINCT 0.5 
      FROM Customers 
     ) AS DT1; 

'String' ?!

... ce qui bien sûr n'est même pas un type de données Access Database Engine SQL. Donc, TYPENAME(), de manière agaçante, utilise le nom du type VBA 'best fit'. Par exemple:

SELECT TYPENAME(CBOOL(0)); 

retourne 'Boolean', même si, comme indiqué plus haut, il n'y a aucun type de données Boolean dans Access Database Engine SQL. Et

SELECT TYPENAME(my_binary_col) 

renvoie 'Chaîne'. Notez que la même limitation de mappage VBA s'applique aux fonctions CAST (encore une autre gêne), par ex. il n'y a pas de fonction 'cast to BINARY' et la fonction CDEC() reste brisée depuis Jet 4.0 :(

+0

Cette fonction TYPENAME est un excellent outil - +1 pour cela et les conseils de dépannage utiles. Il me dit que mes valeurs sont 'Date' et 'Null' (pour les entrées nulles, évidemment), et les résultats de type par ligne sont les mêmes dans l'expression IIf et dans l'expression Switch. Mais Access semble interpréter différemment l'ensemble de la «colonne» du résultat: Date (temporellement triable, justifiée à droite) pour IIf, et autre chose (tri lexical uniquement, justifié à gauche) pour Switch. – mikeh

+0

Cela est dû au fait que IIf() contraint la valeur de retour à un Variant de sous-type Date() lorsque les parties Vrai et Faux sont de type Date. Switch() ne fait pas cela - il retourne juste une variante (probablement de sous-type String), et doit être explicitement contraint avec CDate(). –

+0

@David W. Fenton: rappelez-vous que nous discutons des expressions utilisées dans Access Database SQL, qui n'a pas de types de données Variant ou String, malgré ce que TYPENAME() pourrait vous dire. – onedaywhen

Questions connexes