Access 2003 SQL Switch 会破坏数据类型?

Posted

技术标签:

【中文标题】Access 2003 SQL Switch 会破坏数据类型?【英文标题】:Access 2003 SQL Switch breaks data types? 【发布时间】:2009-10-06 23:59:29 【问题描述】:

我正在运行 Access 2003。我正在使用 Switch 根据布尔标准选择日期字段:

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

即,如果“标准”为真,则返回 Date1,否则返回 Date2。

Date1 和 Date2 是表中的日期/时间类型列。

问题是,Switch 将它们作为文本返回——而不是日期/时间!

有没有办法强迫他们进入约会状态?我试过了

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

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

两者都失败并显示一条或另一条错误消息。

有什么想法吗?

【问题讨论】:

【参考方案1】:

我认为 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("today") 返回 10/6/2009TypeName(trySwitch("today")) 返回 日期

【讨论】:

尽管有 David 和 onedaywhen 的有趣解释,但 IIf 仍然有效(我真的应该一开始就使用它)。有关差异的更多详细信息,请参阅我对 onedaywhen 答案的评论,但现在,我将只使用 IIf。【参考方案2】:

你的例子有些奇怪。

Switch 接受表达式对,如果第一个计算结果为 True,则返回其配对值,否则,它传递到第二个,并计算该参数。

您似乎将 1 视为 True,这是因为它不是 Fales,但您最好这样做:

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

但这只是对 Immediate If 函数的功能的复制,IIf() 和 IIf() 需要更少的参数。

但它也有同样的问题,因为它返回一个变体。但是您应该能够将其强制转换为可以格式化为日期的数据类型。

但该变体是否会被隐式强制或您需要显式执行,取决于您使用它的位置。在查询结果中,您可以将 IIf([criterion], Date1, Date2) 的输出排序为日期,因为该列被强制转换为日期类型。

如果您必须显式进行强制转换,CDate() 是要使用的函数——您可以使用 CDate() 函数包装产生 Variant 输出的外部函数,以确保显式地输出变体强制日期类型:

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

但我很可能在这里遗漏了一些重要的东西,因为我似乎走上了完全不同的轨道......

【讨论】:

有趣:当我将 Date2 包装在 Switch 内的 CDate() 中时,Access 将结果集列视为非日期类型(请参阅我对 onedaywhen 的评论)。但是当我将整个 Switch 语句包装在 CDate 中时,它会将列视为 Date 类型(通过相同的排序/单元格对齐标准)。即“Switch(, Date1, True, CDate(Date2))” 不等同于“CDate(Switch(, Date1, True, Date2))”。 [注意:这里 IIf 更好,因为当 Date1 为 Null 时它会返回 Null,而 Switch 看到 Null Date1 并返回 #Error#,弄脏结果集] 我并不是建议强制传递的参数,因为那些显然在那个时候具有正确的数据类型。正如您所发现的,您必须强制转换为正确的数据类型是 Switch() 或 IIf() 的 Variant 输出。我将进行编辑以使其更清晰。【参考方案3】:

您能否发布一些代码和数据来重现该问题?因为这是 SQL 代码中的SWITCH(),所以我认为 SQL DDL(CREATE TABLE 等)和 DML(INSERT INTO 添加数据)是最合适的:)

[挑剔点:Access 数据库 SQL 没有“布尔”数据类型。它有一个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 类型。


更新:

TYPENAME 功能很棒 工具... Access 似乎解释了 结果集的整个“列” 不一样

确实如此。因为一列只能是一种数据类型,所以该行的TYPENAME() 的结果可能会产生误导。混合类型的行值必须“提升”为更高的数据类型。与 Access 数据库引擎一样,该过程完全不透明,并且完全没有关于该主题的文档,因此您只需要吸吮它并查看例如

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

分别返回“日期”和“十进制”,但该列是什么?显然,答案是:

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;

'字符串'?!

...当然,这甚至不是 Access 数据库引擎 SQL 数据类型。所以TYPENAME() 很烦人地使用了“最合适”的 VBA 类型的名称。例如:

SELECT TYPENAME(CBOOL(0));

返回“布尔”,尽管如上所述,Access 数据库引擎 SQL 中没有布尔数据类型。和

SELECT TYPENAME(my_binary_col)

返回“字符串”。请注意,相同的 VBA 映射限制适用于 CAST 函数(又一个烦恼),例如没有'cast to BINARY'函数并且CDEC()函数自Jet 4.0以来仍然被破坏:(

【讨论】:

TYPENAME 函数是一个很棒的工具——为此 +1 和有用的故障排除提示。它告诉我我的值是 'Date' 和 'Null'(显然是 Null 条目),并且 IIf 表达式和 Switch 表达式中每行的类型结果相同。但是 Access 似乎对结果集的整个“列”有不同的解释:IIf 的日期(时间可排序,右对齐)和 Switch 的其他内容(仅词汇排序,左对齐)。 这是因为当 True 和 False 部分都是 Date 类型时,IIf() 将返回值强制转换为 Date() 子类型的 Variant。 Switch() 不这样做——它只是返回一个变体(可能是子类型 String),并且必须用 CDate() 显式强制。 @David W. Fenton:请记住,我们正在讨论 Access Database SQL 中使用的表达式,它没有 Variant 或 String 数据类型,尽管 TYPENAME() 可能会告诉你什么。

以上是关于Access 2003 SQL Switch 会破坏数据类型?的主要内容,如果未能解决你的问题,请参考以下文章

Access 2003 SQL:from 子句中的语法错误

Access 2003 VBA SQL“参数太少”错误

Access 2003:从 SQL Server 2005 切换到 SQL Server 2012 有啥并发症吗?

使用 MS Access 2003 连接到 SQL Server 2005

SQL 2005 使用 PHP 链接 Access 2003 DB 高级子查询

MS Access 2003 可以连接到的最新 SQL Server 后端是啥?