Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can SELECT expressions sometimes be evaluated for rows not matching WHERE clause?

I would like to know if it's possible for expressions that are part of the SELECT statement list to be evaluated for rows not matching the WHERE clause?

From the execution order documented here, it seems that the SELECT gets evaluated long after the WHERE, however I ran into a very weird problem with a real-life query similar to the query below.

To put you in context, in the example, the SomeOtherTable has a a_varchar column which always contains numerical values for the code 105, but may contain non-numerical values for other codes.

The query statement works:

    SELECT an_id, an_integer FROM SomeTable

    UNION ALL

    SELECT an_id, CAST(a_varchar AS int)
    FROM SomeOtherTable
    WHERE code = 105

The following query complains about being unable to cast a_varchar to int:

SELECT 1
FROM (
    SELECT an_id, an_integer FROM SomeTable

    UNION ALL

    SELECT an_id, CAST(a_varchar AS int)
    FROM SomeOtherTable
    WHERE code = 105
) i
INNER JOIN AnotherOne a
    ON a.an_id = i.an_id

And finally, the following query works:

SELECT 1
FROM (
    SELECT an_id, an_integer FROM SomeTable

    UNION ALL

    SELECT 
        an_id, 
        CASE code WHEN 105 THEN CAST(a_varchar AS int) ELSE NULL END
    FROM SomeOtherTable
    WHERE code = 105
) i
INNER JOIN AnotherOne a
    ON a.an_id = i.an_id

Therefore, the only explanation I could find was that with the JOIN, the query gets optimized differently in a way that CAST(a_varchar AS int) gets executed even if code <> 105.

The queries are run against SQL SERVER 2008.

like image 964
plalx Avatar asked Oct 03 '14 13:10

plalx


People also ask

What is a where clause in a SELECT statement?

The WHERE clause is the part of the SELECT statement that specifies the search conditions. These conditions determine exactly which rows are retrieved. The general format is this: When you run a SELECT statement with a WHERE clause, your system searches for the rows in the table that meet your conditions (also called qualifications ).

Which is an example of a multiple where clause in SQL?

SQL Query Examples on Multiple WHERE Conditions 1. SQL WHERE Clause ‘Equal’ or ‘LIKE’ Condition. 1 2 3 4 5 6 7 SELECT MY_NAME FROM EMPLOYEE WHERE MY_NAME LIKE... 2. Result of NULL Value Comparision. S.No Column 1 Operator Column... 3. Multiple SQL Where Clause Conditions – Like >, >=, <, <=, AND and ...

How do you use not in and where clause together?

WHERE clause combined with - NOT IN Keyword. The WHERE clause when used together with the NOT IN keyword DOES NOT affects the rows whose values matches the list of values provided in the NOT IN keyword. The following query gives rows where membership_number is NOT 1 , 2 or 3.

How do you use multiple arguments in a where clause?

The WHERE clause will cause the query only affect rows where the argument evaluates to true for that row. The argument will be evaluated independently for every row in the table (s). Multiple arguments can be included in a single WHERE clause by utilizing the SQL operators AND and OR.


1 Answers

Absolutely.

The documentation that you reference has a section called Logical Processing Order of the SELECT statement. This is not the physical processing order. It explains how the query itself is interpreted. For instance, an alias defined in the select clause cannot be references in the where clause, because the where clause is logically processed first.

In fact, SQL Server has the ability to optimize queries by doing various data transformation operations when it reads the data. This is a nice performance benefit, because the data is in memory, locally, and the operations can simply be done in place. However, the following can fail with a run-time error:

select cast(a_varchar as int)
from table t
where a_varchar not like '%[^0-9]%';

The filter is applied after the attempt at conversion, in the real process flow. I happen to consider this a bug; presumably, the folks at Microsoft do not think so, because they have not bothered to fix this.

Two workarounds are available. The first is try_convert(), which does conversions and returns NULL for a failure instead of a run-time error. The second is the case statement:

select (case when a_varchar not like '%[^0-9]%' then cast(a_varchar as int) end)
from table t
where a_varchar not like '%[^0-9]%';
like image 189
Gordon Linoff Avatar answered Oct 05 '22 23:10

Gordon Linoff