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/2009 和 TypeName(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(您能否发布一些代码和数据来重现该问题?因为这是 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 Server 2005 切换到 SQL Server 2012 有啥并发症吗?
使用 MS Access 2003 连接到 SQL Server 2005