【问题标题】:Access 2003 SQL Switch breaks data types?Access 2003 SQL Switch 会破坏数据类型?
【发布时间】: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))

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

有什么想法吗?

【问题讨论】:

    标签: sql ms-access ms-access-2003


    【解决方案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() 可能会告诉你什么。
    猜你喜欢
    • 1970-01-01
    • 2014-11-07
    • 2013-04-19
    • 1970-01-01
    • 2016-12-25
    • 1970-01-01
    • 1970-01-01
    • 2012-05-13
    • 2021-09-09
    相关资源
    最近更新 更多