Yes, you will get the same results in every case. There are a few exceptions where SQL Server doesn't seem to process the code in the order the code is written, and a few cases where there are no guarantees at all. Some are intentional and some are unintuitive.
This might not be expected simply because these labels can get lost in more complex code, can be hit only in certain conditions, etc.
Deferred Name Resolution
CREATE PROCEDURE dbo.floob AS
SELECT * FROM dbo.ThisTableDoesNotExist;
This is kind of related in that it allows you to create an object at compile time that references an object that will cause the procedure to fail when you call it. I mention it only because it allows you to create this procedure before you create the table that the procedure will ultimately depend on.
There is a mode in SSMS that allows you to intersperse SQLCMD and T-SQL. SSMS will make a first pass at the code and process all the SQLCMD bits, and then make a second pass where it will process the T-SQL. Let's say you have a table with an identity column, and a file that includes an insert into this table. With the following script run in SQLCMD mode, the
filename.sql query will get executed on the first pass, and the insert of Bob will happen on the second pass. So the IDENTITY values will be generated in the opposite order:
INSERT dbo.table(name) VALUES('Bob');
Compile Time Name Checking
CREATE TABLE #foo1(x int);
CREATE TABLE #foo1(y int);
Msg 2714, Level 16, State 1, Line 4
There is already an object named '#foo1' in the database.
The parser has gone ahead to line 4 and prevented you from creating two objects of the same name, even though that would never have been possible at runtime due to the IF conditional never being able to evaluate as true (line 2 was never executed).
Order of execution of a single statement
Depending on the version and compatibility level of SQL Server, you may see various cases where clauses are not evaluated in the order you expect. E.g.:
CREATE TABLE #x(y varchar(32));
INSERT #x(y) VALUES('foo'),(4);
SELECT y FROM #x
WHERE ISNUMERIC(y) = 1
AND y < 5;
Msg 245, Level 16, State 1, Line 5
Conversion failed when converting the varchar value 'foo' to data type int.
SQL Server tried to evaluate the
y < 5 predicate before the
ISNUMERIC() result could filter out ineligible rows. People often first try to use a CTE or correlated subquery, but that often fails because you still can't control the order in which these things are evaluated. Typical workarounds include using
TRY_CONVERT() or a
CASE expression (example here, and more on
CASE in a minute), while more elaborate and less desirable approaches exist (such as dumping the filtered rows to a #temp table first).
CASE + AGG
While in most cases a
CASE expression is the only surefire way to guarantee order of evaluation (misconceptions abound, though), even that can fail in some scenarios, one of which was discussed here at great length:
Example that fails, even though the
ELSE should never be reached:
DECLARE @i INT = 1;
SELECT CASE WHEN @i = 1 THEN 1 ELSE MIN(1/0) END;
Msg 8134, Level 16, State 1
Divide by zero error encountered.
For completeness I want to make sure it is clear that if your query says...
SELECT ... FROM t1
INNER JOIN t2
INNER JOIN t3
...SQL Server is free to perform those joins in whatever order is most efficient, unless you use
OPTION (FORCE ORDER) or any other hint that implicitly forces order. So you may see join strategies that optimize a join between t1 and t3, and then join those results to t2.
Surely, there are others...
...those are just a few off the cuff.