Why is this syntax not valid? - sql

The following code:
SELECT JaguarStartupTime, CPU, AmountOfRam, UpdatedOn, *
FROM dbo.MachineConfiguration
WHERE ServerName = 'WashingtonDC01'
AND UpdatedOn > '11/21/2012'
ORDER BY JaguarStartupTime DESC
results in an error: Ambiguous column name 'JaguarStartupTime'.
However, removing the ORDER BY makes it work. In addition, prefixing the ORDER BY clause with the table, like below, makes it work too:
SELECT JaguarStartupTime, CPU, AmountOfRam, UpdatedOn, *
FROM dbo.MachineConfiguration
WHERE ServerName = 'WashingtonDC01'
AND UpdatedOn > '11/21/2012'
ORDER BY dbo.MachineConfiguration.JaguarStartupTime DESC
This never made sense to me. Can someone explain?

Because the query includes * (all columns) in the SELECT clause, which also includes the column JaguarStartupTime.
In Layman's terms:
So in the retrieval of the results, the column shows up twice, and then when the server tries to apply the sort order, it's not sure which column you are referring to.
Personally, I'd change the query to eliminate the use of * in the query, even if it means listing a long list of column names. It's best practice, and it will avoid this issue.
As for why it works when prefixed, I found this in the MSDN documentation:
In SQL Server, qualified column names and aliases are resolved to
columns listed in the FROM clause. If order_by_expression is not
qualified, the value must be unique among all columns listed in the
SELECT statement.
This is simply part of the DB engine's underlying mechanism for translating SQL statements into the execution plan.

I agree that in the case in your question ORDER BY JaguarStartupTime is not really ambiguous as both projected columns in fact refer to the same underlying column.
In the general case however there is no guarantee that this will be true. As discussed in the response to this connect item. For example in the following query it is clearly ambiguous which one would be used.
SELECT JaguarStartupTime,
CPU AS JaguarStartupTime
FROM dbo.MachineConfiguration
ORDER BY JaguarStartupTime DESC
For syntax validation purposes SQL Server does not do any analysis of column names to determine whether they are really ambiguous or not. When ordering by some_name that is present in the list of projected column names the some_name must be unique. This is as per the ANSI spec
If a <sort specification> contains a <column name>, then T
shall contain exactly one column with that <column name> and
the <sort specification> identifies that column.
Qualifying the column name with the table name ensures to SQL Server that you are ordering by a source column name rather than a projected column name so it allows it.
SELECT name, name
FROM master..spt_values v1
ORDER BY v1.name
Additionally the following query is allowed.
select name, name
FROM master..spt_values v1
ORDER BY name + ''
The reason why this is not ambiguous is because column aliases in an ORDER BY clause can only be used by themselves rather than in an expression so in the above query name can not be interpreted as an alias and must be interpreted as ordering by v1.name.

Related

How can you filter Snowflake EXPLAIN AS TABULAR syntax when its embedded in the TABLE function? Can you filter it with anything?

I have a table named Posts I would like to count and profile in Snowflake using the current Snowsight UI.
When I return the results via EXPLAIN using TABLULAR I am able to return the set with the combination of TABLE, RESULT_SCAN, and LAST_QUERY_ID functions, but any predicate or filter or column reference seems to fail.
Is there a valid way to do this in Snowflake with the TABLE function or is there another way to query the output of the EXPLAIN using TABLULAR?
-- Works
EXPLAIN using TABULAR SELECT COUNT(*) from Posts;
-- Works
SELECT t.* FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())) as t;
-- Does not work
SELECT t.* FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())) as t where operation = 'GlobalStats';
-- invalid identifier 'OPERATION', the column does not seem recognized.
Tried the third example and expected the predicate to apply to the function output. I don't understand why the filter works on some TABLE() results and not others.
You need to double quote the column name
where "operation"=
From the Documentation
Note that because the output column names from the DESC USER command
were generated in lowercase, the commands use delimited identifier
notation (double quotes) around the column names in the query to
ensure that the column names in the query match the column names in
the output that was scanned

Ambiguous column name for order by the selected column

I never notice below before:
SELECT A,*
FROM Table
ORDER BY A
It gives me the Ambiguous column name error. The * of course contains A, but will sql server take the same column A in above query as two different columns? Is this the reason behind that?
it is because the output has the same name if you did
SELECT A AS A_STANDS_ALONE,*
FROM Table
ORDER BY A
It will work
If you are looking for yes/no answer, then 'YES', you are right.
SQL Selects A column twice, one by explicit and one by the implicit * call.
SQL doesn't understand which one you want to sort by.
The first comment to your post shows that you can use an alias for the column.

Why I must put "AS" clause at the end of subquery.?

I saw this thread:
SELECT
MAX(totalcontracts) AS highest_total
FROM ( SELECT
SuperVisor
,COUNT(ContractNo) AS totalcontracts
FROM Contract
GROUP BY SuperVisor
) AS t
If I delete "as t" line that return me an error. but when I put it back that work fine.
This is temporarly so why do I required to put a name to that subtable?Any sense in that?
Thank you.
In standard SQL a derived table (a subquery you select data from) needs a name:
FROM (<subquery>) [AS] <name>`
(Some DBMS, however, are not compliant with the standard. In Oracle for instance it is not mandatory to give a derived table an alias, but the optional AS is forbidden when you specify one. Other DBMS on the other hand may require the AS although the SQL standard specifies it as optional.)
No, there isn't a real logic necessity here.
Oracle for instance does not force it
select * from (select * from dual);
Nor SQLite
select * from (select 1)
As #jarlh mentioned, if you're using some database systems, in order to use the result from any nested subquery you need to give that result-set a name (or alias), which is why you need to put a name / letter / character after you close the paranthesis.
The AS keyword is not mandatory, but the name is.

Using an Alias column in the where clause in ms-sql 2000

I know you cannot use a alias column in the where clause for T-SQL; however, has Microsoft provided some kind of workaround for this?
Related Questions:
Unknown Column In Where Clause
Can you use an alias in the WHERE clause in mysql?
“Invalid column name” error on SQL statement from OpenQuery results
One workaround would be to use a derived table.
For example:
select *
from
(
select a + b as aliased_column
from table
) dt
where dt.aliased_column = something.
I hope this helps.
Depending on what you are aliasing, you could turn it into a user defined function and reference that in both places. Otherwise your copying the aliased code in several places, which tends to become very ugly and means updating 3+ spots if you are also ordering on that column.

error with a sql query because of ambiguous column name

I'm trying to create a sql query, but there is this error:
Ambiguous column name 'description'.
Its because this column occurs in both tables.
if I remove the description from the query, it works.
I tried to rename the description-field "AS description_pointer", but the error still occurs.
SELECT TOP 1000 [activityid]
,[activitytypecodename]
,[subject]
,[regardingobjectid]
,[contactid]
,[new_crmid]
,[description] AS description_pointer
FROM [crmtestext_MSCRM].[dbo].[FilteredActivityPointer] as I
Left JOIN [crmtestext_MSCRM].[dbo].[FilteredContact]
ON I.[regardingobjectid] = [crmtestext_MSCRM].[dbo].[FilteredContact].[contactid]
WHERE new_crmid not like '%Null%' AND activitytypecodename like '%E-mail%'
Both tables coming into play in the query have a column named description. You RDBMS cannot guess which column table you actually want.
You need to prefix the column name with the table name (or table alias) to disambiguate it.
Bottom line, it is a good practice to always prefix column names with table names or aliases as soon as several tables come into play in a query. This avoids the issue that you are seeing here and make the queries easier to understand for the poor souls that have no knowledge of the underlying schema.
Here is an updated version of your query with table aliases and column prefixes. Obviously you need to review each column to put the correct alias:
SELECT TOP 1000
i.[activityid]
,i.[activitytypecodename]
,i.[subject]
,c.[regardingobjectid]
,c.[contactid]
,c.[new_crmid]
,c.[description] AS description_pointer
FROM [crmtestext_MSCRM].[dbo].[FilteredActivityPointer] as i
Left JOIN [crmtestext_MSCRM].[dbo].[FilteredContact] as c
ON i.[regardingobjectid] = c.[contactid]
WHERE i.new_crmid not like '%Null%' AND i.activitytypecodename like '%E-mail%'