【问题标题】:Calculated column in wrong position when using `SELECT *`使用`SELECT *`时计算的列位置错误
【发布时间】:2011-07-08 10:31:03
【问题描述】:

考虑这个使用SELECT * 并“追加”计算列的查询:

SELECT *, 
       IIF(TRUE, 1, 0) AS calculated_col
  FROM Orders;

我希望calculated_col 是结果集中最右边的一列。但是,它实际上是最左边的列。例如,在 SQL Server 中执行等效查询时,它位于最右边。

现在,因为这是 Access(ACE、Jet 等),SQL 标准不适用,而且 Access 帮助不会指定预期结果,因为它不够详细(礼貌地说)。所以我的问题是:

Access 总是以这种方式运行,还是我的环境(ADO、OLE DB 提供程序等)的“功能”?

Access 在给定的环境中是否总是以这种方式运行? (即为什么我以前没有注意到这一点?)

附:我当然知道SELECT * 被广泛嘲笑,如果列的顺序对我很重要,那么我应该明确地把它们都写出来。然而,我真的对遇到的实际行为感到惊讶,并对我的问题的任何答案感兴趣。

这里有一些 VBA 来重现该行为:只需复制+粘贴到任何 VBA 模块中,不需要设置引用并且不需要安装 Access,例如使用 Excel 的 VBA 编辑器:

Sub ColumnOrderWrong()

  On Error Resume Next
  Kill Environ$("temp") & "\DropMe.mdb"
  On Error GoTo 0

  Dim cat
  Set cat = CreateObject("ADOX.Catalog")
  With cat
    .Create _
        "Provider=Microsoft.Jet.OLEDB.4.0;" & _
        "Data Source=" & _
        Environ$("temp") & "\DropMe.mdb"
    With .ActiveConnection

      Dim Sql As String
      Sql = _
      "CREATE TABLE Orders" & vbCr & _
      "(" & vbCr & " ID INTEGER, " & vbCr & _
      " customer_id" & _
      " INTEGER" & vbCr & _
      ");"
      .Execute Sql

      Sql = _
      "INSERT INTO Orders (ID, customer_id) VALUES" & _
      " (1, 2);"
      .Execute Sql

      Sql = _
      "SELECT *, " & vbCr & _
      "       IIF(TRUE, 55, -99) AS calculated_col" & vbCr & _
      "  FROM Orders;"
      Dim rs
      Set rs = .Execute(Sql)

      MsgBox _
      "Fields(0).Name = " & rs.Fields(0).Name & vbCr & _
      "Fields(1).Name = " & rs.Fields(1).Name & vbCr & _
      "Fields(2).Name = " & rs.Fields(2).Name

    End With
    Set .ActiveConnection = Nothing
  End With
End Sub

【问题讨论】:

  • 为什么你会在没有表名的情况下使用 *?如果你写了糟糕的 SQL,你会得到不可靠的结果,所以不要写糟糕的(即模棱两可的)SQL。
  • 在标准 SQL 中,结果是可预测且明确的。在 Access 中甚至没有定义结果,因此 Access IMO 是这里的“坏 SQL”。如果FROM 子句中只有一个表,为什么添加表名会对结果产生影响?
  • SQL 标准中是否真的定义了列顺序?还是只是除了 Jet/ACE 之外的每个人都只是习惯性地使用 SELECT 的顺序来显示字段?我当然可以看出这是多么合乎逻辑,但除非 SQL 标准定义了它应该如何呈现,否则我认为你没有立足之地。
  • @David-W-Fenton:我相信 SQL-92 规范的第 7.9 节(语法规则 3 和 4)和 7.4(一般规则案例 1b)涵盖了它,但承认我不是100% 确定。
  • @David-W-Fenton:试试this。

标签: sql ms-access vba oledb ado


【解决方案1】:

将您的选择语句更改为:

  Sql = _
       "SELECT Orders.*, " & vbCr & _
       "       IIF(TRUE, 55, -99) AS calculated_col" & vbCr & _
       "  FROM Orders;" 

通过声明表名,我认为它可以避免必须确定默认表是什么。

【讨论】:

    【解决方案2】:

    问题中的 SQL 代码受到 SQL 标准的禁止:当使用 * 时没有点限定(并且忽略特殊情况 COUNT(*)),则不会出现其他列。

    这为解决方案提供了线索:点限定* !!

    例如这按预期工作,calculated_column 出现在结果中的最右边一列:

    SELECT Orders.*, 
           IIF(TRUE, 1, 0) AS calculated_col
      FROM Orders;
    

    【讨论】:

      【解决方案3】:

      从你已经完成的调查来看,看起来你已经吃饱了。

      您可能必须按名称而不是位置来引用记录集的列。

      【讨论】:

      • 我宁愿想到的用法是在另一个 SQL 构造中使用查询构造,其中列顺序很重要,例如UNION 的逻辑表。记录集只是我用来查看结果的工具。
      猜你喜欢
      • 2021-09-08
      • 2017-07-01
      • 1970-01-01
      • 2015-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-19
      • 1970-01-01
      相关资源
      最近更新 更多