Can scalar functions be applied before filtering when executing a SQL Statement?

I suppose I have always naively assumed that scalar functions in the select part of a SQL query will only get applied to the rows that meet all the criteria of the where clause.

Today I was debugging some code from a vendor and had that assumption challenged. The only reason I can think of for this code failing is that the Substring() function is getting called on data that should have been filtered out by the WHERE clause. But it appears that the substring call is being applied before the filtering happens, the query is failing. Вот пример того, что я имею в виду. Скажем, у нас есть две таблицы, каждая с 2 столбцами и имеющая 2 строки и 1 строку соответственно. Первый столбец в каждом - это просто идентификатор. NAME - это просто строка, а NAME_LENGTH сообщает нам, сколько символов в имени с тем же идентификатором. Обратите внимание, что только имена, содержащие более одного символа, имеют соответствующую строку в таблице LONG_NAMES.

NAMES: ID, NAME
    1, "Peter"
    2, "X"
LONG_NAMES: ID, NAME_LENGTH
    1, 5

Если я хочу, чтобы запрос выводил каждое имя с обрезанными последними 3 буквами, я мог бы сначала попробовать что-то вроде этого (при условии синтаксиса SQL Server пока):

SELECT substring(NAME,1,len(NAME)-3)
    FROM NAMES;

Вскоре я обнаружил, что это приведет к ошибке, потому что, когда он достигнет «X», он попытается использовать отрицательное число для в вызове подстроки, и это не удастся. The way my vendor decided to solve this was by filtering out rows where the strings were too short for the len - 3 query to work. He did it by joining to another table:

SELECT substring(NAMES.NAME,1,len(NAMES.NAME)-3) 
    FROM NAMES 
        INNER JOIN LONG_NAMES 
            ON NAMES.ID = LONG_NAMES.ID;

At first glance, this query looks like it might work. The join condition will eliminate any rows that have NAME fields short enough for the substring call to fail.

However, from what I can observe, SQL Server will sometimes try to calculate the the substring expression for everything in the table, and then apply the join to filter out rows. Is this supposed to happen this way? Is there a documented order of operations where I can find out when certain things will happen? Is it specific to a particular Database engine or part of the SQL standard? If I decided to include some predicate on my NAMES table to filter out short names, (like len(NAME) > 3), could SQL Server also choose to apply that after trying to apply the substring? If so then it seems the only safe way to do a substring would be to wrap it in a "case when" construct in the select?

5
задан Joe Stefanelli 9 March 2011 в 17:13
поделиться