Access 2003 SQL Switch ломает типы данных? - PullRequest
0 голосов
/ 07 октября 2009

Я использую Access 2003. Я использую Switch для выбора полей даты на основе логического критерия:

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

Т.е., если "критерий" является истинным, тогда вернуть Date1, иначе вернуть Date2.

Дата1 и Дата2 - столбцы типа Дата / Время в таблице.

Проблема в том, что Switch возвращает их как текст, а не как дату / время!

Есть ли способ заставить их в свидание? Я пытался

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

И

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

Оба из них терпят неудачу с тем или иным сообщением об ошибке.

Есть идеи?

Ответы [ 3 ]

2 голосов
/ 07 октября 2009

Я думаю, что функция Immediate If [IIf ()] лучше подходит для того, что вы пытаетесь сделать:

IIf(<criterion>, Date1, Date2)

Но функция Switch () не должна разбивать типы данных и не является несовместимой с типами данных даты / времени. Рассмотрим эту функцию:

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 («сегодня») возвращает 10/6/2009 и TypeName (trySwitch («сегодня»)) возвращает Дата

1 голос
/ 07 октября 2009

Не могли бы вы опубликовать код и данные, чтобы воспроизвести проблему, пожалуйста? Так как это SWITCH() в коде SQL, то я думаю, что SQL DDL (CREATE TABLE и т. Д.) И DML (INSERT INTO для добавления данных) будут наиболее подходящими:)

[Точный пункт: SQL базы данных Access не имеет логического типа данных. Он имеет тип данных YESNO, который может быть значением NULL; трехзначная логика не является логической.]

Вот некоторый SQL DML ( ANSI-92 Query Mode синтаксис), чтобы продемонстрировать, как он работает, как и ожидалось для меня:

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

Измените любое из значений критерия, и значение всегда будет возвращаться как «Дата», то есть типа DATETIME.


UPDATE:

Эта TYPENAME функция является отличным инструмент ... Доступ, кажется, интерпретирует весь «столбец» набора результатов иначе

Действительно. Поскольку столбец может иметь только один тип данных, результаты TYPENAME() в строке могут вводить в заблуждение. Значения строк смешанных типов должны быть переведены в более высокий тип данных. Как обычно с Access Database Engine, процесс полностью непрозрачен, а документация по этому вопросу полностью отсутствует, так что вам просто нужно пососать его и посмотреть, например,

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

возвращает 'Date' и 'Decimal' соответственно, но каков будет столбец? Видимо, ответ:

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;

'Строка'?!

... что, конечно, даже не тип данных SQL Access Database Engine. Так что TYPENAME(), к сожалению, использует имя типа VBA «наилучшее соответствие». Например:

SELECT TYPENAME(CBOOL(0));

возвращает логическое значение, даже если, как обсуждалось выше, логический тип данных в SQL Access Engine Engine отсутствует. И

SELECT TYPENAME(my_binary_col)

возвращает 'String'. Обратите внимание, что то же ограничение отображения VBA применяется к функциям CAST (еще одно раздражение), например. нет функции приведения к BINARY и функция CDEC() не работает с Jet 4.0: (

1 голос
/ 07 октября 2009

В вашем примере что-то странное.

Switch принимает пары выражений, и если первое значение оценивается как True, его парное значение возвращается, в противном случае оно переходит ко второму и оценивает этот аргумент.

Похоже, вы рассматриваете 1 как True, что так, потому что это не Fales, но вам будет лучше:

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

Но это всего лишь дублирование функциональности Immediate If, ​​функции IIf () и IIf () принимают меньше аргументов.

Но у него та же проблема, что он возвращает вариант. Но вы должны быть в состоянии привести это к типу данных, который может быть отформатирован как Дата.

Но будет ли этот вариант неявно принудительно приведен в исполнение или вам нужно будет сделать это явно, зависит от того, где вы его используете. В результате запроса можно отсортировать выходные данные из IIf ([критерий], Дата1, Дата2) в качестве даты, поскольку столбец приводится к типу даты.

Если вам нужно сделать явное приведение, CDate () - это функция, которую нужно использовать - вы должны обернуть внешнюю функцию, которая производит вывод Variant, функцией CDate (), чтобы быть уверенным, что вывод варианта явно приведено к типу даты:

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

Но я вполне мог бы упустить что-то важное здесь, поскольку я, кажется, ухожу на совершенно другую дорожку ...

...