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.
精彩评论