Сегодня я бы хотел остановится подробно на том, как можно обезопасить себя от непредсказуемых ошибок в T-SQL коде путем его правильного оформления. При написании запросов на выборку данных можно указывать псевдонимы для таблиц. Во-первых, это позволяет в дальнейшем обращаться к ним по более коротким именам, например:
use tempdb;
go
if object_id('tempdb..#t1', N'U') is not null
drop table #t1;
create table #t1 (
id int not null primary key,
some_value char(10) not null
);
insert into #t1 (id, some_value)
values
(1, 'A'), (2, 'B');
-- Пример запроса без использования псевдонимов.
select id, some_value
from #t1;
-- Пример запроса с использованием псевдонимов.
select t1.id, t1.some_value
from #t1 as t1;
А во-вторых, если вы используете более двух таблиц в запросе, и в них имеются столбцы с одинаковым именем, то вам необходимо указывать название таблицы или ее псевдоним, чтобы уточнить, к какому именно столбцу вы обращаетесь.
use tempdb;
go
if object_id('tempdb..#t1', N'U') is not null
drop table #t1;
if object_id('tempdb..#t2', N'U') is not null
drop table #t2;
create table #t1 (
id int not null primary key,
some_value char(10) not null
);
create table #t2 (
id int not null primary key,
some_value char(10) not null
);
insert into #t1 (id, some_value)
values
(1, 'A'), (2, 'B');
insert into #t2 (id, some_value)
values
(1, 'C'), (2, 'D');
-- Пример корректно написанного запроса.
select t1.id, t2.some_value
from #t1 as t1
inner join #t2 as t2 on
t2.id = t1.id;
-- Пример запроса, который вызовет ошибку.
select id, some_value
from #t1 as t1
inner join #t2 as t2 on
t2.id = t1.id;
Как мы видим, последний запрос в примере вызывает следующую ошибку, т.к. SQL Server не может корректно определить, к какому именно столбцу вы пытаетесь обаратиться.
Msg 102, Level 15, State 1, Line 31
Incorrect syntax near ‘t2’.
Однако это еще не все. Иногда игнорирование использования псевдонимов в запросе может приводить к трудно отлавливаемым ошибкам и некорректным результатам.
use tempdb;
go
if object_id('tempdb..#t1', N'U') is not null
drop table #t1;
if object_id('tempdb..#t2', N'U') is not null
drop table #t2;
create table #t1 (
id int not null,
some_id int not null
);
create table #t2 (
no_id int not null
);
insert into #t1 (id, some_id)
values
(1, 1),
(2, 3);
insert into #t2 (no_id) values (5);
-- В таблице #t2 отсутствует поле id, но запрос при этом выполняется без ошибок.
select *
from #t1 as t1
where
some_id in (select id from #t2);
В данном случае мы предполагали, что поле id присутствует во временной таблице #t2, хотя его там нет. Запрос при этом отработал без ошибок и вернул данные, т.к. написан он корректно: вернул те записи, у которых поля id и some_id совпадают, если в таблице #t2 имеется хоть одна запись. Как мы видим, интерпретация запроса получилась совсем другая, которую мы имели ввиду, когда его составляли. Поэтому во избежание подобных случайных ошибок в своих запросах рекомендуется всегда использовать псевдонимы и точно указывать, к каким таблицам и столбцам вы обращаетесь.