开发者

Calculated column in wrong position when using `SELECT *`

开发者 https://www.devze.com 2023-03-18 01:04 出处:网络
Consider this query that uses SELECT * and \'appends\' a calculated column: SELECT *, IIF(TRUE, 1, 0) AS calculated_col

Consider this query that uses SELECT * and 'appends' a calculated column:

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

I would expect calculated_col to be the rightmost column in the resultset. However, it is in fact the leftmost column. It is the rightmost when executing the equivalent query in SQL Server, for example.

Now, because this is Access (ACE, Jet, whatever), the SQL Standards don't apply and the Access Help will not specify the expected result because it is not detailed enough (to put it politely). So my questions are:

Does Access always behaved this way or is it a 'feature' of my environment (ADO, OLE DB provider, etc)?

Has Access always behaved this way in the given environment? (i.e. Why haven't I noticed this before?)

P.S. I know of course that SELECT * is widely derided and that if the order of columns is important to me then I should write them all out explicitly. However, I was genuinely suprised at the actual behaviour encountered and am interested in any answers to my questions.

Here's some VBA to reproduce the behaviour: just copy+paste into any VBA module, no references need to be set and Access need not be installed e.g. use Excel's VBA editor:

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") &开发者_StackOverflow中文版; "\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


Change your select statement to:

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

By declaring the table name, I think it prevents having to determine what is the default table.


The SQL code in the question is proscribed by the SQL standard: when * is used without dot-qualification (and disregarding the special case COUNT(*)) then no other columns may appear.

This gives a clue to the solution: dot-qualify the * !!

e.g. this works as expected, with calculated_column appearing as the rightmost column in the result:

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


From the investigations you've already done, it looks like you're stuffed.

You may have to reference the record set's column's by name rather than position.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号