При попытке исполнения запроса: CREATE DOMAIN EMP_NO AS INTEGER CHECK (VALUE BETWEEN 1 AND 10000); Выдается ошибка: Неизвестный тип объекта "DOMAIN" в интсрукции CREATE, DROP или ALTER. Используется SQL Server MS SQL 2008R2 |
Объектные расширения
Определяемые пользователями типы
Один из основных упреков по адресу языка SQL, звучавший, в частности, в Первом манифесте, заключался в отсутствии каких бы то ни было возможностей хранить в базе данных данные, тип которых являлся бы не предопределенным, а определяемым пользователями. Отрицательные последствия отсутствия такой возможности признавались и во Втором манифесте. В SQL:1999 этот дефект был устранен. Как отмечалось в лекции 11, в стандарте поддерживается возможность определения пользователями двух разновидностей UDT – структурных типов (structured type) и индивидуальных типов (distinct types).
Индивидуальные типы
Напомним, что индивидуальным типом называется UDT, основанный на единственном встроенном типе (например, INTEGER ). Значения такого типа нельзя прямо использовать в операциях соответствующего базового типа, однако допускается явное приведение значений индивидуального типа к базовому типу. Поясним это на примерах.
Пусть заданы следующие определения индивидуальных типов:
CREATE TYPE EMP_NO AS INTEGER FINAL; CREATE TYPE DEPT_NO AS INTEGER FINAL; CREATE TYPE PRO_NO AS INTEGER FINAL;
Таблицу EMP можно определить следующим образом (упрощенный вариант):
CREATE TABLE EMP ( EMP_ID EMP_NO, EMP_NAME VARCHAR(20), DEPT_ID DEPT_NO, PRO_ID PRO_NO);
Такое определение таблицы приведет к тому, что хотя все три индивидуальных типа делены на одном и том же базовом типе INTEGER, попытка выполнить запрос
SELECT EMP_NAME FROM EMP WHERE EMP_ID > DEPT_ID;
будет отвергнута системой (и это правильно, поскольку, скорее всего, запрос задан по ошибке). Но если действительно требуется сравнивать идентификаторы служащих с идентификаторами их отделов, то можно воспользоваться конструкцией явного приведения типа:
SELECT EMP_NAME FROM EMP WHERE CAST (EMP_ID TO INTEGER) > CAST (DEPT_ID TO INTEGER);
Аналогичным образом будет отвергнут запрос
SELECT EMP_NAME, EMP_ID + 5 FROM EMP WHERE DEPT_ID > 630;
Чтобы указать системе, что действительно требуется выполнить операции целочисленного сложения и сравнения над значениями индивидуальных типов, запрос нужно переписать следующим образом:
SELECT EMP_NAME, CAST (EMP_ID TO INTEGER) + 5 FROM EMP WHERE CAST (DEPT_ID TO INTEGER) > 630;
У читателей могут возникнуть два законных вопроса:
- почему, вопреки обыкновению, мы не привели формальные синтаксические правила операции определения индивидуального типа?
- что означает ключевое слово FINAL в приведенных примерах определения индивидуальных типов?
На оба эти вопроса достаточно дать один (возможно, неожиданный) ответ. С формальной точки зрения индивидуальный тип данных является частным случаем структурного типа данных. Обе разновидности UDT определяются единым синтаксисом, который мы обсудим в следующих подразделах. В частности, ключевое слово FINAL играет важную роль в определении структурного типа, указывая на тот факт, что этот тип может использоваться только для создания объектов, а не для порождения новых типов на основе механизма наследования. При определении индивидуальных типов механизм наследования не используется, и поэтому в определении любого индивидуального типа должно присутствовать ключевое слово FINAL. 5Кстати, не очень понятно, по каким причинам в стандарте SQL не поддерживается наследование для индивидуальных типов. Конечно, этот механизм существенно более полезен для структурных типов, но его вполне можно было бы реализовать и для индивидуальных типов . Далее, поскольку индивидуальный тип является частным типом структурного типа, для индивидуального типа можно определять методы.
В своих книгах главный редактор стандартов SQL Джим Мелтон постоянно подчеркивает семантическое сходство понятий индивидуального типа данных и домена в смысле SQL ( лекция 11). Более того, утверждается, что в следующих версиях стандарта SQL использование доменов будет сначала объявлено нежелательным, а потом и вовсе будет запрещено. Но я полагаю, что сделать это совсем непросто.
Напомним, что в случае использования SQL-домена:
- в определении домена указывается базовый встроенный тип данных и, возможно, ограничение допустимых значений, которое распространяется на любой столбец, определенный на данном домене;
- для значений столбца, определенного на домене, допускаются все операции, разрешенные для базового типа.
Естественно, эти возможности могут использоваться текущими пользователями стандарта SQL. В то же время в случае использования индивидуального типа данных:
- в определении индивидуального типа указывается только базовый тип данных; если столбец определяется на индивидуальном типе данных, то для него обязательно придется специфицировать собственное ограничение целостности;
- для значений столбца, определенного на индивидуальном типе данных, не допускаются операции соответствующего базового типа (если не использовать операцию явного приведения типов).
Здесь явно имеются противоречия, для сглаживания которых требуется модифицировать понятие индивидуального типа данных.