Оператор ASSERT используется для проверки определённых условий. Это оператор будет выполняться для каждой строки из набора данных.
Типичный пример, когда можно встретить этот оператор — проверка условия CHECK. Например, для столба можно ограничить список возможных значений. Тогда при вставке данных ASSERT будет проверять для каждой строки значение, переданное в столбец. К сожалению в реальной работе эти возможности SQL используют реже, чем следует. Поэтому мы рассмотрим выдуманный и сильно упрощённый пример.
DROP TABLE IF EXISTS traffic_light; CREATE TABLE traffic_light ( id INT IDENTITY(1, 1), color CHAR(1), CONSTRAINT CHECK_COLOR CHECK (color IN ( 'G', 'R' )) ); INSERT INTO dbo.traffic_light (color) VALUES ('Y');
В этой таблице мы разрешаем цвету условного светофора быть или зелёным, или красным. При вставке данных в эту таблицу SQL Server генерирует следующий план:
Если разобраться с тем, что именно проверяет ASSERT, то мы увидим, что он возвращает 0, если в столбец color передаётся значение отличное от G или R и NULL в противном случае. Ошибка будет сгенерирована, есть ASSERT вернёт значение отличное от NULL.
Помимо проверки CHECK-ограничений ASSERT используется и при проверке ограничений внешних ключей. Попробуем чуть усложнить наш пример, добавив ещё одну таблицу с потенциально возможными цветами светофора и связав две таблицы между собой.
DROP TABLE IF EXISTS possible_light; CREATE TABLE possible_light ( color CHAR(1) PRIMARY KEY ); INSERT INTO dbo.possible_light (color) VALUES ('R'),('Y'),('G'); ALTER TABLE dbo.traffic_light ADD CONSTRAINT fk_light FOREIGN KEY (color) REFERENCES dbo.possible_light (color);
Теперь при вставке данных в первую таблицу план усложнится:
Если идти справа налево, то первый ASSERT как и раньше проверит CHECK ограничение, а второй ASSERT проверит корректность связи по ключам.
В предикате второго оператора ASSERT мы видим непонятное условие Expr1007, но всё станет на свои места, если отобразить план запроса в виде текста:
|--Assert(WHERE:(CASE WHEN NOT [Pass1008] AND [Expr1007] IS NULL THEN (0) ELSE NULL END)) |--Nested Loops(Left Semi Join, PASSTHRU:([lessons].[dbo].[traffic_light].[color] IS NULL), OUTER REFERENCES:([lessons].[dbo].[traffic_light].[color]), DEFINE:([Expr1007] = [PROBE VALUE])) |--Assert(WHERE:(CASE WHEN [lessons].[dbo].[traffic_light].[color]<>'R' AND [lessons].[dbo].[traffic_light].[color]<>'G' THEN (0) ELSE NULL END)) | |--Table Insert(OBJECT:([lessons].[dbo].[traffic_light]), SET:([lessons].[dbo].[traffic_light].[color] = [Expr1004],[lessons].[dbo].[traffic_light].[id] = [Expr1003])) | |--Compute Scalar(DEFINE:([Expr1004]=CONVERT_IMPLICIT(char(1),[@1],0))) | |--Compute Scalar(DEFINE:([Expr1003]=getidentity((1525580473),(6),NULL))) | |--Constant Scan |--Clustered Index Seek(OBJECT:([lessons].[dbo].[possible_light].[PK__possible__900DC6E8209DDE1B]), SEEK:([lessons].[dbo].[possible_light].[color]=[lessons].[dbo].[traffic_light].[color]) ORDERED FORWARD)
По строке DEFINE:([Expr1007] = [PROBE VALUE]) становится понятно, что это выражение — просто результат объединения таблиц. Этим выражением ASSERT проверяет, что вставляемое значение действительно есть в таблице possible_light.
Наконец, рассмотрим ещё один случай, где оператор ASSERT может встречаться в реальной работе. Речь идёт о подзапросах. Во многих ситуациях встречается «скалярный» подзапрос. Т.е. такой подзапрос, который возвращает строго одно значение. В качестве тестового запроса рассмотрим следующий код:
SELECT * FROM dbo.traffic_light tl WHERE (tl.color> (SELECT pl.color FROM dbo.possible_light pl WHERE (1=1)and(pl.color>'A')) )
Практического смысла он не несёт, но позволяет продемонстрировать ситуацию, когда мы сравниваем скалярное значение с результатом подзапроса. План получился не очень сложный:
Самый интересный блок тут это часть где данные из possible_light агрегируются, чтобы подсчитать количество строк, а потом полученное значение передаётся в ASSERT. Думаю, вы уже сами догадались, что Expr1004 это результат агрегации
Stream Aggregate(DEFINE:([Expr1004]=Count(*)...
Вот такой большой пост у меня получился о простейшем, но очень важном операторе.