select 'Hello, World!'

The single biggest challenge to learning SQL programming is unlearning procedural programming (Joe Celko)

[SQL Server] Головоломки (Часть 2)

Olaf Olaf
Добрый день, коллеги!

Продолжая начатую тему [SQL Server] Головоломки (Часть 1), решил опубликовать еще пять вопросов...

1. order by (select null)
Дано: Запрос вида
select * from dbo.Table1 order by (select null)

Вопрос: Можно ли с какой-то долей уверенности сказать будут ли отсортированы данные и в каком порядке?
a) Да
б) Нет
  Ответ

б) Нет
Подсказка:
Правильный ответ – Нет. Предложение order by (select null) будет проигнорировано при выполнении, т.е. данные вернутся в произвольном порядке, как если бы указание сортировки отсутствовало. Конструкция применяется там, где является обязательным использование последовательности данных, но по каким-то причинам поле или набор полей упорядочения не может быть определен, например аналитические функции row_number() over(order by (select null)) или использование паджинации order by (select null) offset 10 rows fetch next 5 rows only.



2. Декартово произведение
Дано: Три запроса
/* 1 */
select *
from dbo.Table1 t1
cross join dbo.Table2 t2

/* 2 */
select *
from dbo.Table1 t1, dbo.Table2 t2

/* 3 */
select *
from dbo.Table1 t1
join dbo.Table2 t2 on 1 = 1

Вопрос: Какие из представленных выше запросов реализуют декартово произведение?
a) Все
б) 1, 2
в) 2, 3
г) 1, 3
д) Ни один
Выберите один вариант ответа
  Ответ

a) Все
Подсказка:
Все 3-и запроса реализуют декартово произведение —
Запрос 1 использует стандарт ANSI-92
Запрос 2 использует стандарт ANSI-89
Запрос 3 использует INNER JOIN с «липовым» условием соединения 1 = 1



3. Приоритет типов данных в предикатах соединения
Дано: Две пустые таблицы
create table dbo.Test1
(
   StringColumn varchar(20)
)

create table dbo.Test2
(
   NumericColumn numeric(19, 0),
   DateTimeColumn datetime 
)

и два запроса соединяющие таблицы по полям разных типов. Запросы выполняются по отдельности.
/* 1 */
select *
from dbo.Test1 t1 
join dbo.Test2 t2 on t1.StringColumn = t2.NumericColumn

/* 2 */
select *
from dbo.Test1 t1 
join dbo.Test2 t2 on t1.StringColumn = t2.DateTimeColumn

Вопрос: К какому типу данных будут преобразованы столбцы, используемые в условии соединения таблиц?
a) В запросе 1 столбец t1.StringColumn участвующий в связывании таблиц будет преобразован к типу numeric(19, 0)
б) В запросе 1 столбец t2.NumericColumn участвующий в связывании таблиц будет преобразован к типу varchar(20)
в) При выполнении запроса 1 возникнет ошибка
г) В запросе 2 столбец t1.StringColumn участвующий в связывании таблиц будет преобразован к типу datetime
д) В запросе 2 столбец t2.DateTimeColumn участвующий в связывании таблиц будет преобразован к типу varchar(20)
е) При выполнении запроса 2 возникнет ошибка
Выберите два варианта ответа
  Ответ

a) В запросе 1 столбец t1.StringColumn участвующий в связывании таблиц будет преобразован к типу numeric(19)
г) В запросе 2 столбец t1.StringColumn участвующий в связывании таблиц будет преобразован к типу datetime
Подсказка:
Столбцы, используемые в условии соединения, не обязательно должны иметь одинаковые имена или одинаковый тип данных. Однако если типы данных не совпадают, то они должны быть совместимыми или допускать в SQL Server неявное преобразование. При выполнении неявного преобразования используется старшинство типов данных согласно документу Data Type Precedence (Transact-SQL) Из 3-х типов данных представленных в запросах выше varchar имеет низший приоритет, поэтому столбцы участвующие в соединениях будут преобразованы к типам данных с более высоким приоритетом — numeric и datetime.



4. Объявление переменных
Дано: Запрос, который заполняет в цикле табличную переменную
declare @i int = 0

while (@i < 10)
begin
   declare @table table(i int)
   insert into @table select @i
   set @i += 1
end

select * from @table

Вопрос: Какие данные будут содержаться в переменной @table после выполнения цикла?
a) При выполнении возникнет ошибка «The variable name '@table' has already been declared»
б) Таблица будет содержать 0 записей
в) Таблица будет содержать 1 запись со значением 9
г) Таблица будет содержать 10 записей со значениями от 0 до 9
  Ответ

г) Таблица будет содержать 10 записей со значениями от 0 до 9
Подсказка:
Все переменные, в том числе и табличные, создаются предварительно, т.е. на этапе компиляции запроса. Именно поэтому во время выполнения цикла будет использоваться единственный экземпляр переменной @table, в который попадут 10 записей от 0 до 9.



5. select @local_variable и несколько значений
Дано: Таблица, содержащая 4 записи и запрос, который инициализирует переменную через оператор select.
select * 
into #temp
from (values (1),(3),(4),(2)) t(k)

declare @i int

select @i = k from #temp order by k

select @i

Вопрос: Чему равно значение переменной @i после выполнения запроса?
a) 1
б) 2
в) 3
г) 4
д) NULL
  Ответ

г) 4
Подсказка:
Согласно документации SELECT @local_variable (Transact-SQL) обычно используется для возвращения одиночного значения в переменную. Однако, если аргумент expression является именем столбца, может вернуться несколько значений. Если инструкция SELECT возвращает более одного значения, переменной присваивается последнее возвращенное значение.

_ABC_
_ABC_
06.06.2016 06:24
Здравствуйте, Olaf, Вы писали:

O>Добрый день, коллеги!


O>Продолжая начатую тему [SQL Server] Головоломки (Часть 1), решил опубликовать еще пять вопросов...


Наткнулся вот на еще один аспект потенциально интересный.
union
Дано: Два непересекающихся набора данных и запрос вида:
declare @ds1 table (id int, amount money)
declare @ds2 table (id int, amount money)

insert into @ds1 (id, amount) values (2, 200), (3, 300)
insert into @ds2 (id, amount) values (1, 100), (1,100)

select
  id
, totalAmount = sum(amount)  
from (select id, amount from @ds1 union
      select id, amount from @ds2) t
where id = 1
group by id


Вопрос: что вернет запрос?
  Ответ
100, т.к. union удаляет все дубликаты, включая те, что содержатся внутри одного и того же результата запроса.