Что такое PostgreSQL?


Бесплатная версия

Проект PostgreSQL распространяется на условиях открытых исходных текстов. Это означает, что пользователь может взять исходный текст программы, использовать его и свободно модифицировать без ограничений, устанавливаемых для закрытых программных продуктов. В области баз данных открытость исходных текстов означает, что пользователь получает полный доступ к данным эталонных тестов и статистике быстродействия, недоступным в продуктах некоторых компаний (например, Oracle). Кроме того, открытость исходных текстов позволяет потребителю модифицировать PostgreSQL для своих конкретных целей.
Тем не менее не следует полагать, что программы, распространяемые с открытыми исходными текстами, ничего не стоят конечному пользователю. Действительно, за загрузку и установку программного продукта платить не придется, но всегда приходится учитывать время и усилия, затрачиваемые на изучение пакета и дальнейшее сопровождение. Если ваша компания не располагает соответствующими ресурсами, воспользуйтесь услугами коммерческих организаций и консультантов, занимающихся PostgreSQL.


Что дальше?



Что дальше?

После краткого знакомства с PostgreSQL перед читателем открывается несколько путей. Следующий список дает примерное представление о содержимом книги. Этот «путеводитель» поможет вам самостоятельно решить, о чем читать дальше.
  • Если вы хотите заняться установкой PostgreSQL 7.1.x, переходите к главе 2.
  • Если у вас нет опыта работы с языком SQL и запросами к базам данных, продолжайте чтение с главы 3. Хотя материал главы 3 в основном носит общий характер, в ней также описаны некоторые приемы и концепции, характерные только для PostgreSQL. Обратите на них особое внимание, если хотите досконально разобраться в программе.
  • Если вы уже знакомы с языком SQL и структурой команд, вероятно, вас больше заинтересуют главы 4, 5 и 7.
  • Если вы владеете практическими навыками работы с PostgreSQL в качестве конечного пользователя и хотите перейти к настройке сервера, определению пользователей и групп, а также заданию параметров аутентификации, переходите к части III. Эта часть призвана помочь системным администраторам в инициализации, настройке и управлении вновь созданными или существующими базами данных PostgreSQL.
  • Если вы знакомы с СУБД PostgreSQL и интересуетесь техническими сторонами и методикой программирования, переходите к части IV. В этой части книги описан PL/pgSQL, «родной» процедурный язык PostgreSQL, а также интерфейс JDBC и сервер приложений LXP на базе Web.




Что такое PostgreSQL?



Что такое PostgreSQL?

PostgreSQL - - объектно-реляционная система управления базами данных (ОРСУБД), разработка которой в различных формах ведется с 1977 года. Работа началась с проекта Ingres в Калифорнийском университете (Беркли). Затем проект Ingres был переведен на коммерческую разработку в корпорации Relational Technologies/Ingres.
В 1986 году другая группа, которую возглавлял Майкл-Стоунбрейкер (Michael Stonebraker) из Беркли, продолжила работу над Ingres и создала объектно-реляционную СУБД Postgres. В 1996 году из-за усовершенствования пакета и перехода на распространение с открытыми исходными текстами было принято новое название — PostgreSQL (в течение непродолжительного времени использовалось название Postgres95). В настоящее время над проектом PostgreSQL активно работает группа разработчиков со всего мира.
PostgreSQL считается самой совершенной СУБД, распространяемой на условиях открытых исходных текстов. В PostgreSQL реализованы многие возможности, традиционно встречавшиеся только в масштабных коммерческих продуктах (за дополнительной информацией обращайтесь к разделу «Возможности PostgreSQL»).



Коммерческие продукты семейства PostgreSQL



Коммерческие продукты семейства PostgreSQL

Версия PostgreSQL для операционной системы Red Hat называется «Red Hat Database». Этот продукт относительно недавно появился на рынке баз данных. В основу Red Hat Database заложена версия с открытыми текстами PostgreSQL 7.1. В настоящее время Red Hat Database работает только в системе Linux, желательно в Red Hat Linux 7.1.


Поддержка сообщества PostgreSQL



Поддержка сообщества PostgreSQL

Сообщество PostgreSQL обеспечивает активную поддержку продукта через списки рассылки. Существует несколько списков рассылки, на которые вы можете подписаться, разделенные по темам (например, pfsql-general, pgsql-hackers и т. д.). Списки
рассылки для пользователей SQL содержат достаточно подробную информацию от общих вопросов до разработки программных интерфейсов PostgreSQL. Полный перечень списков рассылки с подробными описаниями приведен на сайте http:/ /www. postg resql.org.




Продукты бесплатные и коммерческие



Продукты бесплатные и коммерческие

Бесплатная версия PostgreSQL состоит только из системы управления базами данных и программных интерфейсов. Версия PostgreSQL для Red Hat также включает графическую программу установки и ограниченную техническую поддержку.
Выбор между коммерческой и бесплатной версиями PostgreSQL определяется прежде всего деловыми соображениями. При наличии компетентного технического персонала вполне подойдет и бесплатная версия, но если вам потребуется поддержка в процессе установки, настройки и администрирования, возможно, лучше приобрести коммерческую версию PostgreSQL.


Возможности PostgreSQL



Возможности PostgreSQL

Как упоминалось выше, PostgreSQL считается самой совершенной СУБД, распространяемой на условиях открытых исходных текстов. В PostgreSQL реализованы многие возможности, обычно присутствующие только в коммерческих СУБД, таких как DB2 и Oracle. Ниже перечислены основные возможности PostgreSQL версии 7.1.x.
  • Объектно-реляционная модель. Работа с данными в PostgreSQL основана на объектно-реляционной модели, что позволяет задействовать сложные процедуры и системы правил. Примерами нетривиальных возможностей этой категории являются декларативные запросы SQL, контроль параллельного доступа, поддержка многопользовательского доступа, транзакции, оптимизация запросов, поддержка наследования и массивов.
  • Простота расширения. В PostgreSQL поддерживаются пользовательские операторы, функции, методы доступа и типы данных.
  • Полноцепная поддержка SQL. PostgreSQL соответствует базовой спецификации SQL99 и поддерживает такие нетривиальные средства, как объединения стандарта SQL92.
  • Проверка целостности ссылок. PostgreSQL поддерживает проверку целостности ссылок, обеспечивающую правильность данных в базе.
  • Гибкость API. Гибкость API PostgreSQL позволяет легко создавать интерфейсы к РСУБД PostgreSQL. В настоящее время существуют программные интерфейсы для Object Pascal, Python, Perl, PHP, ODBC, Java/JDBC, Ruby, TCL, C/ C+ и Pike.
  • Процедурные языки. В PostgreSQL предусмотрена поддержка внутренних процедурных языков, в том числе специализированного языка PL/pgSQL, являющегося аналогом PL/SQL, процедурного языка Oracle. Одним из преимуществ PostgreSQL является возможность использования Perl, Python и TCL в качестве внутренних процедурных языков.
  • МУСС. Технология MVCC (Multi-Version Concurrency Control) используется в PostgreSQL для предотвращения лишних блокировок (locking). Каждый, кто хоть раз работал с другими СУБД на базе SQL (например, MySQL или Access), наверняка замечал, что обращение к базе данных для чтения иногда сопровождается задержками, связанными с попытками записи в базу данных. Проще говоря, операции чтения блокируются операциями, производящими обновление записей. Применение технологии MVCC в PostgreSQL полностью решает эту проблему. MVCC лучше низкоуровневой блокировки, поскольку операции чтения никогда не блокируются операциями записи. Вместо этого PostgreSQL отслеживает все транзакции, выполняемые пользователями базы данных, что позволяет работать с записями без ожидания их освобождения.
Клиент-сервер. В PostgreSQL используется архитектура «клиент-сервер» с распределением процессов между пользователями. В целом она напоминает методику работы с процессами в Apache 1.3.x. Главный (master) процесс создает дополнительные подключения для каждого клиента, пытающегося установить соединение с PostgreSQL.
Опережающая регистрация изменений. Опережающая регистрация изменений (Write Ahead Logging, WAL) повышает надежность данных. Все изменения данных протоколируются до их непосредственной актуализации в базе. Наличие протокола изменений гарантирует, что в случае сбоя базы данных (что весьма маловероятно) данные можно будет восстановить по запротоколированным транзакциям. После восстановления системы пользователь продолжает работу с состояния, непосредственно предшествовавшего сбою.



Из сказанного может возникнуть впечатление,



Выводы

Из сказанного может возникнуть впечатление, что коммерческая версия PostgreSQL в чем-то объективно лучше бесплатной версии. В действительности это не так. При выборе версии необходимо руководствоваться только требованиями конкретной ситуации. Потребуется ли техническая поддержка на стадии установки? Так ли необходима графическая оболочка в программе установки? Если на оба вопроса вы ответили положительно, подумайте о приобретении коммерческой версии PostgreSQL. Но если вы или технические специалисты вашей организации справятся с компиляцией исходных текстов и изменением конфигурации, возможно, бесплатная версия окажется более подходящей.
Также следует ответить на два дополнительных вопроса. Нужна ли вам печатная документация? Готовы ли вы заплатить за PostgreSQL? Печатная документация входит в комплект поставки коммерческой версии, но авторы надеются, что после чтения этой книги дополнительная документация вам уже не понадобится. Также приходится учитывать и цену коммерческой версии: Red Hat Database стоит 2295 долларов.
Главное, о чем следует помнить при выборе версии PostgreSQL (с позиций общей полезности и широты возможностей), — между бесплатной и коммерческой версиями не существует функциональных различий.

Краткий курс SQL

Анатомия команд SQL



Анатомия команд SQL

Команды SQL всегда начинаются с действия (verb) — слова или группы слов, описывающих выполняемую операцию. Кроме того, команда SQL обычно содержит одну или несколько секций, уточняющих ее смысл. В табл. 3.2 перечислены основные действия SQL.


Базы данных



Базы данных

Хотя РСУБД PostgreSQL часто называют просто «базой данных», этот термин часто приводит к недоразумениям. База данных PostgreSQL представляет собой объектно-реляционную реализацию того, что в стандарте SQL99 формально называется схемой (schema).
Проще говоря, базой данных называется совокупность логически связанных данных, хранящихся вместе. Обычно СУБД обеспечивает доступ к этим данным в многопользовательской среде. В PostgreSQL дело обстоит именно так, хотя доступ ограничивается системой четко определенных прав и ограничений.
PostgreSQL может одновременно предоставлять доступ к нескольким базам данных, у каждой из которых имеется свой владелец, свои таблицы, представления, индексы и функции.
Чтобы создать таблицу, функцию или любой другой объект базы данных, вы подключаетесь к конкретной базе данных при помощи клиента PostgreSQL. После подключения создается объект, принадлежащий этой базе данных и недоступный для всех остальных баз данных (хотя клиент может одновременно открыть несколько подключений к разным базам).
Жесткая изоляция основных объектов данных в базах данных снижает опасность возникновения конфликтов имен при выборе имени, ранее зарезервированного для другой цели (например, если два пользователя захотят создать таблицу с именем products для двух разных целей). Это связано с тем, что ни одна база данных не располагает информацией о компонентах других баз и не пытается устанавливать с ними какие-либо логические связи. Более того, это правило распространяется и на объекты данных объектно-реляционных баз, поэтому созданные пользователем функции и языковые определения недоступны для других пользователей, подключающихся к другим базам данных через PostgreSQL.
По умолчанию PostgreSQL создает только одну рабочую базу данных с именем template 1. Любая база данных, созданная после template 1, фактически является ее клоном и наследует от прототипа все характеристики и объекты, включая структуру таблиц, функции, языки и т. д. Для новых пользователей PostgreSQL нередко создается стандартная база данных с именем, соответствующим имени пользователя PostgreSQL, поскольку если при подключении пользователя имя базы данных не указано, PostgreSQL по умолчанию в качестве имени базы данных подставляет имя пользователя.


Битовые последовательности



Битовые последовательности

Битовые последовательности предназначены для представления двоичных величин в виде произвольной последовательности нулей и единиц. Как и строковые константы, битовые последовательности заключаются в апострофы, но начинаются с обязательного префикса В (в верхнем или нижнем регистре). По наличию этого символа PostgreSQL определяет, что строка является битовой последовательностью, а не обычной символьной строкой.
В соответствии с синтаксисом PostgreSQL открывающий апостроф должен следовать сразу же после префикса В, а битовая последовательность не может содержать других символов, кроме 0 и 1. Внутренние пробелы в битовых последовательностях запрещены, но допускается их разбиение по аналогии с обычными строковыми константами (см. выше пункт «Строковые константы).
Битовые строки обычно требуются только при работе с двоичными функциями и таблицами, содержащими двоичные данные. В листинге 3.6 продемонстрирована вставка битовой последовательности в таблицу. Сначала двоичное представление байта сохраняется в таблице my_bytes, а затем результат операции проверяется простым запросом.


Целочисленные константы



Целочисленные константы

Целочисленные константы используются гораздо чаще, чем битовые последовательности. В PostgreSQL целочисленной константой считается любая лексема, состоящая из цифр (без десятичной точки) и не заключенная в апострофы. Интервал допустимых значений целочисленных констант зависит в основном от контекста, но в PostgreSQL по умолчанию целочисленный тип представляется четырьмя байтами и принимает значения из интервала от -2 147 483 648 до 2 147 483 647.
Целочисленные константы часто встречаются в математических операциях, а также в командах SQL, содержащих ссылки на поля целочисленного типа. В листинге 3.7 целочисленные константы используются для обновления кода автора командой UPDATE.
Вспомните таблицу authors, которая устанавливает соответствие между числовым кодом автора и двумя строками, представляющими его имя и фамилию. Допустим, из каких-то административных соображений было решено, что все коды авторов, меньшие 100, нужно увеличить до 100 и выше.
Внесение исправлений начинается с поиска записей, у которых поле id удовлетворяет данному условию. Для этого в команду SELECT включается секция WHERE с целочисленной константой, используемой при проверке условия «меньше».


Числовые типы



Числовые типы

Числовые типы PostgreSQL используются для представления целых и вещественных значений. С общей точки зрения к числовым типам PostgreSQL относятся следующие типы:
  • 2-, 4- и 8-байтовые целые числа;
  • 4- и 8-байтовые вещественные числа;
  • дробные числа с фиксированной точностью.
Помимо перечисленных в PostgreSQL существуют некоторые специальные типы, также относимые к категории числовых, в том числе устаревший тип money и специальная конструкция serial (табл. 3.13).


Дата и время



Дата и время

Следующая категория типов является удобным средством для хранения даты и времени в универсальной структуре SQL. При этом программист избавляется от хлопот, связанных с форматом хранения (как, например, при хранении этих данных в символьных строках). В PostgreSQL все вычисления с датой и временем производятся но юлианскому календарю. Продолжительность года считается равной 365,24 дня, что обеспечивает правильное представление любой даты с 4713 года до нашей эры и далеко в будущее.
В PostgreSQL поддерживаются все типы даты и времени, определенные в стандарте SQL92 (табл. 3.14), а также некоторые вспомогательные типы PostgreSQL, помогающие решить проблемы с представлением часовых поясов в SQL92.


Формат представления даты



Формат представления даты

В PostgreSQL предусмотрено несколько стандартных форматов даты, в том числе формат ISO-8601, традиционный формат SQL, исходный формат PostgreSQL и многие другие. Некоторые форматы даты указаны в табл. 3.15.
Перечисленные форматы относятся к типам данных date и timestamp.


Форматирование команд SQL



Форматирование команд SQL

Как упоминалось в предыдущем подразделе, команды SQL состоят из последовательности элементов — лексем. Менее очевиден тот факт, что лексемы могут находиться в одной или нескольких строках, поскольку модуль лексического разбора PostgreSQL игнорирует лишние пропуски (в том числе разрывы строк).
В листинге 3.1 приведена команда SQL, которая в первом случае задана в одной строке, а во втором повторяется с разбивкой на несколько строк. Оба варианта команды SELECT выводят все содержимое таблицы my_list.


Форматы представления времени



Форматы представления времени

Время, как и дата, может задаваться разными способами. В табл. 3.20 перечислены самые распространенные форматы значений типов time и time with time zone.


Геометрические типы



Геометрические типы

Геометрические типы PostgreSQL предназначены для представления объектов на плоскости. Они не относятся к стандартным типам данных SQL и потому в книге подробно не рассматриваются. В табл. 3.24 приведена краткая сводка поддерживаемых геометрических типов.


Идентификаторы объектов



Идентификаторы объектов

Как было сказано в подразделе «Таблицы» раздела «Знакомство с реляционными базами данных», база данных содержит таблицы, а каждая таблица содержит хотя бы одно именованное поле. Таблица может содержать записи данных, но их наличие не является обязательным. Каждое поле записи, хранящейся в таблице, содержит некоторые данные или NULL.
Один из вопросов, которые приходится решать при операциях с базами данных, — как различить две записи с одинаковыми значениями полей? Для этого в PostgreSQL предусмотрены идентификаторы объектов (object identifiers, OID), никальные в пределах таблицы. Иначе говоря, таблица никогда не содержит записи одинаковыми идентификаторами OID. Таким образом, даже если содержимое пользовательских полей двух записей полностью совпадает, на программном уровне записи можно различить по значению OID. Пример приведен в листинге 3.31.




Интервальный тип



Интервальный тип

В стандарте SQL92 определен тип данных interval, представляющий фиксированный промежуток времени. Сам по себе тип interval представляет лишь количественную величину, не связанную с определенным начальным или конечным моментом. Интервалы часто используются в сочетании с типами даты и времени для вычисления новой величины посредством сложения или вычитания. Кроме
того, они могут пригодиться для быстрого вычисления точного промежутка между двумя датами или моментами времени, для чего одна величина вычитается из другой.
В PostgreSQL поддерживаются два варианта синтаксиса определения интервалов:
длина единице [ago]
длина! единица [. длина2 единица2 ... ]
[ago]
Здесь:
  • длина — продолжительность интервала, заданная в виде целого или вещественного (для микросекунд) числа. Интерпретация числа определяется следующим параметром.
  • единица — единица, в которой измеряется заданный интервал. Разрешены следующие ключевые слова: second, minute, hour, day, week, month,year, decade, century, millennium. Также допускаются сокращения (любой длины при условии однозначной интерпретации) и формы множественного числа.
  • ago — необязательное ключевое слово ago указывает, что описываемый период времени предшествует некоторому моменту, а не следует после него. Ключевое слово ago можно рассматривать как аналог знака минус (-) в типах даты и времени.
В листинге 3.27 приведены примеры объединения типов date и interval. Как видно из листинга, вычитание инвертированного интервала (с ключевым словом ago) эквивалентно прибавлению обычного интервала по аналогии с вычитанием отрицательных чисел.


Язык SQL и его предшественники



Язык SQL и его предшественники

Язык SQL в значительной степени основан на реляционной алгебре и кортежно-реляционной модели. Реляционная алгебра, представленная Э. Ф. Коддомв 1972 году, определяет базовые принципы обработки синтаксиса SQL; это процедурный способ построения запросов, управляемых данными, который определяет способ достижения поставленной цели. С другой стороны, кортежно-реляционная модель использует декларативные выражения и определяет саму цель при обработке структурированных запросов.
Некоторые перечисленные ниже дополнительные возможности отделяют язык SQL от его предшественников, ограничивающихся простой реализацией отдельных аспектов реляционной алгебры или модели.
  • Поддержка вставки, модификации и удаления данных. Пользователям разрешается вставлять, удалять и обновлять записи, хранящиеся в базе данных.
  • Математические операторы. В SQL используются математические операторы сложения, вычитания, умножения, деления, а также выражения вида (valuel * 5) + valueZ. Также поддерживаются операторы сравнения (например, values >= value4).
  • Отображение данных. Пользователь может вывести связи, сгенерированные при обработке запроса.
  • Присваивание. Пользователь может переименовать связь, сгенерированную при обработке запроса. Он не ограничен стандартным именем связи, производным от имени поля или функции (в зависимости от запроса).
  • Агрегатные функции. Пользователь может группировать логически связанные записи и вычислять сводные показатели (среднее арифметическое, сумму, количество, максимальное или минимальное значение).


Ключевые слова и идентификаторы



Ключевые слова и идентификаторы

Ключевыми словами называются зарезервированные термины SQL, имеющие особый синтаксический смысл для сервера (INSERT, UPDATE, SELECT, DELETE и т. д.).
Каждая команда SQL начинается с ключевого слова, хотя многие ключевые слова сами по себе не являются законченными командами. Например, конструкция INSERT INTO является действительной командой SQL, а слово INTO является зарезервированным ключевым словом. Но как нетрудно предположить, слово INTO не имеет смысла вне контекста.
Идентификаторы, как упоминалось выше, представляют собой имена переменных для ссылки на объекты базы данных. Имена идентификаторов произвольно назначаются при создании базы данных. В PostgreSQL идентификаторы могут связываться с базами данных, таблицами, полями, индексами, представлениями, последовательностями, правилами, триггерами и функциями.
В листинге 3.2 в простую таблицу states включается запись, состоящая из трех полей.


Команды SQL



Команды SQL

Любая концептуальная информация о реляционных базах данных и таблицах приносит пользу лишь в том случае, если вы знаете, как организовать взаимодействие с данными. Язык SQL состоит из структурированных команд, предназначенных для добавления, модификации и удаления данных из базы. Эти команды образуют основу для взаимодействия с сервером PostgreSQL
Этот раздел посвящен «анатомии» команд SQL. В нем рассматриваются структурные компоненты команд, описываются функции каждого компонента и их взаимные связи. Стандартный клиент командной строки PostgreSQL, psql, выводит результаты выполнения команд в приведенных примерах.
Большинство примеров команд SQL относится к базе данных booktown. Весь вывод psql снабжается префиксом вида booktown=#
В некоторых примерах используется тестовая база данных testdb. По умолчанию в приглашении psql выводится только имя базы данных и символы =#, означающие, что система готова к вводу новой команды (хотя вы увидите, что символ = динамически изменяется по мере отслеживания состояния входных данных SQL). В книге это приглашение приводится вместе с входными и выходными данными SQL, чтобы вам было проще освоиться с выводом клиента psql.
Клиент psql подробно описан в главе 4. Здесь он упоминается лишь для пояснения стиля примеров команд SQL.
Примечание 1
Примечание 1


Схема базы данных booktown (вместе с примерами записей) находится в файле booktown.sql на компакт-диске. Чтобы установить эту базу данных, введите в приглашении командной строки команду psql -U postgres template! -f /mnt/cdrom/booktown.sql, где /mnt/cdrom — путь к смонтированному компакт-диску, a postgres — имя суперпользователя PostgreSQL.


Комментарием называется



Комментарии

Комментарием называется фрагмент обычного текста, оформленный специальным образом и внедренный в код SQL. Комментарии не влияют на выполнение программы, поскольку PostgreSQL удаляет их из входного потока и интерпретирует как обычные пропуски. Существует две разновидности комментариев: однострочные и многострочные.
Однострочные комментарии начинаются с двух дефисов (- -) и либо находятся в отдельной строке, либо следуют за лексемами SQL (модуль лексического разбора PostgreSQL не считает комментарии лексемами, а все символы, следующие за последовательностью --, интерпретирует как пропуски). Пример однострочного комментария приведен в листинге 3.11.

Константы



Константы

При работе с базами данных многие объекты хранятся на диске, а для обращения к ним используются идентификаторы (имена таблиц, полей и функций). Однако неизбежно настанет момент, когда в систему потребуется передать новые данные — например, при вставке новых записей, при формировании секций с критериями удаления или модификации или при вычислениях на базе существующих записей. Такие данные передаются в виде констант, также иногда называемых «литералами». Константы предназначены для «буквального» представления данных в командах SQL (вместо ссылки на них по идентификатору).
Константы с косвенной типизацией автоматически распознаются модулем лексического разбора PostgreSQL по их синтаксису. В PostgreSQL поддерживаются пять вариатнов констант с косвенной типизацией:
  • строковые константы;
  • битовые последовательности;
  • целочисленные константы;
  • вещественные константы;
  • логические константы.


Краткая история SQL



Краткая история SQL

В 1970 году доктор Э. Ф. Кодд (Е. F. Codd) из компании IBM в статье «A Relational Model of Data for Large Shared Data Banks» дал формальное определение реляционной модели, образующей концептуальную основу SQL. Данная статья вызвала большой интерес как в плане общей приемлемости, так и в плане практических коммерческих приложений подобных систем.
В 1974 году компания IBM начала работу над проектом System/R. Группа под руководством Дональда Чемберлина (Donald Chamberlin) разработала язык SEQUEL (Structured English Query Language). В 1974-75 годах проект System/R был реализован в прототипе SEQUEL-XRM. Затем в 1976-77 годах проект был полностью переделан, в него была включена поддержка многотабличных и многопользовательских средств. Переработанная система сначала называлась «SEQUEL 2», а затем по соображениям авторских прав была переименована в «SQL».
В 1978 году началось доскональное тестирование системы. Оно наглядно продемонстрировало ее удобство и практическую полезность, в результате чего компания IBM начала разработку коммерческих SQL-продуктов, основанных на прототипе System R, включая SQL/DS (1981 год) и DB2 (1983 год).
Другие разработчики программного обеспечения также обратили внимание на растущую популярность реляционной модели и анонсировали свои продукты на базе SQL. К их числу относились СУБД Oracle, Sybase и Ingres (на базе проекта Ingres Калифорнийского университета в Беркли).
Примечание 1
Примечание 1


Как нетрудно догадаться по названию, СУБД PostgreSQL связана с Ingres. Обе СУБД происходят от проекта Ingres Калифорнийского университета.


Краткий курс SQL



Краткий курс SQL

В этой главе описывается история SQL и основные концепции языка. На базе материала строится следующая глава, посвященная использованию SQL в Post-greSQL. В частности, в ней изложены основные принципы работы реляционных баз данных, описаны объектно-реляционные расширения и структура команд SQL, а также приводится краткий обзор поддерживаемых в PostgreSQL типов данных, операторов и функций.



Пробелы и переводы строк



Листинг 3.1. Пробелы и переводы строк

testdb-* SELECT * FROM mylist;
todos
---------------------------------------
Pick up laundry. Send out bills.
Wrap up Grand Unifying Theory for publication.
(3 rows)
testdb-# SELECT * testdb-* FROM
testdb-# mylist;
todos
--------------------------------------
Pick up laundry. Send out bills.
Wrap up Grand Unifying Theory for publication.
(3 rows)
В листинге 3.1 лексемы второй команды разделены дополнительными пробелами и символами новой строки. Как видно из полученных результатов, PostgreSQL игнорирует лишние пробелы и разрывы строк, вследствие чего команды являются синтаксически эквивалентными. Вы можете воспользоваться этим фактом и разбить длинную команду SQL на несколько строк, чтобы упростить ее чтение. Для таких простых команд, как в листинге 3.1, это не нужно, но разбиение пригодится при работе со сложными командами SQL с многочисленными секциями, выражениями и условиями. В книге периодически встречаются примеры, в которых команда разбивается на несколько строк с комментариями к каждой части.



Операторы в командах SQL



Листинг 3.10. Операторы в командах SQL

booktown=# SELECT * FROM books;
id | title author_id | subject_id
7808 | The Shining |4156 | 9
156 | The Tell-Tale Heart| 15| 9
4513 | Dune |1866 |15
4267 | 2001: A Space Odyssey| 2001| 15
1608 | The Cat in the Hat |1809| 2
1590 | Bartholomew and the Oobleck |1809| 2
(6 rows)
booktown=# UPDATE books SET author_id = author _id + 1500;
UPDATE 6
booktown=# SELECT * FROM books;
id title | author_id | subject_id
7808 | The Shining | 5656 | 9
156 | The Tell-Tale Heart 1515| 9
4513| Dune 3366 | 15
4267 | 2001; A Space Odyssey 3501 | 15
1608 | The Cat in the Hat | 3309 |2
1590 | Bartholomew and the Oobleck | 3309 | 2
Как видно из листинга 3.10, выполнение операции сложения с предыдущим значением поля author_id приводит к модификации этого поля во всех записях таблицы.
Вероятно, вы уже знакомы с основными математическими операторами: + (суммирование двух числовых величин), - (вычитание) и т. д. Существуют и другие, более экзотические операторы — например, поразрядные операторы & и |, которые модифицируют значения на уровне двоичного представления.
Некоторые ключевые слова SQL также часто относятся к категории операторов. В первую очередь это логические операторы AND, OR и NOT. Формально являясь ключевыми словами, они причисляются к операторам, поскольку предназначаются для выполнения операций с константами и идентификаторами.
Основные операторы PostgreSQL перечислены в табл. 3.6.


Однострочные комментарии



Листинг 3.11. Однострочные комментарии

testdb=# SELECT 'Test1 -- This can follow valid SQL tokens.
testdb-# -- or be on a line of its own. testdb-#
AS example; example
Test
(1 row)
Многострочные комментарии начинаются с последовательности /* и завершаются последовательностью */. Такой способ оформления комментариев хорошо знаком программистам С, но между интерпретатором PostgreSQL и компилятором С существует одно принципиальное отличие: комментарии PostgreSQL могут быть вложенными. Иначе говоря, если внутри многострочного комментария имеется другой многострочный комментарий, то закрывающая последовательность */ внутреннего комментария не закрывает внешний комментарий. Пример многострочного комментария приведен в листинге 3.12.


Многострочные комментарии



Листинг 3.12. Многострочные комментарии

testdb=# SELECT 'Multi /* This comment extends across
testdb-# * numerous lines, and can be
testdb-# * /* nested safely */ */
testdb-# | '-test' AS example; example
Multi-test (1 row)
Допустим, имеется файл с кодом SQL, в котором необходимо закомментировать большой фрагмент и передать остаток PostgreSQL для интерпретации и выполнения. Если в этом фрагменте встречаются многострочные комментарии, PostgreSQL правильно заключает, что закрывающая последовательность */ относится к последнему открытому комментарию, а не ко всему закомментированному блоку.
Примечание 1
Примечание 1


Звездочка (без смежного символа косой черты) не имеет особой интерпретации в комментариях. Дополнительные звездочки были включены в листинг 3.12 исключительно по эстетическим сообщениям.


Пример запроса SQL



Листинг 3.13. Пример запроса SQL

booktown=# SELECT Id, name FROM states;
id | name
42 | Washington 51 I Oregon
(2 rows)
booktown=#
В табл. 3.8 и 3.9 анализируется другая, более сложная команда SQL. В ней используется действие UPDATE с секциями SET и WHERE, которые определяют соответственно правило изменения записей и критерий их отбора.


Обновление таблицы командой UPDATE



Листинг 3.14. Обновление таблицы командой UPDATE

booktown=# UPDATE states
booktown-# SET id = 51
booktown-# WHERE
name = 'Oregon';
UPDATE 1
booktown=# SELECT * FROM states
booktown-$ WHERE
name='Oregon':
Id | name | abbreviation
51 | Oregon | OR
(1 row)
booktown=#



Пустые строки и NULL



Листинг 3.15. Пустые строки и NULL

booktown=# SELECT id. title FROM books:
id [ title
7808 | The Shining 156 | The Tell-Tale
Heart 4513 | Dune
100 |
101 | (5 rows)
booktown=# SELECT id. title FROM
books WHERE title = ": id | title
100 (1 row)
Dooktown=# SELECT id, title FROM
books WHERE title IS NULL;
id title
101 |
(1 row)
В листинге 3.16 продемонстрировано более практичное (и реальное) применение ключевого слова NULL в таблице editions, связывающей код ISBN с датой публикации книги.


Пример использования NULL



Листинг 3.16. Пример использования NULL

booktown=# SELECT isbn, publication FROM editions:
isbn | publication
039480001X | 1957-03-01
0394800753 | 1949-03-01
0385121679 | (3 rows)
booktown=# SELECT isbn. publication FROM
editions WHERE publication IS NULL:
isbn | publication
0385121679 |
(1 row)
В этом примере NULL может использоваться для представления изданий, которые еще не были опубликованы или дата публикации которых на момент занесения данных в базу неизвестна. Было бы неправильно подбирать для таких книг какую-нибудь бессмысленную дату, и в обоих случаях NULL выглядит вполне оправданно.


Простая таблица с логическими значениями



Листинг 3.17. Простая таблица с логическими значениями

booktown=# CREATE TABLE daily_inventory
(isbn text. in_stock boolean);

CREATE
booktown=# INSERT INTO
dailyjnventory VALUES ('0385121679', true);

INSERT 3390926 1
booktown=# INSERT INTO dailyjnventory
VALUES ('039480001X'. 't');

INSERT 3390927 1
booktown=# INSERT INTO dailyjnventory
VALUES ('044100590X'. 'true');

INSERT 3390928 1
booktown=# INSERT INTO dailyjnventory
VALUES С0451198492', false);

INSERT 3390929 1
booktown=# INSERT INTO dailyjnventory
VALUES С0394900014', '0');

INSERT 3390930 1
booktown=# INSERT INTO dailyjnventory
VALUES ('0441172717'. '!');

INSERT 3390931 1
booktown=# INSERT INTO dailyjnventory
VALUES ('0451160916');

INSERT 3390932 1
После того как таблица заполнена, можно легко получить информацию об имеющихся в наличии книгах. Для этого используется запрос SELECT, приведенный в листинге 3.18.


Выборка данных по логическому признаку



Листинг 3.18. Выборка данных по логическому признаку

booktown=# SELECT * FROM dailyjnventory WHERE in_stock='yes':
isbn in_stock
0385121679 | t
039480001X | t
044100590X t
0441172717 I t
(4 rows)
В PostgreSQL предусмотрена возможность неявной выборки по значению true в логическом поле; для этого имя поля указывается без операторов или ключевых слов-модификаторов. В хорошо спроектированных таблицах такой подход помогает создавать более наглядные запросы. Пример приведен в листинге 3.19.


Неявная выборка по логическому значению



Листинг 3.19. Неявная выборка по логическому значению

true booktown=# SELECT * FROM dailyjnventory WHERE in_stock;
isbn | in_stock
0385121679 | t
039480001X | t
044100590X | t
0441172717 | t
(4 rows)
Хотя в этом запросе не указана конкретная логическая величина, при отсутствии оператора сравнения подразумевается значение true.
Для выборки по значению false можно либо сравнить значение поля с любой из логических констант, перечисленных в табл. 3.11, либо поставить перед именем поля ключевое слово SQL NOT. Оба способа продемонстрированы в листинге 3.20.


Ключевые слова и команды



Листинг 3.2. Ключевые слова и команды

booktown=# INSERT INTO states VALUES (33, 'Oregon', 'OR');

INSERT 3389701 1
В листинге 3.2 команда SQL INSERT INTO содержит ключевые слова SQL INSERT, INTO и VALUES.
Команда INSERT INTO модифицирует таблицу, заданную идентификатором states. В данном случае модификация сводится к вставке новой записи.


Выборка по логическому значению false



Листинг 3.20. Выборка по логическому значению false

booktown=# SELECT * FROM dailyjnventory WHERE in_stock = 'no';
isbn | in_stock
0451198492 f 0394900014 f (2 rows)
booktown=# SELECT * FROM dailyjnventory
WHERE NOT in_stock:
isbn | in_stock
0451198492 | f
0394900014 | f
(2 rows)
Этот пример убедительно доказывает, что при проектировании языка SQL учитывался фактор наглядности и удобочитаемости программ. При грамотном выборе имен таблиц и полей запрос почти не отличается от обычной фразы на английском языке.
Сравнение значений логических полей с константами из табл. 3.11 может осуществляться при помощи оператора неравенства != (например, WHERE in_stock != 't'). Таким образом, следующие три синтаксические формы эквивалентны:
SELECT * FROM daily_iinventory
WHERE NOT injtock: SELECT * FROM
dailyjnventory WHERE in_stock = 'no1:
SELECT * FROM dailyjnventory WHERE in_stock != 't':
Возможно, вы обратили внимание на то, что в листинге 3.17 в таблицу вставляется семь записей, а суммарное количество записей при двух выборках (для поля i n_stock, равного true и fal se) только шесть. Дело в том, что в последней операции вставки в листинге 3.17 значение поля i n_stock не указано, поэтому в записи книги с кодом ISBN равным 0451160916 поле in_stock равно NULL.
Как упоминалось выше, величина NULL не интерпретируется как true или fal se, поэтому для выборки по значению NULL необходимо использовать условие IS NULL. Также можно воспользоваться оператором ! =, но тогда возникают проблемы с адаптацией программы для других СУБД. Пример запроса SQL с условием IS NULL:
booktown=# SELECT * FROM
dailyjnventory WHERE in_stock IS NULL:
isbn | 1n_stock
0451160916 |
(1 row)
Поскольку IS NULL является обычным условием SQL, для обновления всех случайных значений NULL в поле in_stock можно воспользоваться командой UPDATE, приведенной в листинге 3.21.


Исправление случайных значений NULL



Листинг 3.21. Исправление случайных значений NULL

booktown=# UPDATE dailyjnventory
SET in_stock = Т WHERE in_stock IS NULL;
UPDATE 1



Использование типа numeric вместо money



Листинг 3.23. Использование типа numeric вместо money

booktown=# CREATE TABLE money_example (money_cash money.
booktown(# numeric_cash numeric(10,2)):
CREATE
booktown=# INSERT INTO money_example VALUES C$12.241, 12.24);

INSERT 3391095 1
booktown=# SELECT * FROM money_example;
money_cash | numeric_cash
$12.24 | 12.24 (1 row)
booktown=# SELECT money_cash,
booktown-# '$' | ltrim(to_char(numenc_cash. '9999.99'))
booktown-# AS numeric_cashif1ed
booktown-# FROM money_example;
money_cash | numeric_cashified
$12.24 j 12.24
(1 row)


Использование типа serial



Листинг 3.24. Использование типа serial

booktown=# CREATE TABLE autojdentified (id_serial);

NOTICE: CREATE TABLE will create implicit sequence '
auto Jdentif led Jd_seq'
for SERIAL column 'auto_identified.id'
NOTICE: CREATE TABLE/UNIQUE will create
Implicit index 'auto_identified_1d_key' for table
'autojdentified'
CREATE


Решение задачи «вручную»



Листинг 3.25. Решение задачи «вручную»

booktown=# CREATE SEQUENCE autojdentified id_seq;
CREATE
booktown=# CREATE TABLE autojdentified
booktown-# (id integer UNIQUE DEFAULT
nextval('autojdentifiedjd_seq'));

NOTICE: CREATE TABLE/UNIQUE will create implicit index
'autojdentifiedjdjcey' for table
'autojdentified'
CREATE
ВНИМАНИЕ
После удаления таблицы последовательность, созданная для типов senal, автоматически не удаляется. При удалении таблиц, содержащих поля типа serial, эти последовательности должны удаляться отдельно.


Выбор формата даты



Листинг 3.26. Выбор формата даты

booktown=# SET DATESTYLE TO ISO,US;
SET VARIABLE
booktown=# SHOW DATESTYLE;
NOTICE: DateStyle is ISO with
US (NonEuropean) conventions
SHOW VARIABLE
booktown=f SET DATESTYLE TO
NONEUROPEAN. GERMAN;
SET VARIABLE
booktown=# SHOW DATESTYLE;
NOTICE: DateStyle is German
with European conventions
SHOW VARIABLE
Если дополнительный формат не указан, по умолчанию выбирается подходящее значение (например, для регионального формата German выбирается значение European).
Хотя переменная DATESTYLE является удобным средством настройки формата даты, необходимо помнить, что она относится к категории переменных времени исполнения, а это означает, что настройка действует лишь на протяжении текущего сеанса. Существует два способа присвоить переменной DATESTYLE значение по умолчанию, чтобы его не приходилось указывать заново при каждом сеансе.
  • Изменение переменной среды PGDATESTYLE на сервере, на котором работает процесс postmaster. Например, при использовании командного интерпретатора bash можно добавить строку PGDATESTYLE="SQL US" в файл .bash_profile пользователя postgres. При запуске процесса postmaster пользователем postgres переменная PGDATESTYLE будет автоматически применяться ко всем операциям форматирования даты и времени, выполняемым PostgreSQL.
  • Изменение переменной среды PGDATESTYLE, используемой клиентским приложением (при условии, что оно было написано с применением библиотеки libpq) в начале сеанса. Этот вариант выбирается в том случае, если формат вывода должен настраиваться клиентом, а не сервером. Например, присваивая значение переменной PGDATESTYLE командой export в приглашении bash перед запуском клиента psql, вы задаете формат, который будет использоваться в работе psql.


Операции с интервалами



Листинг 3.27. Операции с интервалами booktown=# SELECT date('1980-06-25');


date
1980-06-25
(1 row)
booktown=# SELECT interval С 21 years 8 days');

interval
21 years 8 days (1 row)
booktown=# SELECT date('1980-06-25') + interval
('21 years 8 days') booktown-# AS spanned_date:
spanned_date
2001-07-03 00:00:00-07
(1 row)
booktown=# SELECT date ('1980-06-25') -
interval ('21 years 8 days ago1)
booktown-# AS twice_inverted_interval_date;
twice_ nverted_interval_date
2001-07-03 00:00:00-07
(1 row)


Использование констант current и now



Листинг 3.28. Использование констант current и now

booktown=# CREATE TABLE tasklog
booktown=# (taskname char(15),
booktown=# timebegun timestamp,
booktown=# timeflnished timestamp);

CREATE
booktown=# INSERT INTO tasklog VALUES
booktown=# ('delivery', 'now', 'current'):
INSERT 169936 1
booktown=# INSERT INTO tasklog
VALUES booktown=# ('remodeling', 'now', 'current');

INSERT 169937 1
booktown=# SELECT taskname, tlmefnished - timebegun
booktown-# AS timespent FROM tasklog;
taskname | timespent
delivery | 00:15-.32
remodeling [ 00:04:42
(2 rows)
Итак, константа now обычно используется при сохранении в таблице фиксированного момента времени, который не изменяется при последующих ссылках. Как видно из листинга 3.29, плохое понимание различий между константами now и current приводит к потенциальным ошибкам программирования SQL. В листинге приведены две команды INSERT; в первой команде используется now, а во второй — current. Сравнение результатов показывает, что в первой строке при каждом запросе время обновляется, а во второй строке оно всегда остается одинаковым.


Сравнение констант now и current



Листинг 3.29. Сравнение констант now и current

booktown=# INSERT INTO shipments (customer_id. isbn, ship_date)
Ccustomer_id, isbn, ship_date)
booktown-# VALUES (1. '039480001X', 'current');

INSERT 3391221 1
booktown=# INSERT INTO shipments (customer_id. isbn, ship_date)
booktown-# VALUES (2. '0394800753'. 'now');

INSERT 3391222 1
booktown=# SELECT isbn. ship_date FROM shipments: isbn | ship_date
039480001X [ current 0394800753 | 2001-08-10 18:17:49-07
(2 rows)
booktown=# SELECT isbn.
booktown-# to_char(ship_date. 'YYYY-MM-DD HH24:MI:SS')
booktown-# AS value
booktown-# FROM shipments; isbn value
039480001X | 2001-08-10 18:21:22 0394800753 | 2001-08-10 18:17:49
(2 rows)
booktown=# SELECT isbn.
booktown-# to_char(ship_date. 'YYYY-MM-DD HH24:MI:SS')
booktown-# AS value
booktown-# FROM shipments;
isbn | value
039480001X | 2001-08-10 18:22:35 0394800753 | 2001-08-10 18:17:49
(2 rows)


Преодоление ограничений



Листинг 3.3. Преодоление ограничений

booktown=# CREATE TABLE lst_bent_rule (rule_name text);

ERROR: parser: parse error at or near "1"
booktown=# CREATE TABLE "lst_bent_rule" (rule_name text);

CREATE
Более того, имена таблиц могут содержать некоторые символы, которые обычно считаются недопустимыми (например, пробелы или амперсанды, хотя присутствие кавычек, разумеется, запрещено). Хотя стандарт ANSI/ISO SQL не позволяет создавать идентификаторы с именами, совпадающими с ключевыми словами SQL, PostgreSQL (как и ряд других реализаций SQL) достаточно либерально относится к этому ограничению.— такие имена допустимы, но они должны заключаться в кавычки.
Защита идентификаторов при помощи кавычек выручает во многих нестандартных ситуациях, но если вы хотите, чтобы ваши команды SQL были стандартными и хорошо адаптировались для других платформ, старайтесь по возможности придерживаться стандартов ANSI/ISO.


Использование функции преобразования типа



Листинг 3.30. Использование функции преобразования типа

booktown=# SELECT text(1000)
booktown-# AS explicitjtext;
explicit_text


Идентификация записей по OID



Листинг 3.31. Идентификация записей по OID

3Stdb=# SELECT * FROM my_list;
todos
----------------------------------
Correct redundancies In my_list.
Correct redundancies in my_list.
(1 rows)
testdb=# SELECT *. old FROM my_list:
todos | old
----------------------------------------
Correct redundancies in my list. | 3391263
Correct redundancies In my list. | 3391264
( 2 rows)
testdb=# DELETE FROM my_list
testdb-# WHERE old = 3391264;
DELETE 1
testdb=# SELECT *.oid FROM my_list;
todos old
----------------------------------------------
Correct redundancies in my list. | 3391263
(1 row)


Использование строковых констант



Листинг 3.4. Использование строковых констант

booktown=# UPDATE authors
booktown-# SET firstjiame = 'Louisa May'
booktown-l WHERE firstjiame = 'Luoisa May'
UPDATE 1
booktown-# SELECT * FROM authors;
id | lastjiame | firstjiame
1809 | Geisel | Theodor Seuss
1111 | Denham | Ariel 15990 | Bourgeois | Paulette
25041 | Bianco j Margery Williams
115 I Poe I Edgar Allen
16 j Alcott I Louisa May
(6 rows)
Команда UPDATE в листинге 3.4 использует строковые константы Louisa May и Luoisa May в сочетании с ключевыми словами SET и WHERE. Как видно из результатов запроса, команда обновляет содержимое таблицы, заданной идентификатором authors, и исправляет опечатку.
Тот факт, что строковые константы заключаются между апострофами, порождает очевидную семантическую проблему: если в самой последовательности символов встречается апостроф, граница строковой константы будет определена неверно. Чтобы экранировать апостроф в строке (то есть обеспечить его интерпретацию как литерала), следует поставить два апострофа подряд. Модуль лексического анализа воспринимает удвоенный апостроф в строковой константе как один апостроф-литерал. PostgreSQL также позволяет экранировать апострофы обратной косой чертой, в стиле языка С:
testdb=# SELECT 'PostgreSQL"s great!' AS example;
example
PostgreSQL's great! (1 row)
booktown=# SELECT 'PostgreSQLN's
С-style slashes are great!' AS example;
example
PostgreSQL's C-style slashes are great!
(1 row)
В PostgreSQL также поддерживаются служебные последовательности языка С, перечисленные в табл. 3.3.


Разбиение строковых констант



Листинг 3.5. Разбиение строковых констант

booktown=# SELECT 'book'
booktown-#
booktown-# 'end' AS example;
example
bookend (1 row)
booktown=# SELECT 'bookend' AS example;
example
bookend
(1 row)
Обе команды имеют эквивалентную семантику. Тем не менее фрагменты должны разделяться хотя бы одним разрывом строки, а при попытке разделить их только пробелами PostgreSQL выдает сообщение об ошибке:
booktown=# SELECT 'book' 'end' AS example;
ERROR: parser: parse error at or near .....
Дело в том, что без разрыва строки PostgreSQL считает, что вы ссылаетесь на две отдельные константы. Объединение двух строковых констант в одной строке выполняется оператором конкатенации 11, описанным в главе 5:
booktown=# SELECT 'book.' || 'end1 AS example; example
bookend (1 row)


Использование битовых последовательностей



Листинг 3.6. Использование битовых последовательностей

testdiH* INSERT INTO my_bytes VALUES (B'OOOOOOOO'):
testdb=# SELECT my_byte FROM my_bytes:
my_byte
10000000
10000001
10000101
11111111
00000000
(5 rows)


Использование целочисленных констант



Листинг 3.7. Использование целочисленных констант

booktown=# SELECT * FROM
authors WHERE id < 100;
id | lastjiame | firstjiame
16 | Alcott | Louisa May (1 row)
booktown=# SELECT * FROM authors WHERE id = 100:
id | lastjiame | firstjiame
(0 rows)
booktown=# UPDATE authors
booktown-* SET id = 116
booktown-tf WHERE id = 16:
UPDATE 1
booktown=# SELECT * FROM authors WHERE id = 116:
id | last_name firstjiame
116 | Alcott | Louisa May (1 row)
В листинге 3.7 секция WHERE команды SELECT сравнивает идентификатор поля id с целочисленной константой 100. Результат состоит из одной записи. После обнаружения записи с недопустимым значением id вводится вторая команда SELECT, которая проверяет, существуют ли в таблице записи с кодом i d=116. Мы убеждаемся в том, что код 116 не задействован в таблице authors, поскольку значения в поле id должны быть уникальными. Операция завершается командой UPDATE, также содержащей целочисленные константы в секциях SET и WHERE.


Допустимые вещественные значения



Листинг 3.8. Допустимые вещественные значения

booktown=# SELECT .04 AS small_float.
booktown-# -16.63 AS negative_float,
booktown-# 4e3 AS exponent!al_float,
booktown-# 6.1e2 AS negative_exponent:
small_float | negative_float |
exponential__float | negative_exponent
0.04 -16.63 4000 | 0.061
(1 row)


Различия между true и 'true'



Листинг 3.9. Различия между true и 'true'

testdb=# SELECT true AS boolean_t. testdb-# 'true' AS string_t,
testdb-# false AS boolean_f,
testdb-# 'false' AS string_f;
boo1_t | string_t | bool_f | string_f
t | true | f | false
(1 row)
Как показано в листинге 3.9, PostgreSQL выводит значения логического типа в виде t или f, однако это вовсе не означает, что символы t и f могут использоваться в качестве логических констант. PostgreSQL не сможет правильно интерпретировать их, что приведет к ошибке.




Логические константы



Логические константы

Логические (булевы) константы гораздо проще всех остальных типов констант PostgreSQL, поскольку они принимают всего два допустимых значения: true и false. Встретив любое из этих значений, не заключенное в апострофы, PostgreSQL интерпретирует его как логическую константу. Пример показан в листинге 3.9.


Логические значения



Логические значения

Логическим значением называется простая структура данных, представляющая одну из двух величин: true или f al se. В PostgreSQL поддерживается тип данных boo! ean, определенный в стандарте SQL99, с нестандартным синонимом bool.
Логическим переменным, как и другим типам данных, может присваиваться значение NULL, Логическая переменная, равная NULL, никогда не интерпретируется как true или false; она интерпретируется только как NULL. Если вы хотите проверить, равна ли логическая переменная псевдозначению NULL, не пытайтесь сравнивать ее с false, это бессмысленно. Для этой цели следует использовать конструкцию IS NULL. Способность логической переменной принимать значения true, false и NULL (и правила, в соответствии с которыми NULL считается отличным от этих двух величин) называется тройственной логикой.
В табл. 3.11 приведены допустимые обозначения логических констант, правильно опознаваемые PostgreSQL. Выбор обозначений является делом вкуса. Все разновидности значения true, как и все разновидности значения fal se, интерпретируются сервером одинаково.


Массивы константы



Массивы - константы

При вставке в поле таблицы нового значения, которое представляет собой массив, в команде SQL необходимо перечислить входящие в него элементы. В соответствии с синтаксисом массивов-констант перечисляемые элементы ограничиваются символами-разделителями (запятыми для встроенных типов) и заключаются в фигурные скобки, которые, в свою очередь, заключаются в апострофы: '{ элемент!, элемент2 [ . ...] }'
В этом синтаксисе элементы могут относиться к любому из допустимых типов PostgreSQL. Поскольку весь массив заключается в апострофы, все апострофы внутри элементов массива должны экранироваться как в обычных строковых константах. С другой стороны, выбор запятой в качестве символа-разделителя создает интересную проблему при работе с символьными строками, содержащими запятые, поскольку не заключенные в апострофы запятые интерпретируются как разделители. Но как упоминалось выше, в массивах-константах в апострофы должен заключаться лишь весь массив, а не его отдельные элементы.
В PostgreSQL эта проблема решается заключением строковых констант в кавычки в тех случаях, когда вне контекста массива обычно используются апострофы: '{"valuel","value 2. which contains a comma" }'
Помните, что для правильной интерпретации PostgreSQL массивы обязательно должны заключаться в апострофы. Массив-константу можно рассматривать как особую разновидность строковых констант, которая интерпретируется как массив в зависимости от контекста (например, при добавлении новых данных в поле, имеющее тип массива). В другой ситуации PostgreSQL интерпретирует эту константу как обычный строковый литерал (последовательность символов, заключенная в апострофы), который просто содержит фигурные скобки.



Массивы в таблицах



Массивы в таблицах

В PostgreSQL предусмотрен синтаксис для определения массивов как фиксированного, так и переменного размера; тем не менее в PostgreSQL 7.1.2 ограничение размера не соблюдается. Это означает, что с точки зрения программы массив может иметь фиксированный размер, но при этом изменение размеров все равно производится динамически. Например, поле таблицы, определенное как массив из трех элементов, может содержать три элемента в одной записи, четыре элемента в другой и вообще не содержать элементов в третьей.
Также допускается определение многомерных массивов, в которых каждый элемент может быть не атомарным значением, а другим массивом. При выборке из многомерных массивов элементы выводятся во вложенных фигурных скобках:
booktown=# SELECT editions FROM myjiotes
WHERE title='The Cat In the Hat';
editions
{{"039480001X"."lst Ed. hard Cover"}.
{"039400014"."1st Ed"}} Cl row)


Массивы



Массивы

В исходном варианте реляционной модели значения полей таблиц должны представлять собой атомарные объекты данных. В объектно-реляционных базах данных, к которым относится PostgreSQL, в структурах данных могут использоваться составные значения, называемые массивами.
Массив представляет собой совокупность элементов с общим идентификатором. Элементы массива могут относиться как к встроенному, так и к пользовательскому типу данных, но они обязательно должны быть однотипными. При обращении к элементам массива используется индексная запись с квадратными скобками (например, ту_аггау[0]). Элементы массивов-констант перечисляются в фигурных скобках, заключенных в апострофы (например, '{value_one.value_two,value_three}').


Обязательная защита идентификаторов



Обязательная защита идентификаторов

Идентификаторы обязательно должны заключаться в кавычки только в двух случаях: если идентификатор объекта базы данных совпадает с ключевым словом или в его имени присутствует хотя бы одна прописная буква. В любом из этих случаев идентификатор должен защищаться как при создании объекта, так и при последующих ссылках на него в командах SELECT, DELETE или UPDATE и т. д.
Если не заключить в кавычки идентификатор, совпадающий с ключевым словом, PostgreSQL выдаст сообщение об ошибке, поскольку идентификатор интерпретируется как ключевое слово. Допустим, имеется таблица с именем select. При попытке обратиться к ней со следующим запросом вы получите сообщение об ошибке:
testdb=# SELECT * FROM select
ERROR: parser: parse error at or near "select"
Как показывает этот пример, запрос к незащищенному идентификатору таблицы select приводит к ошибке. Чтобы идентификатор select воспринимался как имя таблицы, а не как ключевое слово, его необходимо заключить в кавычки. Таким образом, правильный запрос к таблице с именем sel ect должен выглядеть так:
testdb=# SELECT * FROM "select";
selected
1
52 105 (4 rows)
Аналогично следует поступать и с идентификаторами, содержащими хотя бы один символ верхнего регистра. Например, если вы по какой-либо причине создали таблицу с именем ProDucts (обратите внимание на прописные буквы Р и D) и теперь хотите ее уничтожить (еще бы, с таким именем!), идентификатор также следует заключить в кавычки:
D0oktown=# DROP TABLE ProDucts;
iRROR: table "products" does not exist
booktown=# DROP TABLE "ProDucts";
DROP
Защита идентификаторов иногда бывает чрезвычайно полезной, даже если вы зсегда создаете объекты базы данных только с «правильными» именами. Наприпер, при импортировании данных через внешнее соединение ODBC (например, is Microsoft Access) имена созданных таблиц могут быть записаны символами верх-iero регистра. Без защиты идентификаторов вам не удастся использовать такие габлицы в программе.


Операторы



Операторы

Другую категорию специальных символов составляют операторы, предназначенные для выполнения различных операций с идентификаторами или константами. Операторы могут использоваться как для математических вычислений (сложение, вычитание и т. д.), так и для сравнения и логических операций.
Вернемся к таблице books и ее числовому полю author_id. Вспомните, что в этом поле хранится целочисленный код, определяющий автора книги. Теперь представьте, что вследствие модификации системы все коды авторов должны быть увеличены на 1500. Задача решается командой UPDATE и выполнением операции с полем author_id. При этом используется оператор сложения (+). Пример приведен в листинге 3.10.


Предварительное планирование



Предварительное планирование

Прежде чем переходить к непосредственному созданию таблиц, желательно выде-ить немного времени на предварительное планирование объектов базы данных, также на выбор имени, типа и смысла каждого поля в таблице. В результате пла-ирования схема выбора имен становится более стройной и последовательной, это, в свою очередь, приводит к появлению более наглядных и «вразумительных» команд и запросов.
Кроме перечисленных семантических факторов (имена, типы и смысл полей), еобходимо проследить за четким установлением связей между таблицами. Проек-ирование связей является важной частью процесса проектирования таблиц, по-кольку любые ошибки в этой области — как дублирование больших объемов дан-ых, так и случайное исключение важных данных из таблиц — являются крайне ежелательными.
Вернемся к таблице books базы данных booktown, структура которой приведена табл. 3.1. В полях каждой записи хранится внутренний код книги, название, код втора и код темы. Обратите внимание: вместо полного имени автора и текстового писания темы в таблице хранятся простые целочисленные коды, используемые ля связи с двумя другими таблицами: authors и subjects. Содержимое этих таблиц астично иллюстрируют табл. 3.26 и 3.27.


Преобразование типов



Преобразование типов

В PostgreSQL поддерживаются три отдельных варианта синтаксиса преобразования (приведения) типов, то есть механизма приведения данных от одного типа к другому. В команде SQL преобразование типов позволяет явно задать тип создаваемой константы (вместо его косвенного определения по правилам языка).
В общем случае приведение строковой константы к другому типу может выполняться любым из трех способов:
тип 'значение'
'значение': -.тип
CAST ('значение' AS тип)
Числовые константы преобразуются в символьную строку следующими способами:
значение: : тип
CAST (значение AS тип)
Здесь значение представляет константу, тип которой требуется изменить, а тип — новый тип этой константы.
Примечание 1
Примечание 1


Помните, что тип money считается устаревшим, что несколко затрудняет его использование в преобразованиях.
Преобразование к другому типу данных не ограничивается одними константами. Поля набора данных, возвращаемого запросом SQL, также могут преобразовываться к другому типу, при этом используются следующие формы синтаксиса:
идентификатор:: тип
CAST (идентификатор AS тип)
Следует учесть, что не каждый тип данных может быть приведен к любому другому типу. Например, не существует осмысленного преобразования символьной строки abed в двоичную последовательность типа bit. Недопустимые попытки преобразования приводят к ошибкам PostgreSQL. Чаще всего встречаются преобразования символьных строк, типов даты/времени или числовых типов к типу text, а также символьных строк в числа.
Кроме синтаксических форм преобразования типа существуют некоторые функции, позволяющие добиться практически того же результата. Имена этих функций часто совпадают с именами итоговых типов (например, text()), хотя существуют и узкоспециализированные варианты (например, bitfromint4()). В листинге 3.30 приведен пример использования функции text О для преобразования целого числа 1000 в строку типа text, содержащую символы «1000».


Псевдозначение NULL



Псевдозначение NULL

Выше говорилось о том, что с каждым полем ассоциируется определенный тип данных и поле принимает значения только этого типа. Тем не менее существует значение, которое может храниться в любых полях независимо от типа; в SQL оно представлено ключевым словом NULL. Ключевое слово NULL не соответствует конкретному объекту данных и потому вообще не считается типом; это системное ключевое слово, которое указывает базе данных на то, что поле не содержит никакого значения. Единственное исключение из правила об универсальности NULL составляют поля, для которых установлено ограничение NOT NULL.
Ключевое слово NULL часто используется для представления необязательных значений. Оно позволяет обойтись без странных и противоестественных схем, например представления отсутствующих данных в целочисленном поле отрицательными числами. Ситуация со временем может измениться, но NULL — всегда NULL.
NULL можно рассматривать как псевдозначение, то есть признак отсутствия значения, который никогда не может быть эквивалентен значению, отличному от NULL. Одна из распространенных ошибок при работе с псевдозначениями NULL связана с тем, что их часто путают с пустыми символьными строками. Отчасти это связано с тем, что при выборке пустой строки данные в клиенте не выводятся. При выборке NULL происходит то же самое, однако NULL принципиально отличается от пустых строк, и это необходимо хорошо понимать, чтобы ваши запросы правильно работали. Поле строкового типа, содержащее пустую строку, содержит последовательность символов, хотя бы и пустую; таким образом, поле имеет определенное значение. Ключевое слово NULL обозначает полное отсутствие значения в поле.
Это весьма принципиальное различие, поскольку правила выполнения операций SQL с пустыми строками очень отличаются от правил операций с псевдозначениями NULL. Особенно заметно эти различия проявляются при объединениях, рассматриваемых в главе 4.
Примеры выборки NULL и пустых строк приведены в листинге 3.15. Первый запрос SELECT показывает, что записи двух книг были вставлены в таблицу без названий (поле ti tie). Тем не менее из последующих запросов становится видно, что в одной записи (id=100) это поле содержит пустую строку, а в другой записи — NULL


Символьные типы



Символьные типы

Символьные типы используются в любых операциях с символьными данными (например, с фрагментами текста в кодировке ASCII). Обычно они применяются для хранения имен, адресов и т. д.
В стандартном языке SQL поддерживаются два символьных типа character и character varyi ng. В PostgrcSQL к ним добавился обобщенный тип text, не требующий явного задания максимального размера поля. Размер полей типа text автоматически изменяется в соответствии с объемом хранящихся данных и практически не ограничивается (размер поля не может превышать один гигабайт, но на практике поля такого размера почти не встречаются). В табл. 3.12 перечислены символьные типы данных PostgreSQL.


Синтаксические символы



Синтаксические символы

Некоторые специальные символы выполняют в командах SQL примерно те же функции, что и знаки препинания в английском языке. В табл. 3.5 перечислены основные синтаксические символы PostgreSQL.


Системные поля



Системные поля

В PostgreSQL все таблицы содержат системные поля, которые остаются невидимыми для пользователя и не выводятся при выборке (если служебная информация не запрашивается специально). В системных полях хранятся метаданные, описывающие содержимое записей. Некоторые из них позволяют различать кортежи (фиксированные состояния записей) при работе с блоками транзакций (за дополнительной информацией о транзакциях обращайтесь к главе 7).
В табл. 3.25 перечислены системные поля, присутствующие в каждой записи в дополнение к полям, определенным пользователем в структуре таблицы.


Совместимость



Совместимость

Для сохранения совместимости с предыдущими версиями PostgreSQL разработчики продолжают поддерживать типы данных datetime и timespan. Тип datetime эквивалентен timestamp, а тип timespan — типу interval.
К числу типов даты/времени также относятся типы abstime и reltime, обладающие пониженной точностью представления. Тем не менее это внутренние типы PostgreSQL, которые могут исчезнуть в следующих версиях. Старайтесь использовать только SQL-совместимые типы данных и как можно скорее устранить устаревшие типы из существующих приложений.


Специальные символы



Специальные символы

Специальные символы имеют особое синтаксическое значение в PostgreSQL. По этой причине они обычно не могут использоваться в идентификаторах, хотя, как упоминалось выше в пункте «Защищенные идентификаторы» подраздела «Ключевые слова и идентификаторы», данное ограничение обычно удается обойти при помощи кавычек.


Стандарты SQL



Стандарты SQL

В 1986 году язык SQL был стандартизирован Американским национальным институтом стандартов (ANSI), а в 1987 году появился стандарт Международной организации по стандартам (ISO). Стандарт ANSI/ISO был принят в качестве Федерального стандарта по обработке информации (FIPS) правительства США. В 1989 году был опубликован пересмотренный стандарт, который обычно обозначается сокращениями «SQL89» и «SQL1».
По некоторым причинам (отчасти из-за столкновения интересов фирм-разработчиков) стандарт SQL89 был намеренно оставлен незавершенным, а многие возможности были отнесены к разряду «определяемых при реализации». С целью укрепления стандарта комитет ANSI пересмотрел свою предыдущую работу, и в 1992 году был принят стандарт SQL92 (также называемый SQL2). В новом стандарте были исправлены некоторые недостатки SQL89 и намечены концептуальные особенности SQL, которые на тот момент превосходили возможности любых существующих реализаций РСУБД. Кстати, стандарт SQL92 был в шесть раз длиннее своего предшественника. Вследствие расхождений стандарта с текущей ситуацией авторы определили три уровня соответствия SQL92: начальное соответствие (минимальные улучшения в SQL89), промежуточное соответствие (реально достижимый набор принципиальных улучшений) и полное соответствие (стопроцентное выполнение всех положений SQL92).
Позднее, в 1999 году, в ANSI/ISO был опубликован стандарт SQL99, также называемый SQL3. В этом стандарте рассматривались некоторые нетривиальные аспекты современных SQL-систем, в том числе концепции объектно-реляционных баз данных, интерфейсы уровня вызова и обеспечение логической целостности. На смену уровням соответствия SQL92 пришли новые уровни: базовый и расширенный.
В настоящее время PostgreSQL соответствует большинству положений начального уровня стандарта SQL92, а также многим положениям промежуточного и полного уровней. У многих новых положений, появившихся в SQL99, существуют аналоги в области объектно-реляционных концепций PostgreSQL (массивы, функции и наследование).




Строковые константы



Строковые константы

Строковая константа представляет собой произвольную последовательность символов, заключенную в апострофы. Строковые константы часто используются при вставке новых данных в таблицу и при передаче символьной информации другим
объектам базы данных. Ниже приведен пример использования строковых констант при обновлении имен и фамилий таблицы authors базы данных booktown:
booktown=# SELECT * FROM authors;
id | lastjiame | firstjiame
1809 Geisel | Theodor Seuss
1111 | Denham | Ariel
15990 | Bourgeois | Paulette
25041 | Bianco | Margery Williams
16 | Alcott I Luoisa May
115 | Рое | Edgar Allen
(6 rows)
Из результатов запроса видно, что поле firstjiame с кодом id=16, Louisa May, было ошибочно записано в виде Luoi sa May. Ошибка исправляется командой UPDATE со строковой константой, приведенной в листинге 3.4.


Структура имен идентификаторов



Структура имен идентификаторов

Максимальная длина ключевых слов и идентификаторов PostgreSQL равна 31 симюлу. В процессе лексического разбора все ключевые слова и идентификаторы большей длины автоматически усекаются. Идентификаторы начинаются с любой буквы английского алфавита (a-z) или с символа подчеркивания, далее следует фоизвольное сочетание букв, цифр (0-9) и символов подчеркивания. Ключевые лова не могут начинаться или завершаться символом подчеркивания, но для имен щентификаторов это разрешено. Ни ключевые слова, ни идентификаторы не могут начинаться с цифры.
Выше в пункте «Обязательная защита идентификаторов» было показано, что включение идентификатора в кавычки позволяет «преодолеть» правило игнорирования регистра символов. То же относится и к правилу, согласно которому иденификатор не может начинаться с цифры. Хотя без кавычек PostgreSQL не позволит создать таблицу с именем lst_bent_rul e, в кавычках это имя становится приемлемым.
В листинге 3.3 первая команда пытается создать таблицу с недопустимым именем, после чего вторая команда преодолевает это ограничение при помощи кавычек.


Пример таблицы SQL



Таблица 3.1. Пример таблицы SQL

id title authorjd subjected
7808 The Shining 4156 9
156 The Tell-Tale Heart 15 9
4513 Dune 1866 15
4267 2001: A Space Odyssey 2001 15
1608 The Cat in the Hat 1809 2
1590 Bartholomew and the Oobleck 1809 2
Таблица состоит из четырех столбцов, следующих слева направо в фиксированном порядке. В настоящий момент она содержит шесть записей, также иногда называемых кортежами (tuples). Обратите внимание на очень важное обстоятельство: несмотря на фиксированный порядок столбцов в реляционной базе данных, записи хранятся в произвольном порядке. Как будет показано при описании структуры запросов SQL в главе 4, в SQL существуют средства для упорядочивания записей при выборке, но автоматическое упорядочение записей в самой базе не производится. Если в запросе SQL записи должны следовать в определенном порядке, вы должны явно включить в запрос соответствующую секцию.
Каждая таблица содержит минимум один столбец, однако таблица может не содержать ни одной записи. Каждый вертикальный столбец соответствует фиксированному атрибуту данных, представленных в таблице (как, например, столбец title в таблице books из приведенного выше примера). Без столбцов содержимое соответствующего элемента данных становится неопределенным, тогда как без записей в таблице просто отсутствуют данные. В PostgreSQL 7.1 таблица может содержать до 1600 столбцов и неограниченное количество записей (точнее, ограниченное только аппаратными факторами — например, объемом свободного дискового пространства).
В табл. 3.1 имена столбцов наглядно характеризуют смысл хранящихся в них данных. Впрочем, они выбираются более или менее произвольно, поэтому в процессе планирования имен в таблицах следует помнить о предотвращении возможных конфликтов имен.
Хотя на первый взгляд это и не очевидно, каждый столбец таблицы характеризуется определенным типом данных. Тип данных не только помогает лучше описать информацию, хранящуюся в столбце, но и ограничивает его содержимое. Например, столбец author_id имеет тип Integer; это означает, что любая попытка вставки записи, у которой в этом столбце не находится целое число (например, ПОа), завершится неудачей. Типы данных столбцов подробно описаны в разделе «Типы данных».
В этом разделе были представлены общие принципы логической организации данных в реляционных базах и таблицах. В следующем разделе объясняется, почему все операции с базой осуществляются при помощи команд SQL.


Типы данных PostgreSQL



Таблица 3.10. Типы данных PostgreSQL

Тип данных Описание Стандарт
Логические и двоичные типы данных
boolean, bool Отдельная логическая величина (true или false) SQL99
bit(n) Битовая последовательность фиксированной длины (ровно nбит) SQL92
bit varying(/7),varbit(rt) Битовая последовательность переменной длины (до n бит) SQL92
Символьные типы
character(n), char(n) Символьная строка фиксированной длины (ровно n символов) SQL89
character varying(n), varchar(n) Символьная строка переменной длины (до n символов) SQL92
text Символьная строка переменной или неограниченной длины PostgreSQL
Числовые типы
small int, int2 2-байтовое целое со знаком SQL89
integer, int, int4 4-байтовое целое со знаком SQL92
bigint, int8 8-байтовое целое со знаком, до 18 цифр PostgreSQL
real, float4 4-байтовое вещественное число SQL89
double precision, floats, float 8-байтовое вещественное число SQL89
numeric(p.s),
decimal (p.s)
Число из р цифр, содержащее 5 цифр в дробной части SQL99
money Фиксированная точность, представление денежных величин PostgreSQL,
считается устаревшим
serial 4-байтовое целое с автоматическим приращением PostgreSQL
Время и дата
date Календарная дата (день, месяц и год) SQL92
time Время суток SQL92
time with time zone Время суток с информацией о часовом поясе SQL92
timestamp Дата и время SQL92
interval Произвольный интервал времени SQL92
Геометрические типы
box Прямоугольник на плоскости PostgreSQL
line Бесконечная линия на плоскости PostgreSQL
Iseg Отрезок на плоскости PostgreSQL
circle Круг с заданным центром и радиусом PostgreSQL
path Замкнутая или разомкнутая геометрическая фигура на плоскости PostgreSQL
point Точка на плоскости PostgreSQL
polygon Замкнутый многоугольник на плоскости PostgreSQL
Сетевые типы
cidr Спецификация сети IP PostgreSQL
inet Сетевой IP-адрес с необязательными битами подсети PostgreSQL
macaddr МАС-адрес (например, аппаратный адрес адаптера Ethernet) PostgreSQL
Системные типы
old Идентификатор объекта (записи) PostgreSQL
xid Идентификатор транзакции PostgreSQL
В следующих подразделах будут более подробно описаны самые распространенные и наиболее часто используемые типы данных. Нестандартные и/или экзотические типы (например, геометрические, сетевые и битовые) в книге подробно не рассматриваются. Ниже приводится информация о возможностях использования, некоторых аспектах хранения, входных и выходных форматах и общих синтаксических правилах. Но перед описанием конкретных типов данных необходимо сказать несколько слов о ключевом слове NULL.


Логические константы



Таблица 3.11. Логические константы

True False
true false
't' Т
'true' 'false'
'У' 'n'
'yes' 'no'
'1' '0'
ВНИМАНИЕ
Помните, что все константы, перечисленные в табл. 3.11 (за исключением true и false), должны заключаться в апострофы. В противном случае сервер выдает сообщение об ошибке.
В листинге 3.17 приведен пример создания таблицы da I ly_i inventory с информацией о наличии книг в магазине. В этой таблице код ISBN ассоциируется с логическим признаком. После создания таблица заполняется серией команд INSERT, в которых передается строковая константа (код ISBN) и логические константы в разных форматах.


Символьные типы



Таблица 3.12. Символьные типы

Тип Размер Описание
character(rt), chart/7) (4+ л) байт Символьная строка фиксированной длины, дополненная пробелами до п символов
character varying(/?), varchar(/?) До (4+л) байт Символьная строка переменной длины, максимальный размер равен п
text Переменный Строка переменной длины, максимальный размер не ограничен
Параметр п в табл. 3.12 представляет произвольное количество символов и задается для поля при его создании.
Примечание 1
Примечание 1


Тип данных text не предусмотрен в стандарте ANSI/ISO SQL, однако он поддерживается многими реляционными СУБД, в том числе Sybase и MS SQL Server.


Числовые типы PostgreSQL



Таблица 3.13. Числовые типы PostgreSQL

Тип Размер Допустимые значения
bigint, int8 8 байт Целые числа в интервале от -9 223 372 036 854 775 807 до 9 223 372 036 854 775 807
double precision, floats, float 8 байт Вещественные числа, 15 значащих цифр, неограниченный размер (с ограниченной точностью)
integer, int, int4
numeric(p.s), decimal (p. s)
4 байта Переменный Целые числа в интервале от -2 147 483 648 до 2 147 483 647
Целые и вещественные числа из рцифр (всего) и 5 цифр в дробной части
real, float4 4 байта Вещественные числа, шесть значащих цифр, неограниченный размер (с ограниченной точностью)
small int, int2 2 байта Целые числа в интервале от -32 768 до 32 767
money 4 байта Вещественные числа с двумя цифрами в дробной части в интервале от -21
474 836.48 до 21 474 836.47
serial 4 байта Целые числа в интервале от 0 до 2 147 483 647
Как видно из табл. 3.13, у некоторых типов данных PostgreSQL имеются синонимы, полностью эквивалентные исходным типам. Синонимы были созданы для удобства, хотя иногда это приводит к недоразумениям, поскольку некоторые синонимы встречаются в других языках программирования. Если не знать, с каким типом ассоциируется тот или иной синоним, возможны случайные ссылки на другие типы данных. Например, в PostgreSQL типы real и doubl e представляют значения, которые во многих языках относятся к типу float; при этом у обоих типов имеются синонимы, имена которых содержат слово «float» (float и flot8 относятся к double precision, float4 относится к real). Если вы попытаетесь использовать синоним f I oat, полагая, что он связан с типом real, возникнут проблемы, поскольку в действительности этот синоним связан с типом double precision.
Тип numeric Тип numeric (также называемый типом decimal) предназначен для представления сколь угодно больших или малых значений с фиксированной точностью, задаваемой пользователем. При создании таблицы с полем типа numeric в круглых скобках указываются два значения: точность и масштаб. Точность определяет максимальное количество цифр (включая цифры в дробной части), а масштаб определяет количество цифр только в дробной части. Если параметры не заданы, по умолчанию точность равна 30, а масштаб — 6. Максимальная точность (а следовательно, и максимальный размер), задаваемая таким образом, равна 1000. На практике 1000 цифр обычно вполне достаточно.
Примечание 1
Примечание 1

Предотвращение ошибок переполнения
booktcwn=# INSERT INTO numbers
VALUES (9.99999999);
INSERT 3390697 1
booktown=# SELECT * FROM numbers:
number
10.000000 (1 row)
booktown=# INSERT INTO
numbers VALUES (9999.99999999);
ERROR: overflow on numeric
AMS(value) >= 10*5 for field with precision
11 scale 6 booktown=# INSERT INTO
numbers VALUES (trunc(99999.99999999.6));
INSERT 3390698 1
booktown=# SELECT * FROM
numbers; number
10.000000 99999.999999 (2 rows)
booktown=# INSERT INTO
numbers VALUES (trunc0.99999999. 6));
INSERT 3390699 1
booktown=# SELECT * FROM numbers;
number
10.000000 99999.999999 9.999999
(3 rows)


Типы даты и времени



Таблица 3.14. Типы даты и времени

Тип данных Размер Описание Интервал
date 4 байта Календарная дата (год, месяц и день) От 4713 г. до н. э. до 32 767 г. н. э.
time 4 байта Время суток без часового пояса От 00:00:00 до 23:59 :59.99
time with time zone 4 байта Время суток с часовым поясом От 00:00:00+12 до 23:59:59.99-12
timestamp with time zone, 8 байт Календарная дата и время От 1903 г. н. э.
timestamp с часовым поясом до 2037 г. н. э.
interval 12 байт Общий промежуток От-1780 000 000 лет
времени до 1 780 000 000 лет


Форматы представления даты



Таблица 3.15. Форматы представления даты

Пример Описание
July 1. 2001 Название месяца, день и год
Sunday July 1. 2001 Название дня недели, название месяца, день и год
July 15. 01 BC Название месяца, день и год до нашей эры
2001-07-01 Стандартный формат ISO-8601: год, месяц и день в числовом виде
20010715 ISO-8601: полный год, месяц, день
010715 ISO-8601: год из двух цифр, месяц, день
7/01/2001 Американский формат: месяц, день и год
1/7/2001 Европейский формат: день, месяц и год
2001.182 Числовой формат с полным годом и номером дня в году
При указании имени месяца в датах следует либо ввести полное название месяца, либо выбрать одно из стандартных сокращений, перечисленных в табл. 3.16.


Сокращенные обозначения месяцев



Таблица 3.16. Сокращенные обозначения месяцев

Месяц Сокращение
Январь Jan
Февраль Feb
Март Mar
Апрель Apr
Май May
Июнь Jun
Июль Jul
Август Aug
Сентябрь Sep, Sept
Октябрь Oct
Ноябрь Nov
Декабрь Dec
В табл. 3.17 приведены аналогичные сокращения для дней недели.


Сокращенные обозначения дней недели



Таблица 3.17. Сокращенные обозначения дней недели

День Сокращение
Воскресенье Sun
Понедельник Моп
Вторник Tue, Tues
Среда Wed, Weds
Четверг Thu, Thur, Thurs
Пятница Fri
Суббота Sat
Несмотря на разнообразие форматов представления даты в PostgreSQL, значения всегда хранятся в одном внутреннем представлении. В вашем распоряжении имеются различные способы настройки формата, в котором PostgreSQL возвращает дату и время.
Примечание 2
Примечание 2


Хотя даты можно форматировать при помощи строковых функций (таких, как to_char()), гораздо эффективнее установить по умолчанию как можно более близкое представление и лишь затем применять ручное преобразование типов и форматирование текста.
Общий формат вывода даты/времени устанавливается применением команды SET к переменной DATESTYLE. Переменной может быть присвоено одно из четырех стандартных значений, перечисленных в табл. 3.18.


Константы форматов даты



Таблица 3.18. Константы форматов даты

Общий формат Описание Пример
ISO Стандарт ISO-8601 2001-06-25 12:24:00-07
SQL Традиционный формат SQL 06/25/2001 12:24:00.00 РОТ
Postgres Исходный формат PostgreSQL Моп 25 Jun 12:24:00 2001 PDT
German Региональный формат для Германии 25.06.2001 12:24:00.00 РОТ
Например, формат SQL устанавливается следующей командой SQL:
booktown=# SET DATESTYLE TO SQL;
SET VARIABLE
Если выполнить запрос SELECT current_timestamp после присваивания, PostgreSQL вернет текущее время в формате SQL:
booktown=# SELECT current_timestamp;
timestamp
08/10/2001 13:25:55.00 PDT (1 row)
Вывод текущего значения переменной DATESTYLE во время работы PostgreSQL производится следующей командой:
booktown=# SHOW DATESTYLE;
NOTICE: DateStyle is SQL
with US (NonEuropean)
conventions SHOW VARIABLE
Помимо общих форматов, представление даты в PostgreSQL зависит от другого фактора: порядка перечисления компонентов (табл. 3.19). Этот порядок перечисления определяет, должен ли в выводимой дате день следовать за месяцем или наоборот. Порядок перечисления компонентов применяется к четырем общим форматам знакомой командой SET DATESTYLE и не изменяет в формате ничего, кроме относительного расположения дня и месяца.


Дополнительные форматы вывода даты



Таблица 3.19. Дополнительные форматы вывода даты

Формат Описание Пример
European День/месяц/год 12/07/2001 17:34:50.00 МЕТ
US. NonEuropean Месяц/день/год 07/12/2001 17:34:50.0 PST
Более того, общий формат и относительный порядок дня/месяца можно задать в одной команде SET с разделением констант запятыми. Порядок перечисления констант в команде SET не важен, если они не являются взаимоисключающими (например, SQL и ISO). Пример приведен в листинге 3.26.


Основные действия PostgreSQL



Таблица 3.2. Основные действия PostgreSQL

Действие Описание
CREATE DATABASE Создание новой базы данных
CREATE INDEX Создание нового индекса для столбца таблицы
CREATE SEQUENCE Создание новой последовательности в существующей базе данных
CREATE TABLE Создание новой таблицы в существующей базе данных
CREATE TRIGGER Создание нового определения триггера
CREATE VIEW Создание нового представления для существующей таблицы
SELECT Выборка записей из таблицы
INSERT Вставка одной или нескольких новых записей в таблицу
UPDATE Модификация данных в существующих записях
DELETE Удаление существующих записей из таблицы
DROP DATABASE Уничтожение существующей базы данных
DROP INDEX Удаление индекса столбца из существующей таблицы
DROP SEQUENCE Уничтожение существующего генератора последовательности
DROP TABLE Уничтожение существующей таблицы
DROP TRIGGER Уничтожение существующего определения триггера
DROP VIEW Уничтожение существующего представления
CREATE USER Создание в системе новой учетной записи пользователя PostgreSQL
ALTER USER Модификация существующей учетной записи пользователя PostgreSQL
DROP USER Удаление существующей учетной записи пользователя PostgreSQL
GRANT Предоставление прав доступа к объекту базы данных
REVOKE Лишение прав доступа к объекту базы данных
CREATE FUNCTION Создание новой функции SQL в базе данных
CREATE LANGUAGE Создание нового определения языка в базе данных
CREATE OPERATOR Создание нового оператора SQL в базе данных
CREATE TYPE Создание нового типа данных SQL в базе данных
Несмотря на явное сходство с языками программирования, разработчики поставили целью сделать язык SQL по возможности удобным и наглядным. В результате команды SQL часто напоминают простые предложения на английском языке. В отличие от обычных языков программирования, команды SQL указывают серверу, какие данные требуется найти, но не сообщают, как это должно происходить. В результате хорошо написанный запрос SQL читается почти так же легко, как обычное предложение.
Примечание 2
Примечание 2


В учебниках SQL термины «команда» и «запрос» часто считаются эквивалентными. В этой книге термин «запрос» используется только по отношению к командам, возвращающим данные (например, SELECT), а не к общим командам SQL, которые также могут создавать и модифицировать данные.
Во внутреннем представлении PostgreSQL структурированные команды SQL интерпретируются в виде последовательности лексем, обычно разделяемых пропусками (пробелами или символами новой строки вне парных ограничителей), хотя некоторые лексемы могут следовать без пропусков, если это не вызывает неоднозначной интеопоетапии (например, опепатопы могут стоять вплотную к идеитификаторам). В данном контексте лексемой считается слово или символ, осмысленно идентифицируемый сервером в процессе разбора (интерпретации) команды SQL.
С технической точки зрения каждая лексема может быть ключевым словом, идентификатором, защищенным идентификатором, константой (также встречается термин «литерал») или одним из специальных символов. К категории ключевых слов PostgreSQL относит слова, имеющие заранее определенный смысл в контексте SQL или PostgreSQL — действия, секции, имена функций и некоторые необязательные составляющие команд SQL (как, например, слово WORK в команде COMMIT). Идентификаторы представляют имена переменных для таблиц, столбцов и других объектов баз данных.
Ключевые слова и идентификаторы относятся к внутренним функциям, значениям и записям, смысл которых определяется PostgreSQL С другой стороны, константы описывают данные, интерпретируемые буквально (например, числа или символьные строки).
Наконец, команды SQL могут содержать специальные символы. К этой категории относятся зарезервированные символы (круглые и квадратные скобки, точка с запятой), влияющие на смысл и расположение ключевых слов, идентификаторов и литералов. Специальные символы можно рассматривать как своего рода «знаки препинания» в командах SQL.
Операторы также относятся к категории специальных символов и используются для применения логических или математических операций между данными (литеральными или представленными в виде идентификаторов). Обычно операторы содержат от одного до четырех символов.
В нескольких ближайших подразделах эти базовые компоненты SQL описываются более подробно.


Taблица 3 20 Форматы представления времени



Taблица 3.20. Форматы представления времени

Пример Описание
01:24 ISO-8601 с точностью до минут
01:24 AM Эквивалент 01:24 (суффикс AM используется только для наглядности и не влияет на значение)
01:24 РМ Эквивалент 13:24 (для использования суффикса РМ час должен быть меньше либо равен 12)
13:24 24-часовой формат, эквивалент 01:24 РМ
01:24:11 ISO-8601, с точностью до секунд
01:24:11.112 ISO-8601, с точностью до микросекунд
012411 ISO-8601, с точностью до секунд, числовое форматирование
В дополнение к этим форматам в PostgreSQL предусмотрена возможность уточнения времени в типах time и time with time zone. Дополнительные форматы перечислены в табл. 3.21.


Допустимые форматы часового пояса



Таблица 3.21. Допустимые форматы часового пояса

Пример Описание
01:24:11-7 ISO-8601, GMT + 7 часов
01:24:11-07:00 ISO-8601, GMT + 7 часов 0 минут
01:24:11-0700 ISO-8601, GMT + 7 часов 0 минут
01:24:11 PST ISO-8601, тихоокеанское стандартное время (GMT + 7 часов)
Примечание 3
Примечание 3


В PostgreSQL поддерживаются все сокращенные обозначения часовых поясов, предусмотренные в стандарте ISO.
Tnntime with time zone поддерживается в PostgreSQL в основном для сохранения совместимости с существующими стандартами SQL и другими СУБД. Если вам потребуется работать с часовыми поясами, рекомендуется использовать тип timestamp, описанный в следующем пункте. Это объясняется прежде всего тем, что из-за действия летнего времени осмысленная интерпретация часовых поясов иногда возможна лишь при наличии даты.
Во внутреннем представлении PostgreSQL вся информация о часовых поясах хранится в виде числового смещения от времени по Гринвичу (GMT), также называемого UTC (Universal Coordinated Time). По умолчанию PostgreSQL выводит время в часовом поясе, заданном в файле конфигурации операционной системы. Если вы хотите, чтобы время выводилось в другом часовом поясе, это можно сделать четырьмя способами.
  • Настройка переменной среды TZ на сервере. Переменная используется для определения часового пояса по умолчанию при запуске postmaster. Например, она может задаваться в файле .bash_profile пользователя postgres командой export TZ='zone'.
  • Настройка переменной среды PGTZ на стороне клиента. Переменная среды PGTZ может быть прочитана любым клиентом, написанным с использованием библиотеки libpq. Значение интерпретируется как стандартный часовой пояс клиента.
  • Команда SQL SET TIMEZONE ТО. Команда устанавливает для текущего сеанса заданный часовой пояс (например, SET TIMEZONE TO UTC).
  • Секция SQL AT TIME ZONE. Согласно стандарту SQL92 значение секции задается в виде обозначения часового пояса (например, PST) или интервала (например, Interval ( -07:00')). Секция AT TIME ZONE включается в команду SQL после значения времени (например, SELECT my_t1mestamp AT TIME ZONT 'PST').
Примечание 4
Примечание 4


Если переменная часового пояса содержит недопустимое значение, в большинстве систем по умолчанию используется время по Гринвичу (GMT). Кроме того, если при компиляции PostgreSQL был задан ключ USE_AUSTRALIAN_RULES, обозначение EST относится к австралийскому восточному стандартному времени (смещение +10.00 часов по отношению к GMT), а не к восточному стандартному времени США.


Примеры данных типа timestamp



Таблица 3.22. Примеры данных типа timestamp

Пример Описание
1980-06-25 11:11-7 Формат даты ISO-8601 с точностью до минут, часовой пояс PST
25/06/1980 12:24:11.112 Европейский формат даты с точностью до микросекунд
06/25/1980 23:11 Американский формат даты с точностью до минут в 24-часовом представлении
25.06.1980 23:11:12 РМ Немецкий региональный формат даты с точностью до микросекунд и суффиксом РМ
ВНИМАНИЕ
Хотя в PostgreSQL поддерживается синтаксис создания полей или значений типа timestamp without time zone, в PostgreSQL 7.1.2 полученный тип данных все равно содержит информацию о часовом поясе.


Константы даты и времени



Таблица 3.23. Константы даты и времени

Константа Описание
current Текущее (отложенное) время обработки транзакции. В отличие от now не привязывается к конкретному моменту времени и возвращает текущее системное время
epoch infinity 1970-01-01 00:00:00+00 («день рождения» Unix)
Абстрактная константа, более «поздняя» по сравнению со всеми допустимыми значениями даты и времени
-infinity Абстрактная константа, более «ранняя» по сравнению со всеми допустимыми значениями даты и времени
now Фиксированное время обработки транзакции
today Полночь текущего дня
tomorrow Полночь следующего дня
yesterday Полночь предыдущего дня
В PostgreSQL также поддерживаются три встроенные функции для получения текущего времени, даты и их комбинации. Для них были выбраны подходящие имена current_date, current_time и current_timestamp.
Если судить только по именам, константы now и current на первый взгляд кажутся идентичными. В действительности они принципиально различаются по способу хранения в таблице. Константа now транслируется в системное время на момент выполнения команды (например, время вставки, если константа используется в команде INSERT). С другой стороны, константа current обычно применяется в особых случаях (например, при отслеживании сведений о процессах) для вычисления разности между начальным временем, зафиксированным константой now, и текущим временем; результат определяет время выполнения процесса. В листинге 3.28 константы now и current используются для построения журнала задач. Первая команда создает таблицу с полями для хранения имени задачи, начальной и конечной даты/времени. В таблице создаются записи двух задач, при этом начальное время задается константой now, а конечное время — константой current. Из листинга видно, что обе задачи не завершены.
ВМИМАНИЕ
Константы даты/времени, как показано в листинге 3.28, обязательно заключаются в апострофы.


Геометрические типы



Таблица 3.24. Геометрические типы

Тип Размер Описание Синтаксис
point 16 байт Точечный объект, характеризуемый только координатами на плоскости. Координаты А- и /представляются вещественными числами (А-./)
Iseg 32 байта Отрезок прямой. Задается координатами начальной и конечной точек ((xl.yl). (х2.у2))
box 32 байта Прямоугольник. Задается координатами двух углов, расположенных по диагонали ((xl.yl) лх2.у2))
path 4+32хлбайт Замкнутая фигура (аналог многоугольника): множество из п точек, соединенных отрезками ((xl.yl)....)
path 4+32х/?байт Разомкнутая фигура (аналог многоугольника): множество из п точек, соединенных отрезками [(xl.yl),...]
polygon 4+32х/7 байт Многоугольник (аналог замкнутой фигуры): п конечных точек отрезков, образующих контур многоугольника ((xl.yl)....)
circle 24 байта Круг с центром в точке (х.у) и радиусом г <(х,у) .r >


Системные поля



Таблица 3.25. Системные поля

Поле
Описание
old 4-байтовый уникальный идентификатор объекта записи. В пределах одной таблицы значения end никогда не повторяются
tableoid Идентификатор объекта таблицы, содержащей запись. Имя таблицы связывается с идентификатором в системной таблице рд class
xmin Идентификатор транзакции вставки для кортежа
cmin Идентификатор команды, ассоциированной с транзакцией вставки для кортежа
xmax Идентификатор транзакции удаления для кортежа. Для видимых (не удаленных) кортежей равен нулю
cmax Идентификатор команды, ассоциированной с транзакцией удаления для кортежа. По аналогии с xmax равен нулю для видимых кортежей
ctid Идентификатор, описывающий физическое местонахождение кортежа в базе данных. Поле ctid содержит пару чисел: номер блока и индекс кортежа в блоке


Таблица authors



Таблица 3.26. Таблица authors

id last_name first_name
1809 Geisel Theodor Seuss
illl Denham Ariel
15990 Bourgeois Paulette
2031 Brown Margaret Wise
25041 Margery Williams Bianco
16 Alcoa Louisa May
115 Poe Edgar Allen


Таблица subjects



Таблица 3.27. Таблица subjects

id subject location
1809 Arts Creativity St
1111 Children's Books Kids Ct
15990 Classics Academic Rd
2031 Computers Productivity Ave
25041 Drama Main St
16 Horror Black Raven Dr
115 Science Fiction Main St
Вынесение данных об авторе и теме из таблицы books повышает эффективность хранения данных. Если в таблице имеются данные о нескольких книгах, относящихся к одной теме, то вместо нескольких экземпляров полных данных, связанных с темой, в таблице будут храниться только значения subjected. Кроме того, это упрощает модификацию данных, связанных с темой книги (например, информации о размещении этих книг на полках магазина). Такие данные достаточно один раз изменить в одной небольшой таблице вместо того, чтобы обновлять множество записей в основной базе. Аналогичные рассуждения применимы и к таблице authors, связанной с books по полю authorjd.
Тщательное планирование также помогает избежать ошибок при выборе типов данных. Например, таблица editions связывает коды ISBN с кодами книг, хранящимися в таблице booktown. На первый взгляд кажется, что для представления кодов ISBN можно воспользоваться полем типа integer, однако такое решение было бы ошибочным, поскольку коды ISBN иногда содержат символьные данные. Кроме того, в поле типа integer будут теряться начальные нули (код 0451160916 превратится в 451160916).
Из всего сказанного можно сделать вывод, что проектирование таблиц является важной составляющей процесса проектирования базы данных.


Служебные последовательности



Таблица 3.3. Служебные последовательности PostareSQL в стиле С

Последовательность Описание
\\ Обратная косая черта (литерал)
V Апостроф (литерал)
Забой
\f Подача листа
\п Новая строка
Возврат курсора
\t Табуляция
\ххх ASCII-символ с восьмеричным кодом ххх
ВНИМАНИЕ
Вследствие того что обратная косая черта имеет особый смысл (см. табл. 3.3), при включении в строку этот символ обязательно экранируется другой косой чертой (например, в строке 'A single backslash is: \\' двойной символ обратной косой черты преобразуется в один).
Если две строковые константы PostgreSQL разделены промежутком, в который входит хотя бы один символ новой строки, они объединяются в одну строковую константу. Пример приведен в листинге 3.5.


Представление величин с плавающей точкой



Таблица 3.4. Представление величин с плавающей точкой

Представление Пример
##.## 6.4
##e[+-]## 8е-8
[##].##[e[+-]##] .04e8
##.[##][e[+-]##] 4e.5
В первом формате до десятичной точки и после нее должна стоять хотя бы одна цифра. Это необходимо для того, чтобы модуль лексического анализа PostgreSQL опознал значение как вещественную, а не целочисленную константу. В других форматах хотя бы одна цифра должна стоять до или после экспоненты, обозначенной буквой е. Наличие десятичной точки и/или экспоненты отличает вещественные константы от целочисленных.
В листинге 3.8 использование всех вещественных форматов продемонстрировано на примере простой команды SQL SELECT.


Синтаксические символы



Таблица 3.5. Синтаксические символы

Символ Определение
* (звездочка) Выборка всех полей таблицы в команде SELECT, а также подсчет всех записей в агрегатной функции count ()
( ) (круглые скобки) Группировка выражений, изменение приоритета операторов и вызов функций. Смысл круглых скобок в значительной степени зависит от контекста
[ ] (квадратные скобки) Выборка конкретного элемента массива или объявление типа массива (например, в команде CREATE TABLE)
: (точка с запятой) Признак завершения команды SQL. Внутри команд может использоваться только в строковых константах и защищенных идентификаторах
. (запятая) Разделитель элементов в списке
. (точка) Десятичный разделитель в вещественных константах (например, 3.1415), а также квалификатор имен полей (например, table name. column name)
: (двоеточие) Определение срезов (slices) в массивах
$ (знак доллара) Обозначение позиционного параметра в определении функции


Основные операторы PostgreSQL



Таблица 3.6. Основные операторы PostgreSQL

Оператор Определение
Математические операторы
+ Сложение двух чисел
- Вычисление разности двух чисел
/ Вычисление частного от деления двух чисел
* Умножение двух чисел
! Факториал целого числа
§ Модуль (абсолютное значение) числа
Операторы сравнения
= Проверка эквивалентности двух величин
< Проверка условия «первое число меньше второго»
> Проверка условия «первое число больше второго»
~ Поиск совпадения регулярного выражения в тексте
Логические операторы
NOT Логическое отрицание
AND Логическая конъюнкция (true, если оба логических операнда равны true)
OR Логическая дизъюнкция (true, если хотя бы один из логических операндов равен true)
Смысл многих операторов может изменяться в зависимости от контекста, но оператор = играет особенно важную роль в секции SET команды UPDATE.
Хотя в большинстве выражений оператор = требуется для проверки эквивалентности двух величин, в сочетании с идентификатором в секции SET команды UPDATE он становится оператором присваивания и используется для присваивания нового значения существующему идентификатору.
За дополнительной информацией об операторах обращайтесь к разделу «Операторы» в главе 5.



Простой запрос SQL



Таблица 3.7. Простой запрос SQL

SELECT id, name FROM states
Тип лексемы Ключевое слово Идентификаторы Ключевое слово Идентификатор
Описание Команда Имена полей Имя секции Имя таблицы
Как видно из таблицы, команда SELECT содержит ключевые слова SELECT и FROM. Ключевое слово FROM с лексемой states образует секцию, уточняющую смысл команды SELECT.
Лексемы id, name и states в приведенном примере являются идентификаторами. Идентификаторы Id и name определяют выбираемые поля, а идентификатор states определяет имя таблицы, из которой производится выборка. Таким образом, приведенный выше запрос приказывает PostgreSQL выбрать поля Id и name каждой записи таблицы states. В листинге 3.13 показаны результаты выполнения этого запроса.


Команда UPDATE с секцией SET



Таблица 3.8. Команда UPDATE с секцией SET

UPDATE states SET id = 51
Ключевое слово Идентификатор Ключевое слово Идентификатор Оператор Целочисленная константа
Команда Имя таблицы Имя секции Имя поля Присваивание Новое значение поля id


Секция WHERE



Таблица 3.9. Секция WHERE

WHERE name = 'Oregon'
Ключевое слово Идентификатор Оператор Строковая константа
Имя секции Имя поля Проверка эквивалентности Искомое значение
Приведенная команда просматривает содержимое поля name каждой записи и проверяет, совпадает ли оно с условием секции WHERE (совпадение со строковой константой ' Oregon'). Затем во всех записях, соответствующих этому условию, полю id присваивается значение 51.
Итак, рассмотренная команда UPDATE содержит три ключевых слова, три идентификатора и две константы. Ключевыми словами являются лексемы UPDATE (выполняемое действие), SET (правило обновления записей) и WHERE (критерий отбора обновляемых записей).
Оба оператора представлены знаком =. В секции SET этот знак используется для присваивания (то есть обновления поля существующей записи) — применение, специфическое для секции SET. С другой стороны, в секции WHERE оператор = используется для сравнения двух значений. В данном примере поле name записи сравнивается со строковой константой Oregon.
Наконец, в примере присутствует целочисленная константа 51 (новое значение поля id) и строковая константа Oregon (сравниваемая с полем name в секции WHERE).
Таким образом, команда UPDATE, приведенная в листинге 3.14, обновляет таблицу states, присваивая значение 51 полю Id всех записей, у которых поле name содержит значение Oregon. Результат проверяется следующей командой SELECT.


Таблицы в PostgreSQL



Таблицы в PostgreSQL

Многие программисты (особенно обладающие опытом работы с другими реляционными СУБД на базе SQL) хорошо знакомы с общими концепциями реляционных баз данных, рассмотренными в этой главе. Тем не менее в разных РСУ БД используются разные механизмы работы с таблицами на системном уровне. В этом разделе более подробно описана реализация таблиц в PostgreSQL.


Таблицы



Таблицы

Данный раздел посвящен таблицам — одному из важнейших элементов SQL. Таблицы необходимо знать во всех подробностях, поскольку именно в таблицах хранятся все данные. Хорошее знание логической структуры таблиц является обязательным условием правильного планирования и проектирования структур данных SQL и всех программных функций, обеспечивающих доступ к этим данным.
Таблица состоит из строк (записей) и столбцов (полей), пересечения которых называются элементами данных. В электронных таблицах (например, в Excel) элементам данных соответствуют ячейки таблицы. Столбец определяет имя и тип данных, хранящихся в соответствующем элементе данных записи. Каждая запись (строка таблицы) состоит из элементов данных, описываемых именем и типом соответствующего столбца. Таким образом, каждый элемент данных в записи косвенно связан со всеми остальными элементами этой записи. В определенном смысле поле можно рассматривать как описание отдельного элемента записи, а каждую запись — как совокупность данных, удовлетворяющих этим описаниям.
В табл. 3.1 приведено описание структуры простой таблицы books. Ссылки на эту таблицу будут неоднократно встречаться в дальнейших примерах. В каждой записи таблицы хранится информация об отдельной книге: числовой код книги, название, код автора и код темы. Эти характеристики описываются полями 1 d, ti tl e, authoMd и subjected (слева направо).


Тип money



Тип money

Тип money предназначен для хранения денежных величин и обычных чисел. На момент написания книги тип money считается устаревшим и использовать его не рекомендуется. В книге он представлен лишь как один из действующих типов, который все еще может встречаться в существующих системах PostgreSQL.
Вместо типа money следует использовать тип numeric с масштабом 2 и точностью, достаточной для представления максимальной необходимой величины (включая две цифры для дробной части). Форматирование, аналогичное типу money, выполняется при помощи функции to_char(), используемой в листинге 3.23. В этом примере продемонстрирован оператор конкатенации и функция форматирования текста ltrim(), о которых рассказано в главе 4.


Тип serial



Тип serial

Хотя тип serial не относится к числу стандартных типов, он часто используется при создании в таблице полей-идентификаторов, содержащих уникальное значение для каждой записи. В типе serial объединены функциональные возможности 4-байтового типа integer, индекса и последовательности. В листинге 3.24 тип serial генерирует уникальный идентификатор для каждой записи в таблице auto_identified.
В листинге 3.25 та же задача решается при помощи поля типа integer, функции nextval() и последовательности (последовательности описаны в главе7). На момент написания книги эти два способа были функционально тождественными.


Тип timestamp



Тип timestamp

Тип timestamp PostgreSQL сочетает функциональные возможности типов date и time. Формат timestamp состоит из даты, за которой следует минимум один пробел, после чего идет время и необязательный часовой пояс.
В этом формате поддерживаются любые сочетания форматов даты и времени, перечисленные в табл. 3.15 и 3.20. Примеры допустимого ввода в формате timestamp приведены в табл. 3.22.


Типы данных



Типы данных

SQL относится к категории языков с сильной типизацией. Это означает, что с любым объектом данных, представленным в PostgreSQL, связывается определенный тип, даже если на первый взгляд это и не очевидно. Тип данных одновременно определяет и ограничивает разновидности операций, которые могут выполняться с этими данными.
Типы не только ассоциируются со всеми данными, но и играют важную роль при создании таблиц. Как упоминалось в разделе «Знакомство с реляционными базами данных», таблицы состоят из одного или нескольких полей. При создании таблицы каждому полю, помимо имени, назначается определенный тип данных.
Примечание 1
Примечание 1


Хотя в PostgreSQL предусмотрен достаточно широкий спектр встроенных типов данных, вы также можете определять собственные типы данных командой CREATE TYPE. За дополнительной информацией обращайтесь к описанию команды CREATE TYPE.
В табл. 3.10 перечислены базовые типы данных PostgreSQL, а также их синонимы (альтернативные имена). Также существует множество внутренних (то есть не предназначенных для нормального использования) и устаревших типов данных, которые не приводятся в таблице.
Хотя большинство типов данных PostgreSQL взято непосредственно из стандартов SQL, существуют и другие, нестандартные типы данных (например, гео-
метрические и сетевые типы). По этой причине у типов данных PostgreSQL не всегда находятся прямые аналоги в других СУБД на базе SQL.


Вещественные константы



Вещественные константы

Вещественные константы обладают определенным сходством с целочисленными константами, но используются для представления не только целых, но и дробных величин.
Существует несколько форматов представления вещественных констант, представленных в табл. 3.4. Запись ## означает одну или несколько цифр.


Встроенные константы даты и времени



Встроенные константы даты и времени

В PostgreSQL предусмотрено несколько специальных констант, представляющих стандартные значения даты и времени. Эти константы перечислены в табл. 3.23.


команда SQL состоит из отдельных



Выводы

Итак, команда SQL состоит из отдельных лексем, каждая из которых может быть ключевым словом, идентификатором, защищенным идентификатором, константой или специальным символом. В табл. 3.7 структура команд SQL поясняется на примере простой команды SELECT.

Защищенные идентификаторы



Защищенные идентификаторы

Хотя обычно это и не требуется, идентификаторы могут заключаться в кавычки, указывающие на их буквальную интерпретацию. Например, просмотр всех полей таблицы с именем states обычно производится следующей простой командой:
booktown=# SELECT * FROM states;
id | name | abbreviation
---+-------+---------------
33|Oregon|OR
42| Washington | WA
(2 rows)
Команда содержит ключевые слова SELECT и FROM, а также идентификаторы * (обозначение всех полей) и states (имя таблицы). Команда производит выборку всех полей таблицы states и выводит все ее содержимое.
Аналогичного эффекта можно добиться, заключив идентификатор в кавычки:
booktown=# SELECT * FROM "states";
id | name I abbreviation
33 | Oregon | OR 42 | Washington | WA (2 rows)
Как показывает этот пример, применение кавычек к идентификаторам, записанным символами нижнего регистра, ни на что не влияет. Однако попытка защитить идентификатор stAtes в следующей команде приводит к неудаче:
booktown=# SELECT * FROM "stAtes";
ERROR: Relation 'stAtes' does not exist
Дело в том, что команда приказывает PostgreSQL найти таблицу с именем stAtes (вместо states). Другими словами, заключая идентификатор в кавычки, мы требуем, чтобы интерпретатор PostgreSQL интерпретировал его буквально.
Все незащищенные идентификаторы преобразуются к нижнему регистру. Любая смешанная комбинация символов разных регистров (stAtEs, STATES) при отсутствии кавычек перед выполнением команды автоматически приводится к виду states.
Примечание 1
Примечание 1


Преобразование незащищенных идентификаторов к нижнему регистру является отличительной особенностью PostgreSQL. В соответствии со стандартом SQL92 незащищенные идентификаторы должны преобразовываться к верхнему регистру. По историческим причинам, а также для удобства чтения PostgreSQL не выполняет требования данной части стандарта SQL92. Это обстоятельство особенно важно для администраторов баз данных, знакомых с другими продуктами SQL, в которых идентификаторы автоматически преобразуются к верхнему регистру (например, Oracle). Чтобы ваши приложения легко адаптировались для других платформ, помните о проблеме регистра во избежание конфликтов.
Модуль лексического разбора нормально воспринимает команды, записанные в смешанном регистре (при условии правильности их синтаксиса). Тем не менее к выбору регистра символов при записи программ следует относиться внимательно, поскольку смена регистра символов при оформлении программы может как упростить, так и затруднить чтение большого объема кода SQL.
В этой книге идентификаторы записываются символами нижнего регистра, а ключевые слова — верхнего. Визуальное отделение фиксированных системных синтаксических элементов от пользовательских объектов данных значительно упрощает чтение и понимание сложных команд SQL.


Знакомство с реляционными базами данных



Знакомство с реляционными базами данных

PostgreSQL относится к категории объектно-реляционных систем управления базами данных (ОРСУБД). Модель ОРСУБД представляет собой усовершенствование более традиционной модели реляционной системы управления базами данных (РСУБД). В РСУБД логически связанные данные хранятся в двумерных структурах, называемых таблицами. Данные могут состоять из элементов, относящихся к различным стандартным типам — целые и вещественные числа, символы, строки, дата/время. В таблице элементы данных образуют «решетку» из столбцов (полей) и строк (записей). Одной из главных особенностей реляционной модели является ее концептуальная простота, причем это может считаться как ее главным достоинством, так и главным недостатком.
Объектно-реляционная специфика PostgreSQL дополняет традиционную реляционную модель данных многочисленными усовершенствованиями. К их числу относится поддержка массивов (хранения нескольких элементов в одном поле), наследования (связей типа «предок—потомок» между таблицами) и функций (программных методов, вызываемых командами SQL). Для опытных программистов в PostgreSQL даже предусмотрены возможности расширения типов данных и использования процедурных языков.
Вследствие объектно-реляционной ориентации таблицы иногда называются классами, а записи и поля могут соответственно именоваться экземплярами (instances) и атрибутами (attributes). В книге эти термины считаются синонимами. Другие структуры данных SQL (такие, как индексы и представления) иногда называются объектами базы данных.
Примечание 1
Примечание 1


Учтите, что термин «объектно-реляционный» не является синонимом термина «объектно-ориентированный», характерного для многих современных языков программирования. Несмотря на поддержку ряда объектных усовершенствований, PostgreSQL все равно формально является реляционной системой управления базами данных (РСУБД).


Знакомство с SQL



Знакомство с SQL

SQL (Structured Query Language) — мощный, универсальный и проверенный временем язык запросов к реляционным базам данных. История SQL восходит к научным разработкам компании IBM в 70-х годах. В нескольких ближайших разделах вы познакомитесь с историей языка SQL, его предшественниками и различными стандартами SQL, появившимися за эти годы.


SQL в PostgreSQL

Анализ структуры таблицы



Анализ структуры таблицы

Команда \d (с указанием имени таблицы) предназначена для вывода структуры таблицы и ее ограничений, если они имеются. В листинге 4.7 приведены выходные данные команды \d для таблицы books, созданной в предыдущем разделе.
Обратите внимание: каждая строка результата описывает одно из полей (то есть столбцов) таблицы; таким образом, таблица фактически разворачивается па 90°. Такое представление выбрано для наглядности, поскольку многие таблицы содержат большое количество полей, не помещающихся на экране (или на печатной странице) по горизонтали. В книге этот формат будет использоваться при описании структуры таблиц.


COPY TO



COPY TO

Синтаксис команды COPY FROM практически аналогичен синтаксису команды, предназначенной для экспортирования данных в файл, просто ключевое слово FROM заменяется ключевым словом ТО. Кроме того, ключевое слово stdin заменяется ключевым словом stdout, если выходные данные вместо файла направляются в стандартный вывод (например, на экран в psql). В листинге 4.22 приведен пример экспортирования таблицы books в ASCII-файл.


Добавление данных командами INSERT и COPY



Добавление данных командами INSERT и COPY

После создания таблицы с заданной структурой наступает следующий этап — заполнение таблицы данными. В PostgreSQL имеются три общих способа заполнения таблиц данными:
  • вставка новых группированных данных командой INSERT INTO;
  • вставка существующих данных из другой таблицы командой INSERT INTO в сочетании с командой SELECT;
  • вставка данных из внешнего файла командой COPY (или \copy).


Добавление ограничений



Добавление ограничений

После создания таблицы сохраняются некоторые возможности добавления ограничении. В PostgreSQL 7.1.x команда ALTER TABLE с секцией ADD CONSTRAINT позволяет определять для полей существующих таблиц только ограничения внешнего ключа и проверки. Команда создания новых ограничений имеет следующий синтаксис:
ALTER TABLE таблице
ADD CONSTRAINT имя_ограничения определение
Синтаксис определения зависит от типа ограничения. В листинге 4.12 продемонстрирован синтаксис создания ограничения внешнего ключа для таблицы editions (связанной с полем id таблицы books) и ограничения проверки для поля type.


Другие возможности SQL



Другие возможности SQL

В этой главе были представлены фундаментальные концепции применения языка SQL в PostgreSQL. В частности, были рассмотрены вопросы создания таблиц и выполнения с ними различных операций, включая выборку и модификацию данных. В главе 5 будут подробно описаны функции и операторы PostgreSQL, многие из которых уже встречались в этой главе.



Двоичный формат



Двоичный формат

Команда COPY также позволяет выполнять операции ввода и вывода с данными в двоичном формате. Если команда COPY FROM содержит ключевое слово BINARY, входной файл должен быть создан командой COPY TO в двоичном формате PostgreSQL. Двоичные файлы загружаются быстрее ASCII-файлов, но в отличие от последних их нельзя читать и редактировать в простых текстовых редакторах.
В листинге 4.21 приведена команда COPY, предназначенная для вставки записей из двоичного файла в таблицу subjects базы данных booktown.


Группировка записей



Группировка записей

Секция GROUP BY представляет чрезвычайно мощную концепцию SQL — агрегирование. На практике агрегирование запросов SQL приводит к тому, что все записи с одинаковыми значениями выражения, заданного в секции GROUP BY, группируются в одну агрегатную запись. Выражение GROUP BY может быть простым полем таблицы, но оно также может представлять собой произвольную операцию с полем. При перечислении нескольких полей или выражений, разделенных запятыми, группировка записей осуществляется лишь при совпадении записей по всем критериям.
Чтобы эффективно пользоваться агрегированием, необходимо понимать, что все целевые поля, участвующие в агрегирующем запросе, но не указанные в секции GROUP BY, доступны лишь при выборке через агрегатную функцию. Агрегатная функция получает имя поля (или выражение, в котором участвует хотя бы одно имя поля), представляющее несколько значений (например, в нескольких сгруппированных записях), выполняет с ними некоторую операцию и возвращает одно значение.
Самые распространенные агрегатные функции:
  • count () — возвращает количество записей в наборе;
  • тах () — возвращает максимальное значение в наборе;
  • min () — возвращает минимальное значение в наборе.
Агрегатные функции работают только с записями итогового набора, поэтому они выполняются после обработки всех условных объединений и секций WHERE.
Предположим, вы хотите вывести количество книг, хранящихся в базе данных booktown для каждого издательства. Название издательства связывается с названиями опубликованных книг простым объединением таблиц editions и publishers, однако подсчитывать записи вручную весьма утомительно, а при очень больших объемах итоговых наборов — вообще неприемлемо.
В листинге 4.40 выполняется стандартное объединение двух таблиц базы данных booktown, но в нем присутствуют два новых элемента: вызов функции count () и секция GROUP BY.


Использование таблиц



Использование таблиц

Таблицы являются основными блоками хранения данных в базе. Перед любыми операциями создания, выборки или модификации записей необходимо сначала создать таблицу, в которой эти записи будут храниться.
В этом разделе рассматриваются процедуры создания, модификации и удаления таблиц командами CREATE TABLE, ALTER TABLE n DROP TABLE SQL (вопросам создания баз данных посвящена глава 9).


Конструкции CASE



Конструкции CASE

Чтобы программа SQL могла принимать простейшие решения, не прибегая к процедурным языкам, в PostgreSQL поддерживаются конструкции CASE, предусмотренные стандартом SQL Ключевые слова SQL CASE, WHEN, THEN и END позволяют выполнять простые условные преобразования записей.
Вся конструкция CASE включается в целевой список команды SELECT. По умолчанию итоговому полю конструкции CASE присваивается имя case, но ему можно назначить синоним, как любому обычному полю. Общий синтаксис конструкции CASE в списке целей команды SELECT выглядит следующим образом:
CASE WHEN условие! THEN результат! WHEN условие2 THEN результат2
[ ... ]
[ ELSE результат_по_умопчанию END [ AS синоним ]
Конструкция CASE-WHEN-THEN-ELSE отчасти напоминает условные команды f-then-else в традиционных языках программирования (листинг 4.50). Условия секций WHEN должны возвращать логический результат.
Если условие в секции WHEN выполняется, результат соответствующей секции THEN возвращается в поле итогового набора. Если ни одно условие не выполнено, можно задать значение по умолчанию в секции ELSE. Если при отсутствии секции ELSE результат остается неопределенным, возвращается NULL.


Копирование данных из внешних файлов командой COPY



Копирование данных из внешних файлов командой COPY

В PostgreSQL поддерживается и такая полезная возможность, как прямое импортирование данных в таблицу из внешних файлов командой COPY. Файл, содержащий входные данные команды COPY, хранится либо в стандартном текстовом формате ASCII с ограничением полей специальным символом-разделителем, либо в двоичном формате таблиц PostgreSQL. В ASCII-файлах в качестве разделителя обычно используется символ табуляции или запятая. При импортировании данных из ASCII-файла каждая строка файла интерпретируется как отдельная запись данных, а каждый компонент строки — как значение соответствующего поля записи.
Команда COPY FROM работает значительно быстрее обычной команды INSERT, поскольку данные передаются прямо в приемную таблицу за одну транзакцию. С другой стороны, к формату исходного файла предъявляются чрезвычайно жесткие требования, поэтому ошибка всего в одной строке приводит к сбою всей команды COPY.
Синтаксис команды COPY FROM:
COPY [ BINARY ] таблица [ WITH 0IDS ]
FROM { 'имя_файла' \ stdin }
[ [USING] DELIMITERS 'разделитель' ]
[ WITH NULL AS 'строка_nulГ ]
Ниже поясняется смысл параметров команды.
  • BINARY. Признак импортирования входных данных из двоичного файла, ранее созданного командой COPY TO.
  • таблица. Имя таблицы, в которую импортируются данные.
  • WITH OIDS. Из первой строки файла загружаются значения всех идентификаторов OID импортируемой таблицы.
  • FROM { 'имя_файла' \ stdin }. Источник, из которого PostgreSQL получает входные данные — файл с заданным именем либо стандартный ввод (stdin).
  • [ USING ] DELIMITERS 'разделитель'. Символ, используемый в качестве разделителя при разборе входных данных. Не используется для файлов, выведенных в двоичном формате PostgreSQL.
  • WITH NULL AS ' строка_null. Заданная строка должна интерпретироваться как значение NULL. He используется для файлов, выведенных в двоичном формате PostgreSQL.
При подготовке к импортированию файла проследите за тем, чтобы этот файл был доступен для чтения процессом postmaster (то есть пользователем, запустившим PostgreSQL). Кроме того, разрешены только абсолютные имена файлов; при попытке передать относительное имя происходит ошибка.
При работе с входными файлами в формате ASCII в секции DELIMITERS передается символ, используемый в качестве разделителя значений полей в строках файла. Если разделитель не указан, PostgreSQL считает, что значения разделяются символом табуляции. Необязательная секция WITH NULL определяет формат, в котором передаются значения NULL. Если секция отсутствует, PostgreSQL интерпретирует последовательность \N как NULL (например, пустые поля исходного файла по умолчанию интерпретируются как пустые строковые константы, а не как NULL).
Если данные вводятся вручную или передаются терминалу другой программой, в качестве источника в секции FROM можно указать стандартный ввод (stdin). При получении данных из стандартного ввода входной поток должен завершаться последовательностью \. (обратная косая черта плюс точка), за которой немедленно следует символ новой строки.
В листинге 4.19 приведено содержимое файла, выведенного PostgreSQL в формате ASCII. Поля разделяются запятыми, а для представления NULL используется строка \null.B файле сохранены данные из таблицы subjects базы данных booktown.


Назначение системного пути для psql



Листинг 4.1. Назначение системного пути для psql

[user@host user]$ psql
bash: psql: command not found
[user@host user]$ echo $PATH
/b1n:/usr/bin:/usr/local/bin:/usr/bin/Xll:/usr/XHR6/tnn
[user@host user]$ export PATH=$PATH:/usr/local/pgsql/bin
[user@host user]$ psql testdb
Welcome to psql. the PostgreSQL interactive terminal.
Type: \copyright for distribution terms \h for help with SQL commands \? for help on internal slash commands \g or terminate with semicolon to execute query \q to quit
testdb=#
После настройки переменной PATH интерактивный терминал PostgreSQL запускается командой psql, за которой следует имя базы данных.
ВНИМАНИЕ
После выхода из psql изменения переменной среды будут потеряны. Чтобы изменения переменной PATH сохранялись после выхода из программы, команда настройки PATH включается в стартовый сценарий командного интерпретатора (например, ~/.bash_profile).


относящийся к интерпретатору



Листинг 4.1, относящийся к интерпретатору bash, иллюстрирует процедуру назначения системного пути для клиента psql.

Переименование таблицы



Листинг 4.10. Переименование таблицы

oktown=# ALTER TABLE books RENAME TO literature;
TER
oktown=# ALTER TABLE literature RENAME TO books;
TER


Переименование поля



Листинг 4.11. Переименование поля

booktown=# \d daily_inventory
Table "daily_inventory"
Attribute | Type | Modifier
isbn | text
in_stock | boolean |
booktown=# ALTER TABLE daily_inventory
booktown-# RENAME COLUMN in_stock TO is_in_stock;
ALTER
booktown=# ALTER TABLE daily_inventory
booktown-l RENAME COLUMN is_in_stock TO is_stocked;
ALTER


Создание новых ограничений



Листинг 4.12. Создание новых ограничений в существующей таблице

booktown=# ALTER TABLE editions
booktown-# ADD CONSTRAINT foreign_book
booktown-# FOREIGN KEY (book_id) REFERENCES books (id);

NOTICE: ALTER TABLE ... ADD CONSTRAINT will create implicit trigger(s)
for FOREIGN KEY check(s)
CREATE
booktown=# ALTER TABLE editions
booktown-# ADD CONSTRAINT hard_or_paper_back
booktown-# CHECK (type = 'p' OR type = 'h'):
ALTER
Установка ограничения внешнего ключа приводит к тому, что любое значение book_i d в таблице edi ti ons также должно существовать в таблице books. Кроме того, вследствие установленного ограничения проверки поле type в таблице editions может содержать только значения р или Ь.
Примечание 2
Примечание 2


Ограничение уникальности также неявно устанавливается при создании уникального индекса командой CREATE INDEX (см. раздел «Индексы» в главе 7).
Дополнительная информация об ограничениях, их назначении и синтаксисе приведена в главе 7.


Смена владельца таблицы



Листинг 4.13. Смена владельца таблицы

booktown=# ALTER TABLE employees booktown-# OWNER TO corwin;
ALTER
Примечание 3
Примечание 3


Смена владельца таблицы может осуществляться либо текущим владельцем, либо суперпользователем PostgreSQL.


Реструктуризация



Листинг 4.14. Реструктуризация таблицы командой CREATE TABLE AS

booktown=# \d books
Table "books" Attribute | Type | Modifier
id | integer | not null
title text I not null
authorjd | integer |
subjectjd integer j
publication j date | Index: books_id_pkey
booktown=# CREATE TABLE new_books
booktown-# (id, title. authorjd, subjectjd)
booktown-# AS SELECT id, title, authorjd, subjectjd
booktown-f FROM books;
SELECT
booktown=# ALTER TABLE books RENAME TO old_books;
ALTER
booktown=# ALTER TABLE new_books RENAME TO books;
ALTER
booktown=# \d books
Table "books" Attribute | Type | Modifier
id | integer |
title | text |
authorjd j integer j
subjectjd | integer |
booktown=# DROP TABLE books;
DROP
ВНИМАНИЕ
В PostgreSQL 7.1.x присутствие в команде SELECT необязательного списка полей, заключенного в круглые скобки, исключает использование специального символа *. Недостаток должен быть исправлен в PostgreSQL 7.2.


Реструктуризация



Листинг 4.15. Реструктуризация таблицы командами CREATE TABLE и INSERT INTO

booktownHf CREATE TABLE new_books (
booktown(# id integer UNIQUE,
booktown(# title text NOT NULL.
booktown(# authorjd integer.
booktown(# subjectjd integer.
booktown(# CONSTRAINT books_id_pkey PRIMARY КЕУ (id)
booktown(# ):
NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index ' books Jd_pkey'
for table 'new_books'
CREATE
booktown=# INSERT INTO new_books
booktown-# SELECT id, title, author_id, subjectjd
booktown-f FROM books;
INSERT 0 12
booktown=# ALTER TABLE books RENAME TO old_books;
ALTER
booktown=# ALTER TABLE new_books RENAME TO books:
ALTER
booktown=# \d books
Table "books" Attribute | Type | Modifier
id | integer | not null
title ( text I not null
authorjd integer j
subjectjd integer | Index: booksjd_pkey
За дополнительной информацией об использовании команды INSERT INTO с командой SELECT обращайтесь к подразделу «Вставка данных из других таблиц командой SELECT» раздела «Добавление данных командами INSERT и COPY». Команда SELECT рассматривается в разделе «Выборка данных командой SELECT».


Вставка новой записи в таблицу books



Листинг 4.16. Вставка новой записи в таблицу books

booktown=# INSERT INTO books (Id, title, author_id, subject_id)
booktown-# VALUES (41472, 'Practical PostgreSQL', 1212, 4);

INSERT 3574037 1
Команда SQL, приведенная в листинге 4.16, вставляет новую запись с кодом (id) 41472, названием «Practical PostgreSQL», кодом автора 1212 и кодом темы 4. Обратите внимание на завершающее сообщение, начинающееся со слова INSERT, — оно указывает на то, что операция вставки была выполнена успешно. Первое число после INSERT является идентификатором объекта (OID) созданной записи, а второе число обозначает количество созданных записей (в нашем примере,— 1).
В приведенном примере необязательный список полей совпадает с порядком следования полей в структуре таблицы (слева направо). В данном случае этот список можно опустить, поскольку команда INSERT предполагает, что значения присваиваются в естественном порядке следования полей таблицы. Поля в списке можно переставить, но в этом случае порядок значений в секции VALUES тоже должен измениться, как показано в листинге 4.17.


Изменение порядка перечисления полей



Листинг 4.17. Изменение порядка перечисления полей

booktown=# INSERT INTO books (subjected, author_id, id, title)
booktown-# VALUES (4, 7805, 41473, 'Programming Python');

INSERT 3574041 1


Вставка данных из другой таблицы



Листинг 4.18. Вставка данных из другой таблицы

booktown-# INSERT INTO books (id, title, author_id, subject_id)
booktown-# SELECT nextval('book_ids', title, author_id, subject_id
booktown-# FROM book_queue WHERE approved;
INSERT 0 2
В приведенном примере запрос SELECT, включенный в команду INSERT INTO, переносит две записи из таблицы book_queue в таблицу books. В этом контексте допускается использование любой синтаксически правильной команды SELECT. В нашем примере в выборку включается результат вызова функции nextval () для последовательности bookj ds, за которым следуют значения полей title, author_id и subject_id из таблицы book_queue.
На этот раз команда создает сразу несколько новых записей, поэтому в сообщении об успешном выполнении операции вместо значения OID, которое выводилось бы при вставке одной записи, выводится 0. Второе число, как и в случае с обычной командой INSERT INTO, равно количеству созданных записей (в данном случае — 2).


Пример копируемого ASCIIфайла



Листинг 4.19. Пример копируемого ASCII-файла

1.Business.Productivity Ave
2.Children's Books,Kids Ct
3.Classics.Academic Rd
4,Computers,Productivity Ave
5,Cooking.Creativity St
12.Religion.\null
8.Hi story.Academic Rd
9.Horror.Black Raven Dr
10.Mystery.Black Raven Dr
11.Poetry.Sunset Dr
13.Romance.Main St
14.Science.Productivity Ave
15.Science Fiction.Main St
0.Arts.Creativity St
6.Drama.Main St
7.Entertainment.Main St
Следующая команда (листинг 4.20) импортирует содержимое файла /tmp/ subjects.sql в таблицу subjects базы данных booktown.


Получение списка команд psql booktown=# \?



Листинг 4.2. Получение списка команд psql booktown=# \?

\а toggle between unaligned and aligned mode
\c[onnect] [dbname|- [user]]
connect to new database (currently 'booktown')
\C <br> table title <br> \copy... perform SQL COPY with data stream to the client machine <br> \copyright show PostgreSQL usage and distribution terms <br> \d <table> <br> describe table (or view, index, sequence) <br> \d{t|i|s|v} list tables/indices/sequences/views <br> \d{p|S|l} list permissions/system tables/lobjects <br> \da list aggregates <br> \dd [object] list comment for table, type, function, or operator <br> \df list functions <br> \do list operators <br> \dT list data types <br> \e [file] edit the current query buffer or [file] with external editor <br> \echo <text> <br> write text to stdout <br> \encoding <encoding> <br> set client encoding <br> \f <sep> <br> change field separator <br> \g [file] send query to backend (and results in [file] or (pipe) <br> \h [cmd] help on syntax of sql commands. * for all commands <br> \H toggle HTML mode (currently off) <br> \i<file> <br> read and execute queries from <file> <br> <br> \l list all databases <br> \lo_export. \lo_import, \lo_list. \lo_unlink <br> Targe object operations <br> \o [file] send all query results to [file], or (pipe <br> \p show the content of the current query buffer <br> \pset <opt> <br> set table output <opt> <br> = {format|border|expanded|fieldsep| <br> null|recordsep|tuples_only|title|tableattr|pagerj <br> \q quit psql <br> \qecho <text> <br> write text to query output stream (see \o) . <br> \r reset (clear) the query buffer <br> \s [file] print history or save it in [file] \set <var> <br> <value> <br> set internal variable <br> \t show only rows (currently off) <br> \T <tags> <br> HTML table tags <br> \unset <var> <br> unset (delete) internal variable <br> \w <file> <br> write current query buffer to a <file> <br> <br> \x toggle expanded output (currently off) <br> \z list table access permissions <br> \! [cmd] shell escape or command <br> <br><br> <h1>Копирование ASCIIфайла</h1> <br> <br>Листинг 4.20. Копирование ASCII-файла <br><br> booktown=# COPY subjects FROM '/tmp/subjects.sql' <br> booktown-# USING DELIMITERS '.' WITH NULL AS '\null; <br> COPY <br> <br><br> <h1>Копирование двоичного файла</h1> <br> <br>Листинг 4.21. Копирование двоичного файла <br><br> booktown=# COPY BINARY subjects FROM '/tmp/subjects.sql'; <br> COPY <br> <br><br> <h1>Экспортирование таблицы books в файл ASCII</h1> <br> <br>Листинг 4.22. Экспортирование таблицы books в файл ASCII <br><br> booktown=# COPY books TO 'filename'; <br> COPY <br> <br><br> <h1>Выборка всех записей из таблицы books</h1> <br> <br>Листинг 4.23. Выборка всех записей из таблицы books <br><br> 300ktown=# SELECT * FROM books; <br> id | title | author_id | subject_id <br> 7808 | The Shining | 4156 | 9 <br> 4513 | Dune | 1866 | 15 <br> 4267 | 2001: A Space Odyssey | 2001 | 15 <br> 1608 | The Cat in the Hat | 1809 | 2 <br> 1590 | Bartholomew and the Oobleck | 1809 | 2 <br> 25908 | Franklin in the Dark | 15990 | 2 <br> 1501 | Goodnight Moon | 2031 | 2 <br> 190 | Little Women | 16 | 6 <br> 1234 | The Velveteen Rabbit | 25041 | 3 <br> 2038 | Dynamic Anatomy | 1644 | 0 <br> 156 | The Tell-Tale Heart | 115 | 9 <br> 41472 | Practical PostgreSQL | 1212 | 4 <br> 41473 | Programming Python | 7805 | 4 <br> 41477 | Learning Python 7805 | 4 <br> 41478 | Perl Cookbook | 7806 | 4 <br> (15 rows) <br> <br><br> <h1>Изменение порядка следования полей при выборке</h1> <br> <br>Листинг 4.24. Изменение порядка следования полей при выборке <br><br> booktown=# SELECT Id, author_id, title, id <br> booktown-# FROM books;<br> id | authorjd | title | id <br> 7808 | 4156 | The Shining | 7808 <br> 4513 | 1866 | Dune | 4513 <br> 4267 | 2001 | 2001: A Space Odyssey | 4267 <br> 1608 | 1809 | The Cat in the Hat | 1608 <br> 1590 | 1809 | Bartholomew and the Oobleck | 1590 <br> 25908 | 15990 | Franklin in the Dark | 25908 <br> 1501 | 2031 | Goodnight Moon | 1501 <br> 190 | 16 | Little Women | 190 <br> 1234 | 25041 | The Velveteen Rabbit | 1234 <br> 2038 | 1644 | Dynamic Anatomy | 2038 <br> 156 | 115 | The Tell-Tale Heart | 156 <br> 41472 | 1212 | Practical PostgreSQL | 41472 <br> 41473 | 7805 | Programming Python | 41473 <br> 41477 | 7805 | Learning Python | 41477 <br> 41478 | 7806 | Perl Cookbook | 41478<br> (15 rows) <br> Как нетрудно убедиться, команды SELECT в листингах 4.23 и 4.24 возвращают одинаковые наборы данных. Во втором наборе используется другой порядок следования полей (поле subject_id отсутствует, а поле id встречается дважды), что связано с явным перечислением полей после ключевого слова SELECT. <br> <br><br> <h1>Выражения и константы</h1> <br> <br>Листинг 4.25. Выражения и константы <br><br> testdb=# SELECT 2+2, <br> testdb-# pi (),<br> testdb-# 'PostgreSQL is more than a calculator!'; <br> ?column?| pi | ?column? <br> 4 | 3.14159265358979 | PostgreSQL <br> is more than a calculator! <br> (1 row) <br> Для каждой цели в списке может задаваться необязательная секция AS, которая назначает синоним (новое произвольное имя) для каждого поля в итоговом наборе. Имена синонимов подчиняются тем же правилам, что и имена обычных идентификаторов (в частности, они могут содержать внутренние пробелы или совпадать с ключевыми словами при условии заключения их в апострофы и т. д.) <br> Назначение синонима не влияет на исходное поле и действует лишь в контексте итогового набора, возвращаемого запросом. Секция AS особенно удобна при «выборке» выражений и констант, поскольку синонимы позволяют уточнить смысл неочевидных выражений или констант. В листинге 4.26 приведены те же результаты, что и в листинге 4.25, но с другими названиями полей. <br> <br><br> <h1>Секция AS с выражениями и константами</h1> <br> <br>Листинг 4.26. Секция AS с выражениями и константами <br><br> booktown=# SELECT 2 + 2 AS "2 plus 2",<br> booktown-# pi() AS "the pi fnction", <br> booktown-# 'PostgreSQL is more than a calculator!' AS comments; <br> 2 plus 2 | the pi function | comments <br> 4 | 3.14159265358979 | PostgreSQL is more than a calculator! <br> (1 row)<br> <br><br> <h1>Выборка из нескольких таблиц</h1> <br> <br>Листинг 4.27. Выборка из нескольких таблиц <br><br> booktown=# SELECT books.id, title, authors_id, last_name <br> booktown-# FROM books, authors <br> booktown-# WHERE books.authored = authors.id; <br> id | title | id | last_name <br> 190 | Little Women | 16 | Alcott <br> 156 | The Tell-Tale Heart | 115 | Рое <br> 41472 | Practical PostgreSQL | 1212 | Worsley <br> 2038 | Dynamic Anatomy | 1644 | Hogarth<br> 1608 | The Cat in the Hat | 1809 | Geisel <br> 1590 |Bartholomew and the Oobleck | 1809 | Geisel <br> 4513 | Dune | 1866 | Herbert<br> 4267 | 2001: A Space Odyssey | 2001 | Clarke <br> 1501 | Goodnight Moon | 2031 | Brown <br> 7808 | The Shining | 4156 | King <br> 41473 |Programming Python | 7805 | Lutz <br> 41477 |Learning Python | 7805 | Lutz <br> 41478 | Perl Cookbook | 7806 | Christiansen <br> 25908 | Franklin in the Dark | 15990 | Bourgeois <br> 1234 | The Velveteen Rabbit | 25041 | Bianco <br> (15 rows) <br> При использовании ссылок на имена полей, относящихся к разным источникам, может возникнуть неоднозначность. Предположим, команда SELECT получает исходные данные из таблиц books и authors. В каждой из этих таблиц имеется поле с именем id. Без дополнительных уточнений PostgreSQL не сможет определить, к какой таблице относится ссылка на поле i d в следующей команде: <br> booktown=# SELECT id FROM books, authors <br> ERROR: Column reference "id" is ambiguous <br> Для предотвращения неоднозначности в «полные» имена столбцов включается имя таблицы. При этом используется специальный синтаксис, называемый точечной записью (название связано с тем, что имя таблицы отделяется от имени поля точкой). Например, books .id означает поле id таблицы books. <br> Точечная запись обязательна только при наличии неоднозначности между наборами данных. Как показано в листинге 4.27, ссылка может состоять только из имени поля — при условии, что это имя уникально во всех наборах данных, перечисленных в секции FROM. В приведенном примере поле title присутствует только в таблице books, а поле last_name входит только в таблицу authors, поэтому на их имена можно ссылаться без уточнения. <br> Если в качестве источника используется итоговый набор, созданный подзапросом, то весь подзапрос заключается в круглые скобки. По наличию круглых скобок PostgreSQL узнает о том, что команда SELECT интерпретируется как подзапрос, и выполняет ее перед выполнением внешней команды SELECT. <br> В листинге 4.28 приведен несколько необычный запрос, который производит выборку значений всех полей (*) таблицы books с использованием подзапроса. Затем из полученного набора «выбирается» строковая константа test и значение поля id. <br> <br><br> <h1>Выборка из подзапроса</h1> <br> <br>Листинг 4.28. Выборка из подзапроса <br><br> booktown=# SELECT 'test' AS test, id <br> booktown-# FROM (SELECT * FROM books)<br> booktown-# AS example_sub_query;<br> test | id<br> test | 7808 <br> test | 4513 <br> test | 4267 <br> test | 1608 <br> test | 1590 <br> test | 25908 <br> test | 1501 <br> test | 190 <br> test | 1234 <br> test | 2038 <br> test | 156 <br> test | 41472 <br> test | 41473 <br> test | 41477 <br> test | 41478 <br> (15 rows) <br> Странность запроса в листинге 4.28 заключается в том, что общий результат принципиально не отличается от прямой выборки из таблицы books, поскольку результат подзапроса идентичен ее содержимому. Строковая константа из одной команды SELECT комбинируется с данными из набора, полученного другой командой SELECT. Более реалистичный пример использования подзапросов приведен ниже в разделе «Подзапросы», но сначала необходимо лучше разобраться в том, как работает команда SELECT. <br> Примечание 1 <br>Примечание 1<br><br><br> Необязательное ключевое слово ONLY перед именем таблицы, которая является базовой по отношению к другим таблицам, означает, что выборка из производных таблиц не выполняется (наследование рассматривается в главе 7). <br> <br><br> <h1>Определение синонимов для источников данных</h1> <br> <br>Листинг 4.29. Определение синонимов для источников данных <br><br> booktown=# SELECT b.id, title, a.id, last_name <br> booktown-# FROM books AS b, authors AS a<br> booktown-# WHERE b.author_id = a.id; <br> id | title | id lastjname <br> 190 | Little Women | 16 | Alcott <br> 156 | The Tell-Tale Heart | 115 | Рое <br> 41472 | Practical PostgreSQL | 1212 | Worsley <br> 2038 | Dynamic Anatomy | 1644 | Hogarth<br> 1608 | The Cat in the Hat | 1809 | Geisel <br> 1590 | Bartholomew and the Oobleck | 1809 | Geisel <br> 4513 | Dune | 1866 | Herbert<br> 4267 | 2001: A Space Odyssey | 2001 | Clarke <br> 1501 | Goodnight Moon | 2031 | Brown <br> 7808 | The Shining | 4156 | King <br> 41473 | Programming Python | 7805 | Lutz <br> 41477 | Learning Python | 7805 | Lutz <br> 41478 | Perl Cookbook | 7806 | Christiansen <br> 25908 | Franklin in the Dark 15990 | Bourgeois <br> 1234 | The Velveteen Rabbit | 25041 | Bianco <br> (15 rows) <br> Синонимы можно назначать не только для источников данных в секции FROM, но и для отдельных полей внутри этих источников. Для этого за синонимом источника данных приводится список синонимов полей, разделенный запятыми и заключенный в круглые скобки. Список синонимов полей представляет собой последовательность идентификаторов, перечисленных в порядке следования полей в структуре таблицы (слева направо). <br> Список синонимов полей не обязан содержать данные обо всех полях. К тем полям, для которых не были заданы синонимы, можно обращаться по обычным именам. Если единственное поле, которому требуется назначить синоним, находится после других полей, вам придется включить в список все предшествующие поля (синоним поля может совпадать с его именем). В противном случае PostgreSQL не сможет определить, какому полю назначается синоним, и решит, что речь идет о первом поле таблицы. <br> Примечание 2 <br>Примечание 2<br><br><br> Ключевое слово AS не является обязательным. Если оно отсутствует в команде, PostgreSQL считает, что все идентификаторы после ключевого слова FROM являются синонимами. <br> В листинге 4.30 приведен запрос из листинга 4.29, в котором полям id обеих таблиц назначаются уникальные идентификаторы, что позволяет ссылаться на них непосредственно (то есть без применения точечной записи). Синтаксис остается прежним, но на этот раз синоним назначается только полю id таблицы books, в результате ссылка на поле id таблицы authors становится однозначной. <br> <br><br> <h1>Ввод команд в psql</h1> <br> <br>Листинг 4.3. Ввод команд в psql <br><br> testdb=# SELECT * FROM employees <br> testdb-# WHERE firstname = 'Michael'; <br> Запрос из листинга 4.3 возвращает записи обо всех работниках с именем «Michael» из таблицы empl oyees. Деление по строкам использовано лишь для удобства чтения. Запрос передается для обработки только после ввода завершающего символа «точка с запятой». Если в предыдущей строке присутствует символ, требующий парного завершителя (например, круглой скобки или кавычки), этот символ включается в приглашение следующей строки. Например, если начать команду CREATE TABLE с открывающей круглой скобкой и перейти на другую строку, то приглашение будет выглядеть так, как показано в листинге 4.4. <br> <br><br> <h1>Определение синонимов для полей</h1> <br> <br>Листинг 4.30. Определение синонимов для полей <br><br> booktown=# SELECT the_book_id, title, id, last_name <br> booktown-# FROM books AS b (the_book_id), authors <br> booktown-# WHERE author_id = id; <br> id | title id | last_name <br> 190 | Little Women | 16 | Alcott <br> 156 | The Tell-Tale Heart | 115 Рое <br> 41472 | Practical PostgreSQL | 1212 | Worsley <br> 2038 | Dynamic Anatomy | 1644 | Hogarth<br> 1608 | The Cat in the Hat | 1809 | Geisel <br> 1590 | Bartholomew and the Oobleck | 1809 | Geisel<br> 4513 | Dune | 1866 | Herbert <br> 4267 | 2001: A Space Odyssey | 2001 | Clarke <br> 1501 | Goodnight Moon | 2031 | Brown <br> 7808 | The Shining | 4156 | King <br> 41473 | Programming Python | 7805 | Lutz <br> 41477 | Learning Python | 7805 | Lutz <br> 41478 | Perl Cookbook | 7806 | Christiansen <br> 25908 | Franklin in the Dark | 15990 | Bourgeois<br> 1234 | The Velveteen Rabbit | 25041 | Bianco<br> (15 rows)<br> <p ><br> <br><br> <h1>Ключевое слово DISTINCT</h1> <br> <br>Листинг 4.31. Ключевое слово DISTINCT <br><br> booktown=# SELECT DISTINCT author_id <br> booktown-# FROM books; <br> author_id <br> 16 <br> 115 <br> 1212 <br> 1644 <br> 1809 <br> 1866 <br> 2001 <br> 2031 <br> 4156 <br> 7805 <br> 7806 <br> 15990 <br> 25041 <br> (13 rows) <br> booktown=# SELECT DISTINCT ON (author_id) <br> booktown-# author_id. title <br> booktown-# FROM books;<br> author_id | ntitle<br> 16 | Little Women <br> 115 | The Tell-Tale Heart <br> 1212 | Practical PostgreSQL <br> 1644 | Dynamic Anatomy <br> 1809 | The Cat in the Hat <br> 1866 | Dune <br> 2001 | 2001: A Space Odyssey <br> 2031 | Goodnight Moon <br> 4156 | The Shining <br> 7805 | Programming Python <br> 7806 | Perl Cookbook <br> 15990 |Franklin in the Dark <br> 25041 | The Velveteen Rabbit <br> (13 rows) <br> Первый запрос в листинге 4.31 возвращает только 13 записей из таблицы books, хотя таблица содержит 15 записей. Два автора, написавшие по две книги, вошли в итоговый набор лишь в одном экземпляре. <br> Во втором запросе использована другая форма DISTINCT с явным перечислением полей (или выражений), проверяемых на наличие дубликатов. В этом случае запрос также возвращает 13 записей, поскольку секция ON указывает, что дубликаты проверяются по значению поля author_i d. Без секции ON запрос верн)и бы все 15 записей, поскольку по умолчанию PostgreSQL проверяет полное совпадение всех полей. <br> В общем случае PostgreSQL выбирает записи, исключаемые из итогового набора при наличии секции ON, по своему усмотрению. Если в запрос вместе с DISTINCT входит секция ORDER BY, вы можете самостоятельно задать порядок выборки полей так, чтобы нужные записи оказались в начале. Сортировка записей рассматривается в подразделе «Сортировка записей». <br> Если вместо исключения всех дубликатов достаточно сгруппировать записи с повторяющимися значениями некоторого критерия, воспользуйтесь секцией GROUP BY, описанной в подразделе «Группировка записей». <br> <br><br> <h1>Простая секция WHERE</h1> <br> <br>Листинг 4.32. Простая секция WHERE <br><br> booktown=# SELECT * FROM books <br> booktown-# WHERE subject_id = 4; <br> id | title | author_id | subject_id <br> 41472 | Practical PostgreSQL | 1212 | 4 <br> 41473 | Programming Python | 7805 | 4 <br> 41477 | Learning PostgreSQ L | 7805 | 4 <br> 41478 | Perl Cookbook | 7806 | 4 <br> (4 rows) <br> Запрос из листинга 4.32 возвращает только те записи, у которых поле subject_id совпадает с целочисленной константой 4. Итоговый набор содержит всего 4 записи книг о компьютерах вместо 15 записей, приведенных в листинге 4.23. <br> Секция WHERE может содержать несколько условий, объединенных логическими операторами (например, AND или OR) и возвращающими одно логическое значение. Допустим, вас интересуют все записи для книг о компьютерах, которые, кроме того, что они о компьютерах, написаны Марком Лутцем. Запрос уточняется объединением двух условий при помощи логического оператора AND. Возможен и другой вариант — например, поиск всех книг, посвященных компьютерным технологиям или искусству; в этом случае два условия объединяются логическим оператором OR. В листинге 4.33 продемонстрированы оба сценария с ключевыми словами AND и OR. <br> <br><br> <h1>Объединение условий в секции WHERE</h1> <br> <br>Листинг 4.33. Объединение условий в секции WHERE <br><br> booktown=# SELECT title FROM books <br> booktown-# WHERE subject_id = 4 <br> booktown-# AND author_id = 7805; <br> title <br> Programming Python <br> Learning Python <br> (2 rows) <br> booktown=# SELECT title FROM books <br> booktown-# WHERE subject_id = 4 <br> booktown-# AND author_id = 0;<br> title <br> Dynamic Anatomy <br> Practical PostgreSQL <br> Programming Python <br> Learning Python <br> Perl Cookbook <br> (5 rows) <br> Первая команда SELECT в листинге 4.33 содержит два условия, объединенных логическим оператором AND. Первое условие проверяет, что книга посвящена компьютерным технологиям (поле subject_id равно 4), а второе — что автором книги является Марк Лутц (поле author_id равно 7805). Объединение условий уменьшает объем итогового набора — в него входят всего две записи, удовлетворяющие обоим условиям. <br> Во второй команде SELECT в листинге 4.33 прежнее первое условие (книги по компьютерной тематике) объединяется со вторым условием: книги по искусству (поле subject_id равно 0). В результате объем итогового набора увеличивается до пяти записей, каждая из которых удовлетворяет хотя бы одному из этих условий. <br> Количество условий, объединяемых в секции WHERE, не ограничено, хотя при наличии двух и более условий обычно выполняется группировка при помощи круглых скобок, наглядно демонстрирующая логическую связь между условиями.<br> <br><br> <h1>Группировка условий при помощи круглых скобок</h1> <br> <br>Листинг 4.34. Группировка условий при помощи круглых скобок <br><br> booktown=# SELECT * FROM books <br> booktown-# WHERE author_id = 1866<br> booktown-# AND subject_id = 15 <br> booktown-# OR subject_id = 3; <br> id | title | autho_id | subject_id <br> 4513 | Dune | 1866 | 15 <br> 1234 | The Velveteen Rabbit | 25041 | 3 <br> (2 rows) <br> booktown=# SELECT * FROM books <br> booktown-# WHERE author_id = 1866 <br> booktown-# AND (subject_id = 15 <br> booktown-# OR subject_id = 3);<br> <br> id | title | author_id | subject_id <br> 4513 | Dune | 1866 | 15 <br> (1 row) <br> В этом примере продемонстрированы две попытки выборки из базы данных booktown записей, у которых поле author_id равно 1866. Кроме того, поле subject_id должно быть равно либо 15, либо 3. Как видно из результатов первой команды, при перечислении всех трех условий без круглых скобок команда интерпретируется неправильно. Добавление круглых скобок приводит к тому, что вычисления в скобках производятся до проверки внешних условий.<br> <br> <br><br> <h1>показывает как простое</h1> <br> <br>Листинг 4.34 показывает, как простое добавление круглых скобок влияет на результат выполнения команды. <br><br> <h1>Простой перекрестный запрос</h1> <br> <br>Листинг 4.35. Простой перекрестный запрос <br><br> booktown=# SELECT b.id, title, a.id, last_name <br> booktown-# FROM books AS b CROSS JOIN authors AS a <br> booktown-# WHERE b.author_id = a.id; <br> id | title | id | last_name <br> 190 | Little Women | 16 | Alcott <br> 156 | The Tell-Tale Heart | 115 | Рое <br> 41472 | Practical PostgreSQL | 1212 | Worsley <br> 2038 | Dynamic Anatomy | 1644 | Hogarth <br> 1608 | The Cat in the Hat | 1809 | Geisel <br> 1590 |Bartholomew and the Oobleck | 1809 | Geisel<br> 4513 | Dune | 1866 | Herbert <br> 4267 | 2001:Space Odyssey | 2001 | Clarke <br> 1501 | Goodnight Moon | 2031 | Brown <br> 7808 | The Shining | 4156 | King <br> 41473 | Programming Python | 7805 | Lutz <br> 41477 | Learning Python | 7805 | Lutz <br> 41478 | Perl Cookbook | 7806 | Christiansen <br> 25908 | Franklin in the Dark | 15990 | Bourgeois <br> 1234 | The Velveteen Rabbit | 25041 | Bianco <br> (15 rows) <br> Синтаксис CROSS JOIN всего лишь более формально выражает отношения между двумя наборами данных. Между синтаксисом CROSS JOIN и простым перечислением таблиц через запятую нет никаких функциональных различий. <br> <br><br> <h1>Сравнение команд INNER JOIN и WHERE</h1> <br> <br>Листинг 4.36. Сравнение команд INNER JOIN и WHERE <br><br> booktown=# SELECT title, last_name, first_name <br> booktown-# FROM books, authors <br> booktown-# WHERE (books.author_id = authors.id) <br> booktown-# AND last_name = 'Geisel': <br> title last_name | first_name <br> The Cat in the Hat | Geisel | Theodor Seuss <br> Bartholomew and the Oobleck | Geisel | Theodor Seuss <br> (2 rows) <br> booktown=# SELECT title, last_name, first_name <br> booktown-# FROM books AS b INNER JOIN authors AS a <br> booktown-# ON (b.author_id = a.id) <br> Dooktown-# WHERE last_name = 'Geisel'; <br> title | last_name | first_name <br> The Cat in the Hat | Geisel | Theodor Seuss <br> Bartholomew and the Oobleck | Geisel | Theodor Seuss<br> (2 rows) <br> Две синтаксические формы в листинге 4.36 функционально идентичны и возвращают одинаковые результаты. Синтаксис INNER JOIN позволяет отделить критерий связи источников от критерия выбора записей, поскольку связи определяются только в секции ON. Это существенно упрощает чтение и модификацию запросов, поскольку программисту не приходится разбираться в смысле каждого условия в секции WHERE. <br> Обратите внимание: во втором запросе продемонстрировано назначение синонимов а и b в секции ON для таблиц books и authors соответственно. Подобное использование синонимов в секции ON абсолютно законно, более того — часто оно предпочтительно, поскольку программа становится более наглядной. <br> В случае простых объединений по совпадающим значениям вместо ON иногда бывает удобнее использовать секции USING и NATURAL. Впрочем, они применимы лишь к наборам данным, содержащим одноименные поля. Если поля, по которым устанавливается связь между наборами, имеют разные имена, все равно остается возможность использования секций USING и NATURAL благодаря назначению синонимов полей (листинг 4.37). <br> <br><br> <h1>Секции NATURAL и USING</h1> <br> <br>Листинг 4.37. Секции NATURAL и USING <br><br> booktown=# SELECT title. last_name, first_name <br> booktown-# FROM books INNER JOIN authors AS a (author_id) <br> booktown-# USING (author_id) <br> booktown-# WHERE last_name = 'Geisel';<br> title | last_name | first_name <br> The Cat in the Hat | Geisel | Theodor Seuss<br> Bartholomew and the Oobleck | Geisel | Theodor Seuss <br> (2 rows) <br> booktown=# SELECT title, last_name, first_name <br> booktown-# FROM books NATURAL INNER JOIN authors AS a (author_id) <br> booktown-# WHERE lastjiame = 'Geisel';<br> title | last_name | first_name <br> The Cat in the Hat | Geisel | Theodor Seuss<br> Bartholomew and the Oobleck | Geisel | Theodor Seuss<br> (2 rows) <br> Первая команда SELECT в листинге4.37 назначает синоним authorjd первому полю таблицы authors (хотя в действительности это поле называется id). Идентификатор author_id передается в секцию USING, после чего PostgreSQL ищет в каждом наборе идентификатор поля с этим именем для объединения записей. <br> Внутренние объединения часто применяются на практике, но в некоторых ситуациях требуется выборка всех необходимых данных с использованием внешнего объединения. Чтобы попять суть различий между внутренними и внешними объединениями, достаточно разобраться, что происходит с записями, не входящими в установленную связь. <br> При внутреннем объединении все записи, для которых не находится соответствующего значения в других наборах (заданных при помощи ON или USING), просто игнорируются. <br> <br><br> <h1>Внутренние и внешние объединения</h1> <br> <br>Листинг 4.38. Внутренние и внешние объединения <br><br> booktown=# SELECT title, isbn <br> booktown-# FROM books INNER JOIN editions <br> booktown-# ON (books.id = editions.book_id);<br> <br> title | isbn <br> The Tell-Tale Heart | 1885418035 <br> The Tell-Tale Heart | 0929605942 <br> Little Women | 0760720002 <br> The Velveteen Rabbit | 0679803335 <br> Goodnight Moon | 0694003611 <br> Bartholomew and the Oobleck | 0394800753 <br> The Cat in the Hat | 039480001X <br> The Cat in the Hat | 0394900014 <br> Dynamic Anatomy | 0823015505 <br> 2001: A Space Odyssey | 0451457994 <br> 2001: A Space Odyssey | 0451198492 <br> Dune | 0441172717 <br> Dune | 044100590X <br> The Shining | 0451160916 <br> The Shining | 0385121679 <br> Franklin in the Dark | 0590445065 <br> Programming Python | 0596000855 <br> (17 rows) <br> booktown=# SELECT title, isbn <br> booktown-# FROM books LEFT OUTER JOIN editions <br> booktown-# ON (books.id = editions.book_id);<br> <br> title | bisbn <br> The Tell-Tale Heart | 1885418035 <br> The Tell-Tale Heart | 0929605942 <br> Little Women | 0760720002 <br> The Velveteen Rabbit | 0679803335 <br> Goodnight Moon | 0694003611 <br> Bartholomew and the Oobleck | 0394800753<br> The Cat in the Hat | 039480001X <br> The Cat in the Hat | 0394900014 <br> Dynamic Anatomy | 0823015505 <br> 2001: A Space Odyssey | 0451457994 <br> 2001: A Space Odyssey | 0451198492 <br> Dune | 0441172717 <br> Dune | 044100590X <br> The Shining | 0451160916 <br> The Shining | 0385121679 <br> Franklin in the Dark | 0590445065 <br> Practical PostgreSQL <br> Programming Python | 0596000855 <br> Learning Python Perl | Cookbook <br> (20 rows) <br> Во второй команде, приведенной в листинге 4.38, использовано левое внешнее объединение (LEFT OUTER JOIN). Выбор объясняется тем, что запрос должен вернуть названия книг, для которых существуют (или не существуют) коды ISBN. Поскольку таблица books стоит слева от ключевого слова JOIN, задача решается при помощи левого внешнего объединения. Если бы помимо названий, не имеющих кодов ISBN, нас интересовали коды ISBN, не имеющие названий, следовало бы воспользоваться полным внешним запросом FULL OUTER JOIN. <br> Различия между внутренними и внешними объединениями, продемонстрированные в листинге 4.38, чрезвычайно важны, поскольку неправильный выбор объединения приводит к получению лишней информации или потере нужных данных. <br> Примечание 1 <br>Примечание 1<br><br><br> Ключевое слово OUTER во внешних объединениях PostgreSQL является необязательным. Определения LEFT JOIN, RIGHT JOIN и FULL JOIN подразумевают внешнее объединение. <br> <br><br> <h1>Объединение нескольких источников данных</h1> <br> <br>Листинг 4.39. Объединение нескольких источников данных <br><br> booktown=# SELECT a.last_name, p.name AS publisher, e.isbn, s.subject<br> booktown-# FROM ((((authors AS a INNER JOIN books AS b</userinput> <br><br> booktown(# ON (a.id = b.author_id))</userinput> <br> <br> booktown(# INNER JOIN editions AS e ON (e.book_id = b.id))<br> booktown(# INNER JOIN publishers AS p ON (p.id = e.publisher_id))<br> booktown(# INNER JOIN subjects AS s ON (s.id = b.subjected));<br><br> 1ast_name | publisher | isbn | subject <br> Hogarth | Watson-Guptill Publications | 0823015505 | Arts <br> Brown | HarperCollins | 0694003611 | Children's Books <br> Geisel | Random House | 0394800753 | Children's Books <br> Geisel | Random House | 039480001X | Children's Books <br> Geisel | Random House | 0394900014 | Children's Books <br> Bourgeois | Kids Can Press | 0590445065 | Children's Books <br> Bianco | Penguin | 0679803335 | Classics <br> Lutz | O'Reilly & Associates | 0596000855 | Computers <br> Alcott | Henry Holt & Company. Inc. | 0760720002 | Drama <br> Рое | Mojo Press | 1885418035 | Horror <br> Рое | Books of Wonder | 0929605942 | Horror <br> King | Doubleday | 0451160916 | Horror <br> King | Doubleday | 0385121679 | Horror <br> Clarke | Roc | 0451457994 | Science Fiction <br> Clarke | Roc | 0451198492 | Science Fiction <br> Herbert | Ace Books | 0441172717 | Science Fiction <br> Herbert | Ace Books | 044100590X | Science Fiction <br> (17 rows) <br> В листинге 4.39 можно заметить одно любопытное обстоятельство: хотя таблица books участвует в объединении, ни одно из ее полей не входит в итоговый набор. Включение таблицы books в секции JOIN предоставляет критерии для объединения других таблиц. Все таблицы, поля которых возвращаются в результате запроса, связываются с другими таблицами через поле id таблицы books (кроме таблицы publishers, которая связывается с таблицей editions по полю publisher_id). <br> <br> <br><br> <h1>Включение открывающих</h1> <br> <br>Листинг 4.4. Включение открывающих символов в приглашение psql <br><br> testdb=# CREATE TABLE employees ( <br> testdb(# <br> Ввод команды продолжается. Открывающая круглая скобка в приглашении psql напоминает о том, что в команду необходимо включить закрывающую круглую скобку. <br> <br><br> <h1>Группировка записей</h1> <br> <br>Листинг 4.40. Группировка записей <br><br> booktown=# SELECT count(e.isbn) AS "number of books",<br> booktown-# p.name AS publisher <br> booktown-# FROM editions AS e INNER JOIN publishers AS p<br> booktown-# ON (e.publisher_id = p.id) <br> booktown-# GROUP BY p.name; <br> number of books | publisher<br> 2 | Ace Books <br> 1 | Books of Wonder <br> 2 | Doubleday <br> 1 | HarperCollins <br> 1 | Henry Holt & Company. Inc. <br> 1 | Kids Can Press <br> 1 | Mojo Press <br> 1 | O'Reilly & Associates <br> 1 | Penguin <br> 3 | Random House <br> 2 | Roc <br> 1 | Watson-Guptill Publications <br> (12 rows) <br> Секция GROUP BY в листинге 4.40 указывает PostgreSQL на то, что записи объединенного набора данных должны группироваться по имени р. name, которое в данном запросе является ссылкой на имя name таблицы publishers. Все записи с одинаковым названием издательства группируются, после чего функция count() подсчитывает в каждой группе количество значений isbn из таблицы editions и возвращает результат — количество записей, объединенных в каждую группу для одного издательства. <br> Учтите, что в листинге 4.40 аргумент (поле isbn таблицы editions) функции count () был выбран только для того, чтобы дать наглядное представление о смысле команды (подсчет количества книг для одного издателя). Его можно было заменить любым другим полем, поскольку функция count() всегда возвращает количество записей в текущей агрегатной группе. <br> При проектировании агрегатных запросов следует помнить, что секция WHERE не может содержать агрегатных функций, поэтому вместо нее следует использовать секцию HAVING. Секция HAVING работает аналогично секции WHERE, но ее условия должны быть основаны на агрегатных функциях, а не на условиях для отдельных записей. С точки зрения синтаксиса секция HAVING должна следовать за секцией GROUP BY (листинг 4.41). <br> <br><br> <h1>Использование секции HAVING</h1> <br> <br>Листинг 4.41. Использование секции HAVING <br><br> booktown=# SELECT count(e.isbn) AS "number of books",<br> booktown-# p.name AS publisher <br> booktown-# FROM editions AS e INNER JOIN publishers AS p<br> booktown-# ON (e.publisher_id - p.id) <br> booktown-# GROUP BY publisher <br> booktown-# HAVING count(e.isbn) > <br> 1; <br> number of books | publisher <br> 2 | Ace Books <br> 2 | Doubleday <br> 3 | Random House <br> 2 | Roc <br> (4 rows) <br> В листингах 4.40 и 4.41 набор данных создается внутренним объединением таблиц editions и publishers, однако листинг4.41 ограничивает результат теми издательствами, которые представлены в базе данных booktown двумя и более книгами. Задача решается при помощи секции HAVING. <br> Примечание 1 <br>Примечание 1<br><br><br> Если поле итогового набора связывается ключевым словом AS с синонимом, совпадающим с именем уществующего поля в одном из исходных наборов данных, то при использовании этого имени в секции GROUP BY PostgreSQL предполагает, что имя относится к исходному полю, а не к синониму. <br> <br><br> <h1>Использование секции ORDER BY</h1> <br> <br>Листинг 4.42. Использование секции ORDER BY <br><br> booktown=# SELECT isbn, edition, publication <br> booktown-# FROM editions <br> ooktown-# ORDER BY publication ASC; <br> Isbn | edition | publication <br> 0760720002 | 1 | 1868-01-01 <br> 0679803335 | 1 | 1922-01-01 <br> 0694003611 | 1 | 1947-03-04 <br> 0394800753 | 1 | 1949-03-01 <br> 0394900014 | 1 | 1957-01-01 <br> 039480001X | 1 | 1957-03-01 <br> 0823015505 | 1 | 1958-01-01 <br> 0451160916 | 1 | 1981-08-01 <br> 0590445065 | 1 | 1987-03-01 <br> 0385121679 | 2 | 1993-10-01 <br> 1885418035 | 1 | 1995-03-28 <br> 0441172717 | 2 | 1998-09-01 <br> 0929605942 | 2 | 1998-12-01 <br> 044100590X | 3 | 1999-10-01 <br> 0451198492 | 3 | 1999-10-01 <br> 0451457994 | 3 | 2000-09-12 <br> 0596000855 | 2 | 2001-03-01 <br> (17 rows) <br> <br><br> <h1>показывает что записи</h1> <br> <br>Листинг 4.42 показывает, что записи возвращаются в порядке возрастания, от старых дат к новым. Следует помнить, что при сортировке и выборке допускается использование полей, отсутствующих в целевом списке команды SELECT. Более того, если запрос связан с агрегированием, секция ORDER BY может содержать вызовы агрегатных функций и выражения. Возможность сортировки по разнообразным источникам обеспечивает значительную гибкость при упорядочении результатов. <br><br> ВНИМАНИЕ <br> Если синоним поля итогового набора совпадает с именем существующего поля в исходном наборе данных, из которого производится выборка, то при использовании этого имени в секции ORDER BY PostgreSQL предполагает, что имя относится к итоговому набору, а не к полю источника. Такое поведение противоречит стандартному поведению секции GROUP BY, соответствующему стандарту SQL92. <br> При сортировке по нескольким выражениям PostgreSQL сначала упорядочивает итоговый набор по первому (левому) критерию и продолжает применять дальнейшие критерии лишь в том случае, если сортировка по первому критерию не обеспечивает однозначного результата. Пример приведен в листинге 4.43. <br> <br><br> <h1>Секция ORDER BY с несколькими выражениями</h1> <br> <br>Листинг 4.43. Секция ORDER BY с несколькими выражениями <br><br> booktown=# SELECT edition, publication <br> booktown-# FROM editions <br> booktown-# ORDER BY edition ASC,<br> booktown-# publication DESC;<br> edition | publication <br> 1 | 1995-03-28 <br> 1 | 1987-03-01 <br> 1 | 1981-08-01 <br> 1 | 1958-01-01 <br> 1 | 1957-03-01 <br> 1 | 1957-01-01 <br> 1 | 1949-03-01 <br> 1 | 1947-03-04 <br> 1 | 1922-01-01 <br> 1 |1868-01-01 <br> 2 | 2001-03-01 <br> 2 | 1998-12-01 <br> 2 | 1998-09-01 <br> 2 | 1993-10-01 <br> 3 | 2000-09-12 <br> 3 | 1999-10-01 <br> 3 | 1999-10-01 <br> (17 rows) <br> Запрос выбирает поля edition и publication всех записей таблицы editions. Затем секция ORDER BY определяет два поля, по которым должна осуществляться сортировка результата: edition (по возрастанию) и publication (по убыванию). <br> Как видно из результатов в листинге 4.43, сначала записи сортируются по номеру издания, а при совпадении номеров дальнейшая сортировка осуществляется по дате публикации — от новых к старым. <br> Сортировка играет важную роль при использовании ключевого слова DISTINCT, упоминавшегося в подразделе «Удаление дубликатов и ключевое слово DISTINCT». Если вы хотите ограничиться просмотром последнего издания для каждого значения поля edition таблицы editions, комбинация ORDER BY и DISTINCT позволит добиться эффекта, аналогичного применению секции GROUP BY (листинг 4.44). <br> <br><br> <h1>Использование секции DISTINCT с ORDER BY</h1> <br> <br>Листинг 4.44. Использование секции DISTINCT с ORDER BY <br><br> booktown=# SELECT DISTINCT ON (edition) <br> booktown-# edition, publication <br> booktown-# FROM editions <br> booktown-# ORDER BY edition ASC,<br> booktown-# publication DESC;<br> edition | publication <br> 1 | 1995-03-28 <br> 2 | 2001-03-01 <br> 3 | 2000-09-12 <br> (3 rows) <br> booktown=# SELECT edition, max(publication) <br> booktown-# FROM editions <br> booktown-# GROUP BY edition;<br> edition | max <br> 1 | 1995-03-28 <br> 2 | 2001-03-01 <br> 3 | 2000-09-12 <br> (3 rows) <br> Поскольку секция ORDER BY обрабатывается перед удалением дубликатов ключевым словом DISTINCT, общий эффект очень похож на вызов агрегатной функции max() или min() в секции GROUP BY. Подобная методика бывает чрезвычайно эффективной, хотя все зависит от сложности агрегирования и сортировки. <br> Примечание 1 <br>Примечание 1<br><br><br> Вместо имен полей или выражений секция ORDER BY может содержать целочисленные константы. Такие константы интерпретируются как номера позиций в целевом списке; отсчет ведется слева направо, начиная с 1. Таким образом, ORDER BY 1 ASC означает сортировку по первому полю итогового набора. <br> <br><br> <h1>Использование секций LIMIT и OFFSET</h1> <br> <br>Листинг 4.45. Использование секций LIMIT и OFFSET <br><br> booktown=# SELECT isbn, title, publication <br> booktown-# FROM editions NATURAL JOIN books AS b (book_id) <br> booktown-# ORDER BY publication DESC <br> booktown-# LIMIT 5;<br> isbn | title | publication <br> 0596000855 | Programming Python | 2001-03-01 <br> 0451457994 | 2001: A Space Odyssey | 2000-09-12 <br> 0451198492 | 2001: A Space Odyssey | 1999-10-01 <br> 044100590X | Dune | 1999-10-01 <br> 0929605942 | The Tell-Tale Heart | 1998-12-01 <br> (5 rows) <br> booktown=# SELECT isbn, title, publication <br> booktown-# FROM editions NATURAL JOIN books AS b (book_id) <br> booktown-# ORDER BY publication DESC <br> booktown-# LIMIT 5 <br> booktown-# OFFSET 2; <br> isbn | title | publication <br> 0451198492 | 2001: A Space Odyssey | 1999-10-01 <br> 044100590X | Dune | 1999-10-01 <br> 0929605942 | The Tell-Tale Heart | 1998-12-01 <br> 0441172717 | Dune | 1998-09-01 <br> 1885418035 | The Tell-Tale Heart | 1995-03-28 <br> (5 rows) <br> Второй запрос в листинге 4.45 содержит секцию OFFSET, вследствие чего начало отсчета смещается на две записи вниз. Последние три записи в итоговом наборе первого запроса совпадают с первыми тремя записями итогового набора второго запроса. Секция ORDER BY обеспечивает единый порядок следования записей в итоговых наборах обоих запросов. <br> <br><br> <h1>Использование секции UNION</h1> <br> <br>Листинг 4.46. Использование секции UNION <br><br> booktown=# SELECT title FROM books <br> booktown-# UNION <br> booktown-# SELECT last_name FROM authors<br> booktown-# LIMIT 11; <br> title <br> 2001: A Space Odyssey Alcott <br> Bartholomew and the Oobleck <br> Bianco <br> Bourgeois <br> Brautigan <br> Brite <br> Brown <br> Christiansen Clarke Denham <br> (11 rows) <br> <br><br> <h1>Использование секции INTERSECT</h1> <br> <br>Листинг 4.47. Использование секции INTERSECT <br><br> booktown=# SELECT isbn FROM editions <br> booktown-# INTERSECT <br> booktown-# SELECT isbn FROM shipments <br> booktown-# GROUP BY isbn <br> booktown-# HAVING count(id) > <br> 2; <br> isbn <br> 039480001X <br> 0394800753 <br> 0451160916 <br> 0590445065 <br> 0694003611 <br> (5 rows) <br> <br><br> <h1>Использование секции EXCEPT</h1> <br> <br>Листинг 4.48. Использование секции EXCEPT <br><br> booktown=# SELECT last_name, first_name <br> booktown-# FROM authors <br> booktown-# EXCEPT <br> booktown-# SELECT lastjiame, first_name <br> booktown-# FROM authors AS a (author_id) <br> booktown-# NATURAL INNER JOIN books <br> booktown-# ORDER BY first_name ASC; <br> last_name | first_name <br> Denham | Ariel <br> Gorey | Edward <br> Brite | Poppy Z. <br> Brautigan | Richard <br> (4 rows) <br> Команда из листинга 4.48 возвращает только те записи, которые не входят во второй запрос. Фактически это приводит к тому, что итоговый набор состоит из записей об авторах, у которых нет ни одной книги в таблице books. Это связано с присутствием секции INNER JOIN, исключающей из второго запроса всех авторов, коды которых (author_id) отсутствуют в таблице books. <br> Хотя присутствие этих ключевых слов в запросе SQL не позволяет использовать в нем секцию LIMIT, этот запрет легко обходится благодаря поддержке подзапросов в PostgreSQL. Для этого достаточно заключить в круглые скобки каждый из запросов, участвующих в операции UNION, INTERSECT или EXCEPT, и сравнить итоговые наборы подзапросов, как показано в листинге 4.49. <br> <br><br> <h1>Сравнение результатов двух подзапросов</h1> <br> <br>Листинг 4.49. Сравнение результатов двух подзапросов <br><br> booktown=# (SELECT title FROM books ORDER BY title DESC LIMIT 7) <br> booktown-# EXCEPT <br> booktown-# (SELECT title FROM books ORDER BY title ASC LIMIT 11) <br> booktown-# ORDER BY title DESC; <br> title <br> The Velveteen Rabbit <br> The Tell-Tale Heart <br> The Shining <br> The Cat in the Hat <br> (4 rows) <br> Запрос, использованный в листинге 4.49, создает по данным таблицы books набор, отсортированный по названию в алфавитном порядке, и выбирает из него семь последних записей. Затем при помощи ключевого слова EXCEPT из набора исключаются начальные 11 записей при сортировке в алфавитном порядке по возрастаиию. Результат состоит из четырех последних записей таблицы books, отсортированных в обратном алфавитном порядке завершающей секцией ORDER BY. <br> <br><br> <h1>Присваивание значения переменной EDITOR</h1> <br> <br>Листинг 4.5. Присваивание значения переменной EDITOR <br><br> # set EDITOR='joe' <br> $ export EDITOR <br> Команда \е также может применяться для сохранения текущего содержимого буфера в файле. При вводе команды \е клиент psql запускает редактор и загружает содержимое буфера запроса, словно оно было прочитано из файла. Выполните все необходимые операции, сохраните результат в файле командой Save и вернитесь в psql. Команда \е создает временный файл с расширением .tmp; чтобы сохранить запрос в обычном файле, воспользуйтесь командой Save As и введите имя файла.<br> <br> <br><br> <h1>Конструкции CASE в командах</h1> <br> <br>Листинг 4.50. Конструкции CASE в командах <br><br> booktown=# SELECT isbn,<br> booktown-# CASE WHEN cost > <br> 20 THEN 'over $20.00 cost' <br> booktown-# WHEN cost = 20 THEN '$20.00 cost1 <br> booktown-# ELSE 'under $20.00 cost' <br> booktown-# END AS cost_range <br> booktown-# FROM stock <br> booktown-# LIMIT 8; <br> Isbn | cost_range <br> 0385121679 | over $20.00 cost <br> 039480001X | over $20.00 cost <br> 044100590X | over $20.00 cost <br> 0451198492 | over $20.00 cost <br> 0394900014 | over $20.00 cost <br> 0441172717 | under $20.00 cost <br> 0451160916 | over $20.00 cost <br> 0679803335 | $20.00 cost <br> (8 rows) <br> Подзапросы PostgreSQL расширяют возможности конструкций CASE (см. раздел «Подзапросы»). Как показано в листинге 4.51, в качестве результата условного выражения в конструкции может быть задан подзапрос. <br> <br><br> <h1>Конструкции CASE в подзапросах</h1> <br> <br>Листинг 4.51. Конструкции CASE в подзапросах <br><br> booktown=# SELECT isbn, <br> booktown-# CASE WHEN cost > <br> 20 THEN 'N/A - (Out of price range)' <br> booktown-# ELSE (SELECT title FROM books b JOIN editions e <br> booktown(# ON (b.id = e.book_id) <br> booktown(# WHERE e.isbn = stock.isbn) <br> booktown-# END AS cost_range <br> booktown-# FROM stock <br> booktown-# ORDER BY cost_range ASC <br> booktown-# LIMIT 8;<br> isbn | cost_range <br> 0451457994 | 2001: A Space Odyssey <br> 0394800753 | Bartholomew and the Oobleck <br> 0441172717 | Dune <br> 0760720002 | Little Women <br> 0385121679 | N/A - (Out of price range) <br> 039480001X | N/A - (Out of price range) <br> 044100590X | N/A - (Out of price range) <br> 0451198492 | N/A - (Out of price range) <br> (8 rows) <br> Для всех книг, цена которых не превышает 20, запрос возвращает название книги (подзапрос к таблице books) и код ISBN (основной запрос к таблице stock). <br> <br><br> <h1>Создание таблицы</h1> <br> <br>Листинг 4.52. Создание таблицы на основе данных другой таблицы <br><br> booktown=# SELECT * INTO <br> stock_backup booktown=# FROM stock; <br> SELECT <br> Таблица, указанная в секции INTO, не должна существовать, иначе происходит ошибка. В этом случает данные не сохраняются, а запрос завершается неудачей. Следует помнить, что ключевое слово TABLE является необязательным. <br> <br><br> <h1>Простая команда UPDATE</h1> <br> <br>Листинг 4.53. Простая команда UPDATE <br><br> booktown=# SELECT retail FROM stock <br> booktown-# WHERE isbn = '0590445065'; <br> retail <br> 23.95 <br> (1 row) <br> booktown=# UPDATE stock <br> booktown-# SET retail = 25.95 <br> booktown-# WHERE isbn = '0590445065'; <br> UPDATE 1 <br> booktown=# SELECT retail FROM stock <br> booktown-# WHERE isbn = '0590445065';<br> retail <br> 25.95<br> (1 row) <br> Итоговое сообщение UPDATE 1 в листинге 4.53 означает, что одна запись была успешно обновлена. Даже если новое значение поля совпадает со старым, операция все равно считается обновлением, а файлы базы данных на диске модифицируются. <br> <br><br> <h1>Обновление поля во всех записях</h1> <br> <br>Листинг 4.54. Обновление поля во всех записях <br><br> booktown=# SELECT isbn, retail, cost <br> booktown-# FROM stock <br> booktown-# ORDER BY isbn ASC <br> booktown-# LIMIT 3; <br> isbn | retail | cost <br> 0385121679 | 36.95 | 29.00 <br> 039480001X | 32.95 | 30.00 <br> 0394800753 | 16.95 | 16.00 <br> (3 rows) <br> booktown=# UPDATE stock <br> booktown-# SET retail = <br> booktown-# (cost * ((retail / cost) + 0.1::numeric));<br> <br> UPDATE 16 <br> booktown=# SELECT isbn, retail, cost <br> booktown-# FROM stock <br> booktown-# ORDER BY isbn ASC <br> booktown-# LIMIT 3; <br> isbn | retail | cost <br> 0385121679 | 39.85 | 29.00 <br> 039480001X | 35.95 | 30.00 <br> 0394800753 | 18.55 | 16.00 <br> (3 rows) <br> Команда UPDATE, приведенная в листинге 4.54, не содержит секции WHERE, поэтому обновляются все записи таблицы stock. <br> <br><br> <h1>также служит примером</h1> <br> <br>Листинг 4.55 также служит примером практического использования оператора конкатенации || и функции substr(). Полю address присваиваются две строковые константы, объединенные оператором || для предотвращения выхода за пределы командной строки терминала. Затем функция substr() усекает выводимый адрес, чтобы он не переносился на другую строку. В данном случае это сделано лишь для удобства чтения выходных данных. Конечно, если вас интересует полное содержимое поля, усекать его не следует. <br><br> <h1>Выполнение команды</h1> <br> <br>Листинг 4.55. Выполнение команды UPDATE с обновлением нескольких полей <br><br> booktown=# UPDATE publishers <br> booktown-# SET name = 'OVReilly & Associates', <br> booktown-# address = 'OVReilly & Associates. Inc. ' <br> booktown-# || '101 Morris St, Sebastopol, CA 95472' <br> booktown-# WHERE id = 113; <br> UPDATE 1 <br> booktown=# SELECT name, substrtaddress, 1, 40) || '...' AS short_address <br> booktown-# FROM publishers <br> booktown-# WHERE id = 113; <br> name | short_address <br> O'Reilly & Associates | O'Reilly & Associates. Inc. 101 Morris S... <br> (1 row) <br> В этой команде UPDATE значения обоих полей, name и address, заданы в виде строковых констант. Обратите внимание: внутренние апострофы в строках экранируются обратной косой чертой. Команда SELECT позволяет убедиться в правильности выполненного обновления. <br> <br><br> <h1>Команда UPDATE с несколькими источниками</h1> <br> <br>Листинг 4.56. Команда UPDATE с несколькими источниками <br><br> booktown=# UPDATE stock . <br> booktown-# SET retail = stock_backup.retail <br> booktown-# FROM stock_backup <br> booktown-# WHERE stock.isbn = stock_backup.isbn; <br> UPDATE 16 <br> Секция FROM поддерживает все разновидности синтаксиса JOIN, описанные в разделе «Выборка данных командой SELECT», что открывает широкие возможности обновления данных в существующих наборах. Более того, как упоминалось выше, в качестве источника данных в секциях FROM могут использоваться подзапросы. <br> <br><br> <h1>Удаление записей из таблицы</h1> <br> <br>Листинг 4.57. Удаление записей из таблицы <br><br> booktown=# SELECT * FROM stock <br> booktown-# WHERE stock = 0; <br> isbn | cost | retail | stock <br> 0394800753 | 16.00 | 16.95 | 0 <br> 0394900014 | 23.00 | 23.95 | 0 <br> 0451198492 | 36.00 | 46.95 | 0 <br> 0451457994 | 17.00 | 22,95 | 0 <br> (4 rows) <br> booktown=# DELETE FROM stock <br> booktown-# WHERE stock = 0; <br> DELETE 4 <br> При отсутствии секции WHERE команда DELETE удаляет из таблицы все записи (листинг 4.58). <br> <br><br> <h1>Удаление всех записей из таблицы</h1> <br> <br>Листинг 4.58. Удаление всех записей из таблицы <br><br> booktown=# DELETE FROM stock_backup; <br> DELETE 16 <br> <br><br> <h1>Простой подзапрос</h1> <br> <br>Листинг 4.59. Простой подзапрос <br><br> booktown=# SELECT title FROM books <br> 30oktown-# WHERE author_id = (SELECT id FROM authors)<br> booktown(# WHERE last_name='Geisel' <br> booktown(# AND first_name='Theodor Seuss');<br> <br> title <br> The Cat in the Hat <br> Bartholomew and the Oobleck <br> (2 rows) <br> Оператор = сравнивает поле id подзапроса к таблице authors с полем author_id габлицы books. Подзапрос находит в таблице authors запись об авторе с именем c<Theodor Seuss» и фамилией «Geisel»; сравнивая поле id этой записи с полем Author_id таблицы books, мы отбираем все книги, написанные этим автором. <br> Построение подзапросов требует осторожности: чтобы результат запроса проверялся простым оператором, подзапрос должен возвращать только одну запись. Например, если использовать для выборки кода автора более общий запрос, возвращающий несколько записей, PostgreSQL выдаст сообщение об ошибке: <br> booktown=# SELECT title FROM books <br> booktown-# WHERE authoMd = (SELECT id FROM authors <br> booktown(# WHERE last_name ` 'G');<br> <br> ERROR: More than one tuple returned by a subselect used as an expression. <br> Обычные операторы не могут сравнивать отдельную величину с несколькими шачениями, поэтому сравнение поля authoMd с несколькими полями приводит к ошибке. Проблема легко решается включением в подзапрос секции LIMIT 1, благодаря которой подзапрос никогда не вернет более одной записи. <br> Если требуется проверить присутствие отдельной величины в заданном наборе, замените оператор = ключевым словом IN. Подзапрос, приведенный в листинге 4.60, выбирает несколько значений, сравниваемых с полем author_id (для авторов, имена которых начинаются с букв А-Е). Сравнение осуществляется при юмощи ключевого слова IN. Средства поиска по регулярному выражению рассматриваются в разделе «Операторы» главы 5. <br> <br><br> <h1>Создание таблицы books</h1> <br> <br>Листинг 4.6. Создание таблицы books <br><br> booktown=# CREATE TABLE books ( <br> booktown(# id integer UNIQUE. <br> booktown(# title text NOT NULL, <br> booktown(# authoMd integer, <br> booktowntf subjected integer, <br> booktown(# CONSTRAINT books_id_pkey PRIMARY KEY (id));<br> <br> NOTICE: CREATE TABLE/PRIMARY KEY <br> will create implicit index 'books_id_pkey' for table <br> 'books' <br> CREATE <br> После выполнения команды CREATE выводится сообщение с информацией об успешном создании таблицы. Если вы получите сообщение об ошибке, проверьте правильность расстановки знаков препинания и написания всех ключевых слов. Если сообщения вообще нет, вероятно, в команде осталась незакрытая круглая скобка, апостроф или другой парный символ. <br> Кроме того, в сообщении NOTICE говорится о том, что при создании описанной таблицы был построен скрытый индекс books_id_pkey. <br> <br><br> <h1>Подзапрос с ключевым словом IN</h1> <br> <br>Листинг 4.60. Подзапрос с ключевым словом IN <br><br> booktown=# SELECT title FROM books <br> booktown-# WHERE authorjd IN (SELECT id FROM authors <br> booktown(# WHERE last_name - '"[A-E]');<br> <br> title <br> 2001: A Space Odyssey <br> Franklin in the Dark <br> Goodnight Moon <br> Little Women <br> The Velveteen Rabbit <br> Perl Cookbook <br> (6 rows) <br> Благодаря ключевому слову IN запрос находит в таблице данные о книгах нескольких авторов, коды которых были выбраны подзапросом. Хотя ключевое сло-ю IN позволяет проверить значение по нескольким записям, количество сравниваемых полей должно быть одинаковым. <br> Если вы хотите, чтобы секция IN сравнивала несколько полей, сгруппируйте их имена в круглых скобках в секции WHERE непосредственно перед IN. Сгруппированные поля должны соответствовать полям целевого списка как по количеству, так и по типу. <br> В листинге4.61 приведен подзапрос к таблице editions, который группирует поле i sbn с целочисленной константой 0 для всех книг в бумажной обложке (type=' р'). Возвращаемые подзапросом записи сравниваются с полем isbn и полем stock таблицы stock с использованием ключевого слова IN. В результате команда SELECT выбирает данные обо всех книгах в бумажной обложке, отсутствующих на складе. <br> <br><br> <h1>Многоцелевой подзапрос в секции IN</h1> <br> <br>Листинг 4.61. Многоцелевой подзапрос в секции IN <br><br> booktown=# SELECT isbn, cost, retail FROM stock <br> booktown-# WHERE (isbn, stock) <br> booktown-# IN (SELECT isbn, 0 FROM editions <br> booktown(# WHERE type = 'p');<br> <br> isbn | cost | retail <br> 0394800753 | 16.00 | 16.95 <br> 0394900014 | 23.00 | 23.95 <br> 0451457994 | 17.00 | 22.95 <br> (3 rows) <br> <br><br> <h1>Создание представления</h1> <br> <br>Листинг 4.62. Создание представления <br><br> booktown=# CREATE VIEW recent_shipments <br> booktown-# AS SELECT count(*) AS num_shipped, max(ship_date), title <br> booktown-# FROM shipments <br> booktown-# JOIN editions USING (isbn) <br> booktown-# NATURAL JOIN books AS b (book_id) <br> booktown-# GROUP BY b.title <br> booktown-# ORDER BY num_shipped DESC; <br> CREATE <br> Ответ сервера CREATE подтверждает, что представление было успешно создано. В результате в базе данных booktown создается представление recent_shipments с информацией обо всех поставках книг, о количестве заказанных экземпляров и дате последней поставки по каждой позиции. <br> <br><br> <h1>демонстрирует еще</h1> <br> <br>Листинг 4.63 демонстрирует еще одно важное обстоятельство: хотя при создании представления используется секция ORDER BY, итоговый набор можно заново отсортировать при выводе. Для этого в команду SELECT, осуществляющую выборку из представления, включается другая секция ORDER BY. <br><br> Примечание 1 <br>Примечание 1<br><br><br> При попытке вызова команд DELETE или UPDATE для представления происходит ошибка, поскольку представление не содержит собственных данных. Несмотря на внешнее сходство с таблицами, представления всего лишь обеспечивают механизм обращения к другому набору данных, поэтому их модификация невозможна. <br> <br><br> <h1>Использование представления</h1> <br> <br>Листинг 4.63. Использование представления <br><br> booktown=# SELECT * FROM recent_shipments; <br> num_shipped | max | title <br> 5 | 2001-08-13 09:47:04-07 | The Cat in the Hat <br> 5 | 2001-08-14 13:45:51-07 | The Shining <br> 4 | 2001-08-11 09:55:05-07 | Bartholomew and the Oobleck <br> 3 | 2001-08-14 13:49:00-07 | Franklin in the Dark <br> 3 | 2001-08-15 11:57:40-07 | Goodnight Moon <br> 3 | 2001-08-14 13:41:39-07 | The Tell-Tale Heart <br> 2 | 2001-08-15 14:02:01-07 | 2001: A Space Odyssey <br> 2 | 2001-08-14 08:42:58-07 | Dune <br> 2 | 2001-08-07 13:00:48-07 | Little Women <br> 2 | 2001-08-09 09:30:46-07 | The Velveteen Rabbit <br> 1 | 2001-08-14 07:33:47-07 | Dynamic Anatomy <br> (11 rows) <br> booktown=# SELECT * FROM recent_shipments<br> booktown-# ORDER BY max DESC <br> booktown-# LIMIT 3; <br> num_shipped | max | title <br> 2 | 2001-08-15 14:02:01-07 | 2001: A Space Odyssey <br> 3 | 2001-08-15 11:57:40-07 | Goodnight Moon <br> 3 | 2001-08-14 13:49:00-07 | Franklin in the Dark <br> (3 rows) <br> <br><br> <h1>Выходные данные команды \d</h1> <br> <br>Листинг 4.7. Выходные данные команды \d <br><br> booktown=# \d books <br> Table "books" Attribute | Type | Modifier<br> id integer | not null <br> title text I not null <br> authorjd j integer j subjectjd | integer | <br> Index: books_id_pkey <br> Ниже приведены более подробные описания полей и атрибутов, встречающихся в листинге 4.7. <br> <ul> <li> Id. В поле Id хранится числовой код, уникальный для каждой книги. Поле id определяется с типом Integer и для него устанавливаются следующие ограничения:</li></ul> <ul> <li> UNIQUE. Ограничение гарантирует уникальность значений поля. В общем случае поле с ограничением уникальности может содержать NULL, но попытки вставки дубликатов завершаются неудачей. Поле Id также используется в качестве первичного ключа. </li> <li> PRIMARY KEY. Хотя в выходных данных команды \d об этом не упоминается, из исходной команды CREATE TABLE видно, что поле id также назначено первичным ключом таблицы. Установка ограничения первичного ключа для поля также неявно подразумевает установку ограничений NOT NULL и UNIQUE. </li> <li> NOT NULL. Автоматически устанавливается при назначении ограничения PRIMARY KEY. Ограничение гарантирует, что поле id всегда содержит значение, отличное от NULL. Поле никогда не остается пустым, и любые попытки вставки псевдозначения NULL завершаются неудачей. </li> </ul> <li> title. Поле title содержит символьные данные типа text. Тип text обладает большей гибкостью по сравнению с varchar и хорошо подходит для данного поля, поскольку не требует задания максимального количества символов. Для поля titl e установлено ограничение NOT NULL; это означает, что поле всегда содержит значение, отличное от NULL. </li> <li> authorjd. Поле author_id содержит значения типа integer и используется для связи с таблицей authors. Ограничения для этого поля не устанавливаются, поскольку в таблице могут встречаться книги, написанные неизвестным автором, что исключает ограничение NOT NULL. С другой стороны, один автор может написать несколько книг, поэтому ограничение UNIQUE также не подходит. </li> <li> subject_id. Поле subject_id аналогично полю author_id— оно тоже содержит значения типа integer и используется для установки связи с таблицей subjects. Ограничения для этого поля также отсутствуют, поскольку некоторые книги не принадлежат ни к одной категории, а категории, как правило, содержат более одной книги. </li> Структура таблицы может изменяться после ее создания, но возможности мо-(ификаций ограничены. Например, к их числу относится переименование табли-(ы, переименование существующих и добавление новых полей. PostgreSQL 7.1.x ie позволяет удалять поля из таблиц, поэтому структуру таблицы следует тща-•ельно продумать перед ее созданием. <br> <br><br> <h1>Добавление поля</h1> <br> <br>Листинг 4.8. Добавление поля <br><br> booktown=# ALTER TABLE books <br> booktown-# ADD publication date; <br> ALTER <br> booktown=# \d books <br> Table "books" <br> Attribute | Type | Modifier <br> id integer | not null <br> title text I not null <br> authorjd j integer | <br> subjectjd integer | <br> publication date j Index: books_id_pkey <br> <br><br> <h1>показывает что в таблице</h1> <br> <br>Листинг 4.8 показывает, что в таблице books появилось новое поле с именем pub! I cation и типом date. Кроме того, он дает типичный пример плохой координации планирования между разработчиками: в базе данных booktown из нашего примера дата публикации уже хранится в таблице editions, поэтому включать его в таблицу books не нужно. Изменение структуры таблиц после подобных ошибок рассматривается ниже в подразделе «Реструктуризация таблиц». <br><br> <h1>Изменение значений по умолчанию</h1> <br> <br>Листинг 4.9. Изменение значений по умолчанию <br><br> Doktown=# ALTER TABLE books <br> 3oktOwn-# ALTER COLUMN id <br> x> <br>ktown-# SET DEFAULT nextvalС books.ids'): <br> JER <br> }oktown=# \d books <br> TABLE "books" Attribute | Type | Modifier <br> id integer not null default nextval('books.ids'::text) <br> 1tle | text not null <br> juthorjd | integer ;ubject_id | integer j idex: books_id_pkey <br> )oktown=# ALTER TABLE books )oktown-# ALTER id <br> )oktown-# DROP DEFAULT; <br> JER <br> joktown=# \d books <br> TABLE "books" Attribute | Type | Modifier <br> id | integer | not null <br> ;itle | text not null <br> iuthor_id j integer ;ubject_id j integer idex: books_id_pkey <br> <br><br> <h1>Модификация таблицы командой ALTER TABLE</h1> <br> <br> Модификация таблицы командой ALTER TABLE <br><br> В большинстве современных РСУБД предусмотрена возможность модификации таблиц командой ALTER TABLE. Реализация ALTER TABLE в PostgreSQL 7.1.x поддер-кивает шесть типов модификации: <br> <ul> <li> создание полей; </li> <li> назначение и отмена значений по умолчанию; </li> <li>переименование таблицы; </li> <li> переименование полей; </li> <li> дооавление ограничении; </li> <li> смена владельца. </li> </ul> <br><br> <h1>Модификация записей командой UPDATE</h1> <br> <br>Модификация записей командой UPDATE <br><br> После того как записи сохранены в базе данных, вы можете обновить их поля командой SQL UPDATE. Новые значения полей задаются в виде констант, идентификаторов других баз данных или выражений. Допускается обновление как поля в целом, так и подмножества его значений в соответствии с заданными условиями. Синтаксис команды UPDATE: <br> UPDATE [ ONLY ] таблица SET <br> поле = выражение [. ...] [ FROM источник ] [ WHERE условие ] <br> <ul> <li> UPDATE [ ONLY ] таблица. Ключевое слово ONLY означает, что обновляется только заданная таблица, но не ее производные таблицы. Применяется лишь в том случае, если таблица использовалась в качестве базовой при наследовании. </li> <li> SET поле = выражение [. ...]. Обязательная секция SET содержит перечисленные через запятую условия, определяющие новые значения обновляемых полей. Условия всегда имеют форму поле = выражение, где поле — имя обновляемого поля (не допускаются ни синонимы, ни точечная запись), а выражение описывает новое значение поля. </li> <li> FROM источник. Секция FROM принадлежит к числу нестандартных расширений PostgreSQL и позволяет обновлять поля значениями, взятыми из других наборов. </li> <li> WHERE условие. В секции WHERE задается критерий, по которому в таблице выбираются обновляемые записи. Если секция WHERE отсутствует, поле обновляется во всех записях. По аналогии с командой SELECT может использоваться для уточнения выборки из источников, перечисленных в секции FROM. </li> </ul> В листинге 4.53 приведен пример простой команды UPDATE. Команда заполняет поле retail таблицы stock вещественной константой 29.95. Секция WHERE ограничивает обновление записями, соответствующими заданному критерию. <br> <br><br> <h1>Назначение и отмена значений по умолчанию</h1> <br> <br> Назначение и отмена значений по умолчанию <br><br> При модификации существующих таблиц наибольшая свобода действий предоставляется при выборе значений по умолчанию. Программист может относительно легко назначать и отменять эти значения для отдельных полей, для чего используется команда ADD TABLE с секцией ALTER COLUMN. <br> В PostgreSQL команда ALTER TABLE, назначающая или отменяющая значение по умолчанию для поля имя_поля, имеет следующий синтаксис: <br> ALTER TABLE таблица <br> ALTER [ COLUMN ] имя_поля <br> ( SET DEFAULT значение ] DROP DEFAULT } <br> Как и в предыдущем разделе, ключевое слово COLUMN является необязательным включается в команду лишь для наглядности. В листинге 4.9 приведен пример азначения и отмены простой последовательности значений по умолчанию для оля id таблицы books. <br> <br><br> <h1>Объединение наборов данных</h1> <br> <br>Объединение наборов данных <br><br> Как было показано в примере использования секции WHERE для выборки из двух таблиц (см. подраздел «Выбор источников в секции FROM»), существует возможность выборки данных из разных источников с объединением их полей. В SQL этот процесс формально называется объединением (join). <br> В результате объединения двух или более наборов данных создается новый набор записей, состоящих из всех полей исходных наборов. Базовый вариант объединения представляет собой декартово произведение, то есть совокупность всех возможных комбинаций двух наборов. Далее из этого произведения отбирается часть записей по критериям, заданным в секции JOIN. <br> Существуют три разновидности объединений. <br> <ul> <li> Перекрестные объединения (CROSS JOIN). Декартово (перекрестное) произведение двух наборов данных. Произведение не определяет отношений между наборами, а лишь содержит все возможные комбинации записей объединяемых наборов. </li> <li> Внутренние объединения (INNER JOIN). Подмножество декартова произведения двух наборов данных с критерием, используемым для объединения записей. Критерий возвращает логическую величину — признак вхождения записи в объединенный набор. </li> <li> Внешние объединения (OUTER JOIN). Как и внутренние объединения, содержат критерий объединения записей, но обязательно возвращают минимум один экземпляр каждой записи заданного набора. Это может быть левый набор (источник данных слева от ключевого слова JOIN), правый набор (источник данных справа от ключевого слова JOIN) или оба набора в зависимости от конкретной разновидности внешнего объединения. Пустые поля в тех частях записей, которые не отвечают критерию объединения, содержат NULL. </li> </ul> <br><br> <h1>Обновление нескольких полей</h1> <br> <br> Обновление нескольких полей <br><br> Перечисление команд присваивания в секции SET через запятую позволяет обновить несколько полей таблицы в одной команде. В листинге 4.55 продемонстрировано одновременное изменение полей name и address таблицы publ i shers для записи с полем id, равным ИЗ. <br> <br><br> <h1>Обновление поля во всех записях таблицы</h1> <br> <br> Обновление поля во всех записях таблицы <br><br> При отсутствии секции WHERE команда UPDATE обновляет заданное поле во всех записях таблицы. Обычно в этой ситуации новое значение поля задается выражением, а не константой. Выражение, указанное в секции SET, вычисляется заново для каждой записи, а новое значение поля определяется динамически. Пример приведен в листинге 4.54, в котором команда UPDATE обновляет поле retail таблицы stock. Повышение розничной цены для всех книг, имеющихся в наличии, вычисляется при помощи математического выражения. Выражение состоит из нескольких компонентов, а круглые скобки обеспечивают нужный порядок их вычисления. <br> Подвыражение (retail / cost) определяет текущую удельную прибыль, которая увеличивается на 10 % при помощи оператора + и вещественной константы 0.1. Конструкция 0.1:: numeric выполняет явное преобразование вещественной константы к типу numeric; необходимость преобразования объясняется тем, что частное при делении retail /cost относится к типу numeric. Наконец, новая удельная прибыль умножается на стоимость единицы товара из поля cost. Результат равен новой цене, сохраняемой в поле retail. <br> <br><br> <h1>Обновление записей по нескольким источникам</h1> <br> <br> Обновление записей по нескольким источникам <br><br> В PostgreSQL команда SQL UPDATE была дополнена мощной нестандартной возможностью — поддержкой секции FROM. Секция FROM позволяет получать входные данные из других наборов данных (таблиц и подзапросов). <br> В листинге 4.56 команда UPDATE с секцией FROM обновляет данные таблицы stock по данным таблицы stock_backup. Секция WHERE описывает связь между обновляемой таблицей и источником. Каждый раз, когда в таблицах находятся совпадающие значения isbn, поле retail в таблице stock обновляется значением из резервной таблицы stock_backup. <br> <br><br> <h1>Переименование полей</h1> <br> <br> Переименование полей <br><br> PostgreSQL позволяет изменять имена полей без изменения данных, хранящихся таблице. Впрочем, переименование полей — дело рискованное, поскольку существующие приложения могут содержать ссылки на имена полей. Если программа обращается к полю по имени, то переименование может нарушить ее работоспособность. <br> Команда переименования полей имеет следующий синтаксис: <br> ALTER TABLE таблица <br> RENAME [ COLUMN ] имя_поля ТО новое_иня_поля <br> Как и в других командах ALTER TABLE, ключевое слово COLUMN является необязательным. По двум идентификаторам, разделенным ключевым словом ТО, Post-greSQL может определить, что команда переименования относится к одному полю, а не таблице. Пример переименования полей приведен в листинге 4.11. <br> <br><br> <h1>Переименование таблицы</h1> <br> <br> Переименование таблицы <br><br> Переименование таблиц осуществляется командой ALTER TABLE с секцией RENAME, интаксис переименования таблицы: <br> JER TABLE таблица <br> RENAME TO новое_иня <br> Таблицу можно переименовывать сколько угодно раз, это никак не отражается а состоянии хранящихся в ней данных (листинг 4.10). Конечно, в некоторых си-/ацпях переименования нежелательны — например, если таблица используется вешним приложением. <br> <br><br> <h1>Перекрестные объединения</h1> <br> <br> Перекрестные объединения <br><br> Результат перекрестного объединения принципиально не отличается от перечисления источников через запятую. Следовательно, в команде выборки с перекрестным объединением практически всегда должна присутствовать секция WHERE, уточняющая связи между объединенными наборами данных. В листинге 4.35 приведен запрос из листинга 4.27, в котором перечисление источников заменено формальным синтаксисом JOIN. <br> <br><br> <h1>Подзапросы</h1> <br> <br>Подзапросы <br><br> Поддержка подзапросов, впервые реализованная в PostgreSQL версии 6.3, существенно повысила гибкость команд SQL. Подзапросом называется команда SELECT, заключенная в круглые скобки, которая выполняется в контексте другой команды SQL. Подзапросы чаще используются для возвращения одной записи, но они также могут использоваться для определения подмножества записей. <br> Подзапросы могут находиться практически в любой части команды SQL — в списке целей, в секции WHERE и т. д. В листинге 4.59 приведен простой пример использования подзапроса для выборки критерия поиска из другой таблицы. <br> <br><br> <h1>Представления</h1> <br> <br>Представления <br><br> При работе с SQL нередко возникают ситуации, когда один и тот же запрос приходится использовать повторно. Ничто не раздражает так, как необходимость многократного ввода больших и сложных запросов в psql. Кроме того, было бы крайне неэффективно пересылать большие наборы данных по сети на сервер PostgreSQL при выполнении стандартных процедур. <br> В подобных ситуациях обычно используются представления (views). Представление можно рассматривать как хранимый запрос, на основе которого создается объект базы данных. Этот объект очень похож на таблицу, но в его содержимом динамически отражается состояние только тех записей, которые были заданы при создании. Представления весьма гибки и универсальны; они могут строиться на основе как простых и стандартных запросов к одной таблице, так и чрезвычайно сложных запросов, в которых задействовано несколько таблиц. <br> <br><br> <h1>Применение представлений</h1> <br> <br> Применение представлений <br><br> Представления значительно упрощают получение нужных данных. Вместо того чтобы вводить длинный запрос, достаточно ввести простую команду SELECT (листинг 4.63). <br> <br><br> <h1>Пример создания таблицы</h1> <br> <br> Пример создания таблицы <br><br> Команда SQL, приведенная в листинге 4.6, создает таблицу books в базе данных booktovvn. <br> <br><br> <h1>Простая команда SELECT</h1> <br> <br> Простая команда SELECT <br><br> В простейшем случае команда SELECT выбирает из заданной таблицы все данные (то есть все записи и все поля). Полная выборка данных производится командой <br> SELECT * FROM имя таблицы;<br> Как упоминалось при описании синтаксиса SELECT, звездочка (*) является сокращенным обозначением всех несистемных полей. Таким образом, команда SELECT * выбирает из указанной таблицы все поля и все записи, поскольку количество записей в итоговом наборе не ограничивается. В листинге 4.23 приведен пример выборки всех записей (*) из таблицы books базы данных booktown. <br> <br><br> <h1>Различия команд COPY и \copy</h1> <br> <br> Различия команд COPY и \copy <br><br> Команда SQL COPY не эквивалентна команде psql \copy. Команда \copy имеет тот же синтаксис (хотя и не завершается точкой с запятой), она выполняет операцию че- <br> рез клиента psql, а не через серверный процесс postmaster. В результате команда \copy выполняется с правами пользователя, запустившего psql, а не с теми правами, с которыми работает процесс postmaster. <br> <br><br> <h1>Редактирование буфера запроса</h1> <br> <br> Редактирование буфера запроса <br><br> Команда \е открывает текущее содержимое буфера запроса в редакторе, заданном переменной среды EDITOR. Это позволяет просмотреть и при необходимости изменить любую строку запроса перед его обработкой. В листинге 4.5 показано, как задать значение переменной EDITOR. Если переменная EDITOR не задана, используется редактор vi. <br> <br><br> <h1>Реструктуризация таблиц командами CREATE TABLE и INSERT INTO</h1> <br> <br> Реструктуризация таблиц командами CREATE TABLE и INSERT INTO <br><br> Если таблица, создаваемая командой CREATE TABLE AS, вас почему-либо не устраивает (например, если в таблице необходимо установить ограничения полей), то одну команду CREATE TABLE AS можно заменить двумя командами SQL. Сначала команда CREATE TABLE создает новую таблицу, а затем команда INSERT INTO с запросом SELECT заполняет ее данными (листинг 4.15). <br> <br><br> <h1>Реструктуризация таблиц командой CREATE TABLE AS</h1> <br> <br> Реструктуризация таблиц командой CREATE TABLE AS <br><br> Распространенная методика реструктуризации таблиц основана на использовании команды CREATE TABLE с секцией AS в сочетании с запросом SQL. Команда создает временную таблицу на основании существующей таблицы, после чего временная таблица переименовывается. Физическое создание новой таблицы может сопровождаться удалением полей и изменением порядка их следования с одновременным заполнением данными из исходной таблицы. <br> В приведенном ниже описании синтаксиса этой усеченной версии команды CREATE TABLE запрос представляет собой команду SELECT для выборки данных, переносимых в новую таблицу. Типы данных всех создаваемых полей определяются типами данных соответствующих полей, выбранных в результате выполнения запроса. <br> CREATE [ TEMPORARY | TEMP ] TABLE таблица [ ( имя_поля [....])] AS запрос <br> Преимущество такого подхода заключается в том, что создание таблицы и заполнение ее данными происходит в одной команде SQL. Самый заметный недостаток — отсутствие полноценных возможностей для установки ограничений в созданной таблице. После того как таблица создана, в нее можно добавлять только ограничения внешних ключей и проверки. После создания новой таблицы старую таблицу можно переименовать (или уничтожить) и присвоить новой таблице имя старой. <br> Допустим, из таблицы books удаляется лишнее поле publication, созданное в пункте «Создание полей» подраздела «Модификация таблицы командой ALTER TABLE». Для этого мы создаем усеченную версию таблицы (с перечислением нужных полей) с указанием соответствующей команды SELECT в секции AS команды CREATE TABLE, после чего старая таблица удаляется командой DROP TABLE (листинг 4.14). <br> <br><br> <h1>Реструктуризация таблиц</h1> <br> <br> Реструктуризация таблиц <br><br> Несмотря на возможность включения новых полей в существующую таблицу, следует помнить, что в PostgreSQL (во всяком случае, в версии 7.1.x) не поддерживается удаление полей. Существует два относительно простых способа реструктуризации существующих таблиц. Первый способ основан на использовании команды CREATE TABLE AS, а во втором способе команда CREATE TABLE объединяется с командой INSERT INTO. <br> Фактически оба способа сводятся к созданию новой таблицы требуемой структуры, заполнению ее данными из существующей таблицы и переименованию. Таким образом, новая таблица занимает место старой. <br> ВНИМАНИЕ <br> При реструктуризации таблиц следует помнить, что идентификаторы объектов (OID) изменятся, а старые индексы, сгенерированные для исходной таблицы, не будут автоматически действовать в новых таблицах. Все индексы необходимо удалить и построить заново. <br> <br><br> <h1>Секция WITH OIDS</h1> <br> <br> Секция WITH OIDS <br><br> Файлы, содержащие идентификаторы объектов (созданные командой COPY TO с секцией WITH OIDS), загружаются командой COPY FROM, в которую также включается секция WITH OIDS. Попытки использования команды COPY FROM с секцией WITH OIDS по отношению к файлу, в котором значения OID не были сохранены при создании, завершаются неудачей. <br> Экспортирование данных с идентификаторами объектов принадлежит к числу специальных возможностей, присущих только команде COPY. Значения OID являются системными и поэтому не могут изменяться командами INSERT и UPDATE. Если не принять меры предосторожности, в таблице могут появиться две записи с одинаковыми значениями OID.<br> <br> <br><br><br> <h1>Синонимы источников данных в секции FROM</h1> <br> <br> Синонимы источников данных в секции FROM <br><br> Источникам данных в секции FROM — таблицам, подзапросам и т. д. — можно назначать синонимы в секции AS (по аналогии с отдельными полями). Синонимы часто используются для упрощения точечной записи, о которой говорилось в преды- <br> дущем разделе. Наличие синонима для набора данных позволяет обращаться к нему при помощи точечной записи, что делает команды SQL более компактными и наглядными. В листинге 4.29 приведен запрос из листинга 4.27 с упрощением точечной записи при помощи секции AS. <br> <br><br> <h1>Синтаксис команды CREATE TABLE</h1> <br> <br> Синтаксис команды CREATE TABLE <br><br> Синтаксис команды CREATE TABLE выглядит так: <br> CREATE [ TEMPORARY | TEMP ] TABLE имя_таблицы ( <br> { имя_поля тип [ограничение_поля [... ] ] | ограничение_таблицы } <br> [. ..Т ] ) [ INHERITS (бдзовая_тзблица [....])] <br> Ниже поясняется смысл компонентов команды. <br> <ul> <li> TEMPORARY | TEMP. Таблица, созданная с ключевым словом TEMPORARY или TEMP, автоматически уничтожается в конце текущего сеанса. Имя временной таблицы может совпадать с именем существующей таблицы; в этом случае все ссылки на таблицу с этим именем будут относиться к временной таблице (до момента ее уничтожения). Все индексы таблицы также являются временными и уничтожаются в конце сеанса. </li> <li> Имя_таблицы. Имя для ссылок на таблицу после ее создания. </li> <li> Имя_поля тип [ограничение _поля ] | ограничение ^таблицы. После имени таблицы в круглых скобках перечисляются определения полец таблицы, разделенные запятыми. Определение поля состоит из имени, которое представляет собой синтаксически правильный идентификатор допустимого типа, а также необязательного ограничения. Ограничения полей описаны в подразделе «Ограничения в таблицах» раздела «Нетривиальное использование таблиц» главы 7. Ограничения полей и таблицы могут чередоваться, хотя на практике обычно сначала перечисляются ограничения полей, а затем следуют ограничения таблицы. </li> <li> [....]. После определения поля может следовать запятая, за которой указано новое определение. Многоточие означает произвольное количество определений полей (вплоть до максимального значения 1600). Помните, что за последним элементом списка не может следовать запятая, как разрешено в языках типа Perl; это приведет к ошибке лексического разбора. </li> <li> INHERITS ( базовая _таблица [. ...] ). Объектные возможности PostgreSQL позволяют задать одну или несколько таблиц (в виде списка, разделенного запятыми), базовых по отношению к создаваемой (производной) таблице. При наличии этого необязательного элемента объявления между таблицами устанавливается связь типа «предок-потомок». Механизм наследования является относительно новой возможностью РСУБД и подробно описывается в подразделе «Наследование» раздела «Нетривиальное использование таблиц» главы 7. </li> </ul> Примечание 1 <br>Примечание 1<br><br><br> Параметры ограничение_поля и ограничение_таблицы в приведенном выше объявлении могут соответствовать достаточно сложным синтаксическим конструкциям. Синтаксис различных ограничений подробно описан в подразделе «Ограничения в таблицах» раздела «Нетривиальное использование таблиц» главы 7. <br> <br><br> <h1>Синтаксис psql</h1> <br> <br> Синтаксис psql <br><br> При запуске psql выводится краткая сводка четырех основных команд psql: <br> <ul> <li> \h — справка по SQL; </li> <li> \? — справка по командам psql; </li> <li> \д — выполнение запросов; </li> <li> \q — выход из psql после завершения работы. </li> </ul> Все команды psql начинаются с символа \ (обратная косая черта). Результат выполнения команды \? приведен в листинге 4.2. <br> <br><br> <h1>Сложные объединения</h1> <br> <br> Сложные объединения <br><br> Хотя одна секция JOIN объединяет всего два набора данных, на практике объединения не ограничиваются двумя источниками. За набором, созданным посредством объединения, может следовать новая секция JOIN — по аналогии с тем, как перечисляются через запятую источники данных. <br> Элементы комбинированных объединений рекомендуется заключать в круглые скобки. Явная группировка гарантирует отсутствие неоднозначности (как для PostgreSQL, так и для разработчика) относительно того, какие наборы и в каком порядке объединяются. Пример объединения нескольких источников данных приведен в листинге 4.39. <br> <br><br> <h1>Смена владельца</h1> <br> <br> Смена владельца <br><br> По умолчанию создатель таблицы автоматически становится ее владельцем. Владелец обладает всеми правами, связанными с таблицей, в том числе правами предоставления и отзыва прав командами GRANT и REVOKE (см. главу 10). Смена владельца производится командой ALTER TABLE с секцией OWNER. Команда имеет следующий синтаксис: <br> ALTER TABLE таблица <br> OWNER TO новый_владелец <br> Пример смены владельца командой ALTER TABLE приведен в листинге 4.13. Новым владельцем таблицы employee назначается пользователь corwin. <br> <br><br> <h1>Сортировка записей</h1> <br> <br>Сортировка записей<br><br> Как упоминалось в главе 3, записи хранятся в таблицах в произвольном порядке. Более того, даже повторное выполнение запроса никоим образом не гарантирует одинакового порядка следования возвращаемых записей. Однако упорядочение данных играет важную роль при выборке, поэтому в SQL поддерживается инструкция ORDER BY, являющаяся гибким средством сортировки итогового гонораpa. <br> Секции ORDER BY передается список полей, разделенный запятыми (или выражений, в которых используются поля). Переданный список задает критерий сортировки. Для каждого критерия сортировки могут дополнительно указываться ключевые слова ASC, DESC и USING, управляющие типом сортировки. <br> <ul> <li> ASC. Записи сортируются по возрастанию заданного критерия (то есть числа сортируются от меньших к большим, а текст — по алфавиту от «а» до «z»). Ключевое слово ASC эквивалентно конструкции USING <. По умолчанию выбирается именно этот способ сортировки, поэтому ASC используется лишь для наглядности. </li> <li> DESC. Записи сортируются по убыванию заданного критерия (то есть числа сортируются от больших к меньшим, а текст — по алфавиту от «z» до «а»). Ключевое слово DESC эквивалентно конструкции USING >. </li> <li> USING оператор. Позволяет задать оператор сравнения полей при определении очередности записей. Особенно часто используется при нестандартных критериях сортировки. </li> </ul> В листинге 4.42 приведен пример сортировки таблицы editions с использова-[ием секции ORDER BY. Сортировка осуществляется по значению поля publ ication, [ричем в команде явно указан порядок сортировки — по возрастанию (ASC). <br> <br><br> <h1>Создание полей</h1> <br> <br> Создание полей <br><br> Для создания нового поля в команду ALTER TABLE включается секция ADD COLUMN. Синтаксис команды ALTER TABLE с секцией ADD COLUMN: <br> ALTER TABLE таблица <br> ADD [ COLUMN ] имя_поля тип_поля <br> <ul> <li> таблица — имя таблицы, в которой создается новое поле; </li> <li> имя_поля — имя создаваемого поля; </li> <li> тип_поля — тип создаваемого поля. </li> </ul> Ключевое слово COLUMN не является обязательным и включается в команду лишь для наглядности. <br> Предположим, в таблицу books базы данных booktown потребовалось включить новое поле publication для хранения даты публикации. Листинг4.8 показывает, как это делается. <br> <br><br> <h1>Создание представления</h1> <br> <br> Создание представления <br><br> Представления создаются командой CREATE VIEW, синтаксис которой выглядит следующим образом: <br> CREATE VIEW представление<br> AS запрос <br> <ul> <li> представление. Имя (идентификатор) создаваемого представления. </li> <li> запрос. Полная команда SQL SELECT, определяющая содержимое представления. </li> </ul> Предположим, таблица shipments связывает уникальный код поставки с кодом клиента, кодом ISBN книги и датой отправки заказа. Структуру таблицы shipments иллюстрирует табл. 4.1. <br> <br><br> <h1>Создание таблиц на базе существующих таблиц</h1> <br> <br>Создание таблиц на базе существующих таблиц <br><br> Команда SELECT с секцией INTO TABLE создает новую таблицу, структура и содержимое которой определяются итоговым набором запроса. Синтаксис: <br> SELECT цели_выборки <br> INTO [ TABLE ] новая_таблица FROM старая_таблица <br> В этом варианте команда SELECT косвенно выполняет команду CREATE TABLE. Имена и типы полей, а также содержимое таблицы определяются параметрами итогового набора. Возвращаемое в ответ сообщение «SELECT» указывает на то, что команда была успешно выполнена, а в базе данных создана новая таблица. В листинге 4.52 приведен пример создания таблицы stock_backup по данным таблицы stock. <br> <br><br> <h1>Создание таблицы командой CREATE TABLE</h1> <br> <br> Создание таблицы командой CREATE TABLE <br><br> В языке SQL таблицы создаются командой CREATE TABLE. Минимальный набор параметров включает имя таблицы и описания полей, состоящие из имени поля и типа данных. Команде CREATE TABLE также могут передаваться некоторые необязательные параметры: ограничения полей (правила, которые определяют, какие данные могут или не могут присутствовать в поле) и ограничения таблицы (общие ограничения и связи, определенные для самой таблицы). <br> <br><br> <h1>SQL в PostgreSQL</h1> <br> <br>SQL в PostgreSQL <br><br> Наше знакомство с языком SQL продолжается. На этот раз основное внимание мы уделим практическим аспектам его применения. В этой главе будет показано, как при помощи команд SQL создавать таблицы, заполнять их данными и модифицировать эти данные. <br> Система PostgreSQL, как и большинство сетевых СУБД, основана па парадигме «клиент-сервер». Центральное место в PostgreSQL занимает процесс postmaster, предназначенный не для прямого взаимодействия с пользователем, а для обслуживания подключений со стороны различных клиентов. <br> При запуске службы (service) PostgreSQL процесс postmaster начинает работать в фоновом режиме, прослушивая заданный порт TCP/IP в ожидании подключений со стороны клиентов. По умолчанию postmaster ведет прослушивание порта 5432. <br> Существует несколько интерфейсов, через которые клиент подключается к процессу postmaster. В примерах этой книги используется psql — самый универсальный и доступный клиент, входящий в комплект поставки PostgreSQL. <br> В этой главе описаны основные принципы работы с psql, процедуры создания и использования таблиц, а также некоторые операции с данными в таблицах. Кроме того, в ней рассматриваются подзапросы и представления SQL. <br> <br><br><br> <h1>Сравнение наборов записей</h1> <br> <br>Сравнение наборов записей <br><br> Если объединения используются в SQL для слияния полей двух источников, то ключевые слова UNION, INTERSECT и EXCEPT сравнивают значения полей в двух наборах и строят новый итоговый набор на основании результатов сравнения. Каждое из перечисленных ключевых слов может использоваться в конце синтаксически правильного запроса SQL, а за ним может следовать второй запрос; в этом случае итоговые наборы двух запросов сравниваются и записи либо включаются в результат, либо игнорируются. <br> Сравниваемые наборы данных должны содержать одинаковое количество полей, относящихся к соответствующим типам. При этом не требуется, чтобы поля имели одинаковые имена или принадлежали к одной таблице или источнику данных. <br> <ul> <li> UNION. Все различающиеся записи двух наборов включаются в один набор данных. Совпадающие записи не дублируются. </li> <li> INTERSECT. Все записи, не входящие в оба набора данных, игнорируются. Таким образом, результат состоит только из записей, присутствующих в обоих наборах. </li> <li> EXCEPT. Все записи, входящие в оба набора данных, игнорируются. Таким образом, результат состоит только из тех записей набора, указанного слева от ключевого слова EXCEPT, которые не входят в набор, указанный справа от него. </li> </ul> В листингах 4.46-4.48 показаны результаты применения этих операций к двум наборам данных. В листинге 4.46 итоговый набор формируется слиянием фамилий авторов с названиями книг, для чего используется ключевое слово UNION. <br> В листинге 4.47 продемонстрирована выборка кодов ISBN из таблицы editions. Выборка ограничивается записями, которые упоминаются более чем в двух поставках в таблице shi pments. Наконец, в листинге 4.48 из первого запроса исключаются все записи, входящие во второй запрос. <br> <br><br> <h1>Таблица shipments</h1> <br> <br> Таблица 4.1. Таблица shipments <br><br> <table border=1> <tr> <td> Поле</td> <td> Тип</td> <td> Модификатор</td> </tr> <tr> <td> id</td> <td> integer</td> <td> NOT NULL DEFAULT nextval ( 'shipments_ship_id_seq' )</td> </tr> <tr> <td> customer_id</td> <td> integer</td> <td> </td> </tr> <tr> <td> isbn</td> <td> text</td> <td> </td> </tr> <tr> <td> ship_date</td> <td> timestamp</td> <td> </td> </tr> </table> Допустим, вы хотите узнать количество поставок, сведения о которых хранят-я в таблице. Это можно сделать несколькими способами, но для простоты начнем э следующего решения: <br> booktown=# SELECT COUNT(*) FROM shipments; <br> count <br> 32 <br> (1 row) <br> Звездочка (*) в этом запросе просто указывает PostgreSQL на необходимость эдсчета всех записей вместе со значениями NULL, которые могли бы присутствоваъ в поле с явно заданным именем. Запрос подсчитывает общее количество записей, то есть количество зарегистрированных поставок. <br> Предположим, данные из таблиц editions и books были объединены секцией JOIN, чтобы в выходные данные входили названия всех книг. Более того, в запрос была включена секция GROUP BY, обеспечивающая группировку поставок по названиям книг. <br> Вспомните, о чем говорилось выше в этой главе, — при группировке по полю title функция count() подсчитывает количество записей в каждой группе (в данном случае — для каждого названия книги). Наконец, для поля ship_date таблицы shipments вызывается функция max(), чтобы в результатах запроса выводилась дата последней поставки по каждой книге и количество экземпляров: <br> booktown=# SELECT count(*) AS num_shipped, max(ship_date), title <br> booktown-# FROM shipments <br> booktown-# JOIN editions USING (isbn) <br> booktown-# NATURAL JOIN books AS b (book_id) <br> booktown-# GROUP BY b.title <br> booktown-# ORDER BY num_shipped DESC; <br> num_shipped | max | title <br> 5 | 2001-08-13 09:47:04-07 | The Cat in the Hat <br> 5 | 2001-08-14 13:45:51-07 | The Shining <br> 4 | 2001-08-11 09:55:05-07 | Bartholomew and the Oobleck <br> 3 | 2001-08-14 13:49:00-07 | Franklin in the Dark <br> 3 | 2001-08-15 11:57:40-07 | Goodnight Moon <br> 3 | 2001-08-14 13:41:39-07 | The Tell-Tale Heart <br> 2 | 2001-08-15 14:02:01-07 | 2001: A Space Odyssey <br> 2 | 2001-08-14 08:42:58-07 | Dune <br> 2 | 2001-08-07 13:00:48-07 | Little Women <br> 2 | 2001-08-09 09:30:46-07 | The Velveteen Rabbit <br> 1 | 2001-08-14 07:33:47-07 | Dynamic Anatomy <br> (11 rows) <br> Запрос выдает полезную информацию, но синтаксис получается слишком громоздким, и часто вводить его вручную нежелательно. В листинге 4.62 показано, как на базе этого запроса создать представление командой CREATE VIEW. <br> <br><br> <h1>Удаление дубликатов и ключевое слово DISTINCT</h1> <br> <br>Удаление дубликатов и ключевое слово DISTINCT <br><br> Необязательное ключевое слово DISTINCT исключает дубликаты из итогового набора. Если ключевое слово ON отсутствует, из результатов запроса с ключевым словом DISTINCT исключаются записи с повторяющимися значениями целевых полей. Проверяются только поля, входящие в целевой список SELECT. <br> Предположим, таблица books содержит 15 записей, в каждой из которых присутствует поле authorjd. Некоторые коды авторов многократно встречаются в таблице books. Включение в запрос ключевого слова DISTINCT (листинг 4.31) гарантирует, что итоговый набор будет содержать не более одной записи для каждого автора. <br> <br><br> <h1>Удаление таблиц командой DROP TABLE</h1> <br> <br> Удаление таблиц командой DROP TABLE <br><br> В SQL таблицы удаляются командой DROP TABLE. Команда имеет следующий синтаксис (таблица — имя удаляемой таблицы): <br> DROP TABLE таблица <br> Использование команды DROP TABLE требует осторожности, поскольку удаление таблицы приводит к уничтожению всех хранящихся в ней данных. <br> Примечание 4 <br>Примечание 4<br><br><br> Уничтожение таблицы с неявно созданным индексом приводит к уничтожению всех связанных с ней индексов. <br> <br><br><br> <h1>Удаление записей командой DELETE</h1> <br> <br>Удаление записей командой DELETE <br><br> Удаление записей из таблиц производится стандартной командой SQL DELETE. Вызов DELETE приводит к необратимым последствиям (исключение составляют тщательно спланированные транзакционные блоки), поэтому удаление данных из базы требует крайней осторожности. <br> Команда удаления одной или нескольких записей из базы имеет следующий синтаксис: <br> DELETE FROM [ ONLY ] таблица [ WHERE условие ] <br> <ul> <li> DELETE FROM [ ONLY ] таблица. Ключевое слово ONLY означает, что обновляется только заданная таблица, но не ее производные таблицы. Применяется лишь в том случае, если таблица использовалась в качестве базовой при наследовании. </li> <li> WHERE условие. В секции WHERE задается критерий, по которому в таблице выбираются удаляемые записи. При отсутствии секции WHERE из таблицы удаляются все записи. </li> </ul> Секция WHERE почти всегда присутствует в команде DELETE. В ней определяются условия отбора удаляемых записей, выраженные в такой же синтаксической форме, как и при использовании команды SELECT. <br> Перед выполнением команды DELETE рекомендуется выполнить команду SELECT с соответствующей секцией WHERE и просмотреть удаляемые данные перед их фактическим уничтожением. Пример приведен в листинге 4.57. <br> <br><br> <h1>Уничтожение представлений</h1> <br> <br> Уничтожение представлений <br><br> Команда уничтожения представления имеет следующий синтаксис (представление — имя уничтожаемого представления): <br> DROP VIEW представление <br> Уничтожение представления не отражается на данных, которые использовались представлением. Представление всего лишь обеспечивает доступ к данным других таблиц и потому может уничтожаться без потери данных (хотя запрос, на котором оно основано, конечно, теряется). <br> <br><br><br> <h1>Уточнение запросов</h1> <br> <br> Уточнение запросов <br><br> В секции WHERE задается логическое условие, которому должны удовлетворять записи итогового набора. На практике команда SELECT почти всегда содержит как минимум одну уточняющую секцию WHERE. <br> Предположим, вы хотите получить список всех книг о компьютерных технологиях в базе данных booktown. У этих книг поле subject_id равно 4. Соответственно в секцию WHERE включается оператор =, который проверяет это условие. Пример приведен в листинге 4.32. <br> <br><br> <h1>Внешние объединения</h1> <br> <br> Внешние объединения <br><br> С другой стороны, внешнее объединение может сохранить записи, для которых не находится соответствия в других наборах. В этом случае недостающие поля заполняются значениями NULL. Решение о том, войдет ли такая запись во внешнее объединение, зависит от того, в каком из объединяемых наборов отсутствуют данные, и от типа внешнего объединения. <br> Существуют три разновидности внешних объединений. <br> <ul> <li> Левое внешнее объединение. Всегда содержит как минимум один экземпляр каждой записи из набора, указанного слева от ключевого слова JOIN. Отсутствующие поля из правого набора заполняются значениями NULL. </li> <li> Правое внешнее объединение. Всегда содержит как минимум один экземпляр каждой записи из набора, указанного справа от ключевого слова JOIN. Отсутствующие поля из левого набора заполняются значениями NULL. </li> <li> Полное внешнее объединение. Всегда содержит как минимум один экземпляр каждой записи каждого объединяемого набора. Отсутствующие поля в записях нового набора заполняются значениями NULL. </li> </ul> Вернемся к таблицам books и editions из базы данных booktown. Если в таблице books содержится общая информация о книгах, то в таблице editions хранятся данные, относящиеся к конкретному изданию — код ISBN, издатель и дата публикации. В таблицу editions входит поле book_id, связывающее ее с полем id, которое является первичным ключом таблицы books. <br> Допустим, вы хотите получить информацию о каждой книге вместе со всеми имеющимися кодами ISBN. Запрос с внутренним объединением таблиц books и editions вернет набор данных с названиями книг и кодами ISBN, но, как видно из листинга 4.38, если у книги нет печатного издания (или информация об этом издании еще не занесена в базу данных booktown), информация о ней не включается в результат. <br> Вторая команда в листинге 4.38 использует внешнее объединение и возвращает 20 записей. У трех записей в итоговом наборе отсутствуют коды ISBN, но эти записи все равно включаются в результат. <br> <br><br> <h1>Внутренние и внешние объединения</h1> <br> <br> Внутренние и внешние объединения <br><br> На практике чаще используются внутренние и внешние объединения, при которых секция JOIN обязательно содержит критерий, уточняющий связи между объединяемыми наборами данных. Синтаксис внутренних и внешних объединений: <br> источник! [ NATURAL ] тип_объединения источник2 <br> [ ON ( условие [. ...] ) I USING ( поле [, ...] ) ] <br> <ul> <li> источник! Первый из объединяемых наборов данных (имя таблицы или подзапрос). </li> <li> [ NATURAL ]. Два набора данных объединяются по равным значениям одноименных полей (например, если обе таблицы содержат поле с именем id, то объединяются записи с совпадающими значениями полей id). При наличии ключевого слова NATURAL учитываются синонимы полей (если они были назначены), а секции ON и USING становятся не только ненужными, но и недопустимыми. </li> <li> тип_объединепия. В данном контексте допустимы следующие типы объединений: [INNER] JOIN (то есть JOIN без уточнения подразумевает INNER JOIN), LEFT [OUTER] JOIN, RIGHT [OUTER] JOIN и FULL [OUTER] JOIN. </li> <li> источник2. Второй из объединяемых наборов данных (имя таблицы или подзапрос). </li> <li> ON ( условие [. ... ] ). Отношение между источниками. В секции ON можно задать произвольный критерий по аналогии с тем, как задаются условия в секции WHERE. В критерии могут использоваться синонимы таблиц и полей. </li> <li> USING ( поле [, ... ]). Одноименные поля источников, по совпадающим значениям которых производится объединение. В отличие от NATURAL JOIN позволяет ограничиться некоторыми одноименными полями, тогда как NATURAL проводит объединение по всем одноименным полям. По аналогии с NATURAL в параметрах секции USING учитываются синонимы полей. </li> </ul> <br><br> <h1>Внутренние объединения</h1> <br> <br> Внутренние объединения <br><br> Конструкция INNER JOIN была включена в стандарт SQL92 для того, чтобы условия объединения источников данных (условия JOIN) можно было отличить от условий принадлежности записей к итоговому набору (условия WHERE). Рассмотрим две команды SELECT, приведенные в листинге 4.36. <br> <br><br> <h1>Вставка данных из других таблиц командой SELECT</h1> <br> <br> Вставка данных из других таблиц командой SELECT <br><br> Команда INSERT INTO применяется и в другой ситуации — когда данные, сохраняемые в таблице, уже присутствуют в другой таблице (или неекольких таблицах). В этом случае команда имеет следующий синтаксис: <br> INSERT INTO таблица <br> [ ( имя_поля [. ...] ) ] запрос <br> По аналогии с синтаксисом INSERT INTO, представленным в предыдущем подразделе, команда содержит необязательный список полей, которым присваиваются новые значение. Тем не менее в этой форме INSERT INTO секция VALUES заменяется полной командой SQL SELECT. <br> Предположим, база данных booktown содержит таблицу book_queue с информацией о книгах, ожидающих поступления в продажу. После подтверждения данные переносятся из таблицы book_queue в обычную таблицу books. Пример решения этой задачи продемонстрирован в листинге 4.18. <br> <br><br> <h1>Вставка новых данных</h1> <br> <br> Вставка новых данных <br><br> Ниже приведен синтаксис команды INSERT INTO при вставке новых данных: <br> INSERT INTO таблица <br> [ ( имя_поля [, ...] ) ] VALUES ( значение [. ...] ) <br> Ниже перечислены параметры команды. <br> <ul> <li> таблица. Имя таблицы, в которую вставляются данные командой SQL INSERT. </li> <li> ( имя_поля [. ...] ). Необязательный группированный список полей новой записи, которым присваиваются значения. </li> <li> VALUES. Ключевое слово SQL, за которым следует группированный список значений. </li> <li> ( значение [, ... ] ). Обязательный группированный список значений полей. Для каждого поля указывается ровно одно значение, элементы списка разделяются запятыми. Элемент списка может быть выражением (например, операцией с двумя операндами) или константой. </li> </ul> Тип каждого значения в секции VALUES должен соответствовать типу поля, которому оно присваивается. Если необязательный список полей отсутствует, PostgreSQL предполагает, что секция VALUES содержит значения всех полей в структуре таблицы в порядке их определения. Если количество значений меньше количества полей, PostgreSQL пытается использовать значение по умолчанию (или NULL при его отсутствии) для каждого пропущенного элемента. <br> В листинге 4.16 приведен пример создания новой записи в таблице books базы данных booktown. <br> <br><br> <h1>Ввод запросов в приглашении psql</h1> <br> <br> Ввод запросов в приглашении psql <br><br> Запустите psql и убедитесь в том, что вы подключены к нужной базе данных (и зарегистрированы в системе с нужными параметрами). На экране появляется приглашение, которое по умолчанию совпадает с именем текущей базы данных. Приглашение выглядит примерно так: <br> testdb=# <br> Чтобы передать PostgreSQL команду SQL, просто введите ее в приглашении. Весь вводимый текст накапливается до тех пор, пока ввод не будет завершен символом точки с запятой (:). Ввод команды не прерывается даже разрывами строк, <br> что позволяет распределить запрос по нескольким строкам. Пример многострочного запроса приведен в листинге 4.3. <br> <br><br> <h1>Выбор интервалов записей</h1> <br> <br>Выбор интервалов записей <br><br> В PostgreSQL количество записей, выбираемых запросом SQL, не ограничивается. Обработка запроса, возвращающего несколько миллионов записей, займет много времени, но сервер не остановится, пока не вернет весь итоговый набор (или процесс не будет прерван извне). <br> Вероятно, выделение некоторой части выборки легко реализуется на программном уровне, но в SQL предусмотрены ключевые слова LIMIT и OFFSET, упрощающие выборку заданной части итогового набора. <br> Секция LIMIT ограничивает максимальное количество записей в итоговом наборе (хотя размер итогового набора вполне может быть меньше заданной величины). При наличии секции OFFSET в итоговом наборе пропускается количество записей, заданное параметром секции. Если заданы оба ключевых слова, то отсчет ограничения, указанного в секции LIMIT, начинается после пропуска записей в соответствии с секцией OFFSET. <br> Как показано в листинге 4.45, первый запрос, содержащий простую секцию LIMIT, ограничивается выборкой первых пяти записей из результатов объединения таблиц editions и books. Обычно это объединение содержит 17 записей. <br> <br><br> <h1>Выбор источников в секции FROM</h1> <br> <br>Выбор источников в секции FROM <br><br> В секции FROM указывается источник данных — таблица или итоговый набор. Секция может содержать несколько источников, разделенных запятыми. Результат подобного перечисления функционально эквивалентен перекрестному объединению, о котором рассказано в подразделе «Объединение наборов данных». <br> Использование нескольких источников данных в PostgreSQL требует осторожности. В результате выполнения команды SELECT для нескольких источников без секций WHERE и JOIN, уточняющих связи между источниками, возвращается полное декартово произведение источников. Иначе говоря, итоговый набор содержит все возможные комбинации записей из всех источников. <br> Обычно для уточнения связей между источниками, перечисленными через запятую в секции FROM, используется секция WHERE. Пример приведен в листинге 4.27 (за дополнительной информацией о секции WHERE обращайтесь к подразделу «Уточнение запросов»). <br> <br><br> <h1>Выбор полей</h1> <br> <br> Выбор полей <br><br> Команда SELECT * является хорошим примером простейшего запроса, но на прак-гике необходимая информация нередко ограничивается несколькими полями габлицы. Чтобы повысить эффективность выборки и сделать запрос более наглядным, рекомендуется явно перечислить все необходимые поля вместо полной вы-эорки с символом *. В частности, ограничение выборки особенно актуально при использовании секции JOIN, подробно рассматриваемой ниже в подразделе «Объединение наборов данных». <br> Поля, включаемые в итоговый набор, перечисляются после ключевого слова SELECT. Запрос возвращает данные только для полей, входящих в этот список. По-эядок перечисления полей не обязан совпадать с их порядком в структуре табли-ды; допускается как многократное вхождение, так и отсутствие некоторых полей в :писке. Пример приведен в листинге 4.24. <br> <br><br> <h1>Выборка данных командой SELECT</h1> <br> <br>Выборка данных командой SELECT <br><br> Центральное место в SQL занимает команда SELECT, предназначенная для построения запросов и выборки данных из таблиц и представлений. Данные, возвращаемые в результате запроса, называются итоговым набором; как и таблицы, они состоят из записей и полей. <br> Данные итогового набора не хранятся на диске в какой-либо постоянной форме. Итоговый набор является лишь временным представлением данных, полученных в результате запроса. Структура полей итогового набора может соответствовать структуре исходной таблицы, но может и радикально отличаться от нее. Итоговые наборы даже могут содержать поля, выбранные из других таблиц. <br> Из-за своей особой роли в PostgreSQL команда SELECT также является самой сложной командой, обладающей многочисленными секциями и параметрами. Ниже приведено общее определение синтаксиса SELECT, а отдельные компоненты рассматриваются в следующих разделах. Термин выражение соответствует имени поля или общему выражению (например, результату операции, в которой участвует значение поля и константа или значения двух полей). <br> SELECT [ ALL | DISTINCT [ ON ( выражение [. ...] ) ] ] цель [ AS имя ] [. ...] [ FROM источник [. ... ] ] <br> [ [ NATURAL ] тип_обьединения источник <br> [ ON условие \ USING ( список_полей ) ] ] <br> [. ...] <br> [ WHERE условие ] [ GROUP BY критерий [. ...] ] [ HAVING условие [. ...] ] <br> [ { UNION | INTERSECT | EXCEPT } [ ALL ] подзапрос ] [ ORDER BY выражение <br> [ ASC | DESC | USING оператор ] [. ...] ] <br> [ FOR UPDATE [ OF таблица [. ...]]] [ LIMIT { число | ALL } [ { OFFSET | . } начало ] ] <br> В этом описании источник представляет собой имя таблицы или подзапрос. Эти общие формы имеют следующий синтаксис: <br> FROM { [ ONLY ] таблица [ [ AS ] синоним [ ( синоним_поля [....])]]] ( запрос ) <br> [ AS ] синоним [ ( синоним_поля [. ...] ) ] } <br> <ul> <li> ALL. Необязательное ключевое слово ALL указывает на то, что в выборку включаются все найденные записи. </li> <li> DISTINCT [ ON ( выражение [, ...] ) ]. Секция DISTINCT определяет поле или выражение, значения которого должны входить в итоговый набор не более одного раза. </li> <li> цель [ AS имя ] [, ...]. В качестве цели обычно указывается имя поля, хотя цель также может быть константой, идентификатором, функцией или общим выражением. Перечисляемые цели разделяются запятыми, существует возможность динамического назначения имен целей в секции AS. Звездочка (*) является сокращенным обозначением всех несистемных полей, вместе с ней в списке могут присутствовать и другие цели. </li> <li> FROM источник [. ... ]. В секции FROM указывается источник, в котором PostgreSQL ищет заданные цели. В данном случае источник является именем таблицы или подзапроса. Допускается перечисление нескольких источников, разделенных запятыми (примерный аналог перекрестного запроса). Синтаксис секции FROM подробно описан ниже. </li> <li> [ NATURAL ] тип_объединения источник [ ON условие \ USING ( список_полей ) ]. Источники FROM могут группироваться в секции JOIN с указанием типа объединения (INNER, FULL, OUTER, CROSS). В зависимости от типа объединения также может потребоваться уточняющее условие или список полей. </li> <li> WHERE условие. Секция UHERE ограничивает итоговый набор заданными критериями. Условие должно возвращать простое логическое значение (true или false), но оно может состоять из нескольких внутренних условий, объединенных логическими операторами (например, AND или OR). </li> <li> GROUP BY критерий [, ... ]. Секция GROUP BY обеспечивает группировку записей по заданному критерию. Причем критерий может быть простым именем поля или произвольным выражением, примененным к значениям итогового набора. </li> <li> HAVING условие [. ... ]. Секция HAVING похожа на секцию WHERE, но условие проверяется на уровне целых групп, а не отдельных записей. </li> <li> { UNION | INTERSECT | EXCEPT } [ ALL ] подзапрос. Выполнение одной из трех операций, в которых участвуют два запроса (исходный и дополнительный); </li> <li> итоговые данные возвращаются в виде набора с обобщенной структурой, из которого удаляются дубликаты записей (если не было задано ключевое слово ALL):</li></ul> <ul> <li> UNION — объединение (записи, присутствующие в любом из двух наборов); </li> <li> INTERSECT — пересечение (записи, присутствующие одновременно в двух наборах); </li> <li> EXCEPT — исключение (записи, присутствующие в основном наборе SELECT, но не входящие в подзапрос). </li> </ul> <li> ORDER BY выражение. Сортировка результатов команды SELECT по заданному выражению. </li> <li> [ ASC | DESC | USING оператор ]. Порядок сортировки, определяемой секцией ORDER BY выражение: по возрастанию (ASC) или по убыванию (DESC). С ключевым словом USING может задаваться оператор, определяющий порядок сортировки (например, < или >). </li> <li> FOR UPDATE [ OF таблица [. ... ] ]. Возможность монопольной блокировки возвращаемых записей. В транзакционных блоках FOR UPDATE блокирует записи указанной таблицы до завершения транзакции. Заблокированные записи не могут обновляться другими транзакциями. </li> <li> LIMIT { число \ ALL }. Ограничение максимального количества возвращаемых записей или возвращение всей выборки (ALL). </li> <li> { OFFSET | ,} начало. Точка отсчета записей для секции LIMIT. Например, если в секции LIMIT установлено ограничение в 100 записей, а в секции OFFSET — 50, запрос вернет записи с номерами 50-150 (если в итоговом наборе найдется столько записей). Ниже описаны компоненты секции FROM. <br> </li> <li> [ ONLY ] таблица. Имя таблицы, используемой в качестве источника для команды SELECT. Ключевое слово ONLY исключает из запроса записи всех таблиц-потомков. </li> <li> [ AS ] синоним. Источникам FROM могут назначаться необязательные псевдонимы, упрощающие запрос (например, на таблицу books можно ссылаться по псевдониму Ь). Ключевое слово AS является необязательным. </li> <li> ( запрос ) [ AS ] синоним. В круглых скобках находится любая синтаксически правильная команда SELECT. Итоговый набор, созданный запросом, используется в качестве источника FROM так, словно выборка производится из статической таблицы. При выборке из подзапроса обязательно должен назначаться синоним. </li> <li> ( синоним_поля [. ...] ). Синонимы могут назначаться не только всему источнику, но и его отдельным полям. Перечисляемые синонимы полей разделяются запятыми и группируются в круглых скобках за синонимом источника FROM. Синонимы перечисляются в порядке следования полей в таблице, к которой они относятся. </li> <br><br> <h1>Выполнение запросов</h1> <br> <br> Выполнение запросов <br><br> В psql существует два способа ввода и исполнения запросов (в psql этот термин означает команду SQL вообще). В интерактивном режиме запросы обычно вводятся непосредственно в приглашении командной строки (то есть из стандартного ввода). Команда psql \i читает файл локальной файловой системы и использует его содержимое в качестве входных данных. <br> <br><br> <h1>Выражения константы и синонимы</h1> <br> <br> Выражения, константы и синонимы <br><br> Целями команды SELECT могут быть не только простые поля, но и произвольные выражения (включающие вызовы функций или различные операции с идентификаторами) и константы. Синтаксис команды практически не изменяется, появляется лишь одно дополнительное требование — все самостоятельные выражения, , идентификаторы и константы должны разделяться запятыми. В списке разрешены произвольные комбинации разнотипных целей. <br> Команда SELECT также может использоваться для простого вычисления и вывода результатов выражений и констант. В этом случае она не содержит секции FROM или имен столбцов (листинг 4.25). <br> <br><br> <h1>Запуск psql</h1> <br> <br> Запуск psql <br><br> Перед запуском psql убедитесь в том, что двоичный файл psql находится в стандартном каталоге исполняемых файлов (например, /usr/bin), либо путь к каталогу двоичных файлов PostgreSQL (например, /usr/local/pgsql/bin) включен в список ката- <br> логов переменной среды PATH. За дополнительной информацией обращайтесь к главе 2. <br> Способ присваивания значения переменной PATH зависит от командного интерпретатора. В bash или ksh соответствующая команда может выглядеть так:<br> $ export PATH=$PATH:/usr/local/pgsql/bin<br> В интерпретаторах csh или tcsh используется несколько иной синтаксис: <br> $ set path=(Spath /usr/local/pgsql/bin) <br> <br><br> <h1>Знакомство с psql</h1> <br> <br>Знакомство с psql <br><br> Клиент psql работает в режиме командной строки и входит в комплект поставки PostgreSQL. Его часто называют интерактивным монитором или интерактивным терминалом. Этот простой, но мощный инструмент позволяет напрямую работать с сервером PostgreSQL и потому особенно хорошо подходит для экспериментов. <br> <br><br> <h1>Операторы и функции</h1> <h1>Агрегатные функции</h1> <br> <br>Агрегатные функции <br><br> Агрегатными функциями называется особый класс функций, применяемых сразу к нескольким записям набора данных, но возвращающим одно значение. Обычно агрегатные функции используются в запросах с группировкой по критерию, заданному в секции GROUP BY, но также встречается их применение в запросах, у которых целевой список состоит только из агрегатных функций. В этом случае агрегатная функция обрабатывает все записи итогового набора. <br> В табл. 5.16 перечислены агрегатные функции, поддерживаемые в PostgreSQL. Полный список агрегатных функций выводится в psql командой \da. <br> <br><br> <h1>Агрегатные выражения</h1> <br> <br> Агрегатные выражения <br><br> При вызове агрегатной функции передается агрегатное выражение, применяемое к записям, созданным командой SELECT. По своей структуре агрегатные выражения сходны с обычными выражениями SQL, но они могут начинаться с ключевого слова ALL или DISTINCT. <br> Если задано ключевое слово DISTINCT, функция обрабатывает только группы с уникальными значениями агрегатного выражения; группы с повторяющимися значениями игнорируются. Ключевое слово ALL, как и в команде SELECT, всего лишь явно указывает на тот факт, что выражение относится ко всем группам. В листинге 5.19 приведены примеры разных форм агрегатных выражений. <br> <br><br> <h1>Числовые операторы</h1> <br> <br>Числовые операторы <br><br> Числовые операторы PostgreSQL делятся на три категории. <br> <ul> <li> Математические операторы выполняют математическую операцию с одним или двумя операндами и возвращают значение числового типа. </li> <li> Операторы сравнения проверяют заданное соотношение между двумя числовыми величинами (например, что одна величина больше другой) и возвращают результат проверки в виде типа boolean. </li> <li> Двоичные операторы работают на уровне отдельных битов, то есть единиц и нулей в двоичном представлении. </li> </ul> Ниже приведены более подробные описания по всем трем категориям. <br> <br><br> <h1>Двоичные операторы</h1> <br> <br> Двоичные операторы <br><br> Двоичные операторы выполняют поразрядные операции с битовыми последовательностями или целыми числами, что обычно приводит к изменению их значений. Двоичные операторы PostgreSQL перечислены в табл. 5.6. <br> <br><br> <h1>Функции для работы с датой и временем</h1> <br> <br>Функции для работы с датой и временем <br><br> В PostgreSQL поддерживаются как стандартные функции SQL current_date, current_time и current_timestamp, так и множество нестандартных функций. Функции PostgreSQL, предназначенные для работы с датой и временем, перечислены в табл. 5.11. <br> <br><br> <h1>Функции преобразования типа</h1> <br> <br>Функции преобразования типа <br><br> Хотя PostgreSQL позволяет выполнять явные преобразования между основными типами данных, некоторые преобразования удобнее выполнять при помощи функций. В табл. 5.13 перечислены основные функции преобразования типов PostgreSQL, а ниже приводятся их подробные описания. <br> <br><br> <h1>Функции</h1> <br> <br>Функции <br><br> Функция представляет собой идентификатор, используемый в PostgreSQL для выполнения программных операций в командах SQL. Функции всегда возвращают одно значение, применяемое в команде SQL, из которой была вызвана функция. Происходящее отчасти напоминает возврат значения оператором, вызванным из запроса; более того, с технической точки зрения оператор представляет собой указатель на встроенную системную функцию. Таким образом, операторы можно рассматривать как удобную форму записи, упрощающую вызов системных функций. <br> <br><br><br> <h1>Использование функций</h1> <br> <br>Использование функций <br><br> При вызове функции в команде SQL указывается имя функции, после которого в круглых скобках перечисляются аргументы. Существует два основных стиля передачи аргументов. Стандартные функции SQL92 обычно реализуются так, что их аргументы разделяются специальными ключевыми словами SQL (такими, как FROM, FOR и USING). С другой стороны, функции в стиле PostgreSQL получают аргументы, разделенные запятыми (вероятно, программисту с опытом программирования на С этот способ покажется более привычным). <br> В качестве аргументов могут передаваться константы, допустимые идентификаторы или выражения. Интерпретация аргументов и их принадлежность к определенному типу данных полностью зависит от вызываемой функции. За именем функции практически всегда обязательно следуют круглые скобки, даже если при вызове не передаются аргументы. <br> функция_в_стиле_sq192 ( { аргумент \ КЛЮЧЕВОЕ_СЛОВО } [.:.] )<br> ipyHKuHz_Bj:THnej)gsql92 ( аргумент [, ...] ) <br> ВНИМАНИЕ <br> Круглые скобки не обязательны только для функций SQL92 current_date, current_t1me и current_timestamp. В PostgreSQL эти функции также вызываются без круглых скобок, чтобы обеспечить совместимость со спецификацией SQL92. <br> Вызовы функции могут быть вложенными — при условии, что тип данных, возвращаемый внутренней функцией, совместим с типом соответствующего аргумента внешней функции. Допускается вложение вызовов на произвольную глубину: <br> имя_функции (имя_вложенной_функции (аргументы [. ... ] ) [. ...] ) <br> В PostgreSQL существует множество стандартных функций, работающих со встроенными типами данных. Полный список функций выводится командой \df в клиенте psql. Кроме того, в PostgreSQL поддерживается возможность определения пользовательских функций при помощи команды CREATE FUNCTION. За дополнительной информацией обращайтесь к главе 7. <br> Примечание 1 <br>Примечание 1<br><br><br> По умолчанию полям в целевом списке, значение которых определяется функцией, назначается синоним в виде имени функции без круглых скобок и без аргументов (например, to_char). <br> <br><br><br> <h1>Конкатенация</h1> <br> <br> Конкатенация <br><br> Оператор конкатенации (11) играет очень важную роль при форматировании выходных данных. Как и все операторы, он может использоваться в командах SQL всюду, где могут использоваться константы. Допускается последовательная конкатенация строковых значений, для этого перечисляемые строковые константы или идентификаторы разделяются операторами 11. <br> Например, оператор конкатенации может использоваться в секции WHERE для фильтрации записей на основании сравнения с символьной строкой. Пример приведен в листинге 5.4. <br> <br><br> <h1>Правильное использование</h1> <br> <br>Листинг 5.1. Правильное использование математического оператора <br><br> booktown=# SELECT id 1 AS id_p1us_one. 1ast_name <br> booktown-# FROM authors <br> booktown-# ORDER BY id DESC LIMIT 5; <br> id_plus_one j last_name <br> 25042 Bianco 15991 | Bourgeois <br> 7807 | Christiansen <br> 7806 | Lutz <br> 4157 I King <br> (5 rows) <br> Попытка сложения несовместимых типов продемонстрирована в листинге 5.2. <br> <br><br> <h1>Использование операторов сравнения</h1> <br> <br>Листинг 5.10. Использование операторов сравнения <br><br> booktown=# SELECT isbn, stock booktown-# FROM stock <br> booktown-# WHERE retail <= 25 <br> booktown-# AND stock != 0: <br> isbn | stock <br> 0441172717 | 77 <br> 0590445065 | 10 <br> 0679803335 | 18 <br> 0760720002 | 28 <br> 09296C5942 | 25 <br> 1885418035 | 77 <br> (6 rows) <br> <br><br> <h1>Ключевое слово BETWEEN</h1> <br> <br>Листинг 5.11. Ключевое слово BETWEEN <br><br> booktown=# SELECT isbn FROM stock <br> booktown-# WHERE cost BETWEEN 10 AND 17; <br> isbn <br> 0394800753 0441172717 0451457994<br> (3 rows) <br> Аналогичного результата можно добиться и при помощи оператора <= в сочетании с оператором > <br>= (листинг 5.12). <br> <br><br> <h1>Имитация ключевого</h1> <br> <br>Листинг 5.12. Имитация ключевого слова BETWEEN при помощи операторов <br><br> booktown=# SELECT isbn FROM stock <br> booktown-# WHERE cost > <br>= 10 AND cost <= 17; isbn <br> 0394800753 0441172717 0451457994 <br> (3 rows) <br> В варианте с ключевым словом BETWEEN команда выглядит более понятной. Впрочем, для PostgreSQL оба варианта эквивалентны, поэтому выбор зависит от личных предпочтений программиста. <br> <br><br> <h1>Сдвиг битовых последовательностей</h1> <br> <br>Листинг 5.13. Сдвиг битовых последовательностей <br><br> booktown=# SELECT b'1000' » 2 AS "8 shifted right". <br> booktown-# Mttoint4(b'1000' » 2) AS integer. <br> booktown-# 8 » 2 AS likewise; <br> 8 shifted right | integer | likewise <br> 0010 I 2 I 2 <br> (1 row) <br> Примечание 2 <br>Примечание 2<br><br><br> При сдвиге битовых последовательностей исходная длина строки не изменяется, а разряды, выходящие за левый или правый край последовательности, отсекаются. При использовании операторов &, | или # битовые операнды должны иметь одинаковую длину.<br> <br><br> <h1>Объединение условий</h1> <br> <br>Листинг 5.14. Объединение условий с использованием логических операторов <br><br> booktown=# SELECT isbn, cost, stock <br> booktown-# FROM stock <br> booktown-# WHERE cost > <br> 30 <br> booktown-# OR stock = 0: <br> Isbn cost | stock <br> 0394900014 23.00 | 0 <br> 044100590X | 36.00 | 89 <br> 0451198492 | 36.00 | 0 <br> 0451457994 17.00 j 0 (4 rows) <br> booktown=# SELECT Isbn, cost, stock <br> booktown-# FROM stock <br> booktown-# WHERE cost > <br> 30 <br> booktown-# AND stock = 0; <br> Isbn | cost stock <br> 0451198492 36.00 0 <br> (1 row) <br> <br><br> <h1>Проверка с использованием конструкции IS NULL</h1> <br> <br>Листинг 5.15. Проверка с использованием конструкции IS NULL <br><br> booktown=# SELECT lastjiame, firstjiame <br> booktown-l FROM authors <br> booktown-* WHERE firstjiame IS NULL; <br> lastjiame fi rstjname <br> Geisel <br> (1 row) <br> При сравнении команд в листингах 5.15 и 5.16 может показаться, что эти два варианта синтаксиса идентичны. Тем не менее между ними существует принципиальное различие. <br> <br><br> <h1>Сравнение со значением NULL</h1> <br> <br>Листинг 5.16. Сравнение со значением NULL <br><br> booktown=# SELECT lastjiame, firstjiame <br> booktown-l FROM authors <br> booktown-f WHERE firstjiame = NULL: <br> lastjiame | fi rstjname <br> Geisel | <br> (1 row) <br> В PostgreSQL условие = NULL преобразуется в IS NULL, а условие != NULL преобразуется в IS NOT NULL. Это сделано только для совместимости с существующими клиентскими приложениями (например, Microsoft Access). <br> Тем не менее при сравнении значений с NULL вместо математических операторов = и != рекомендуется использовать конструкции IS NULL и NOT IS NULL. В настоящее время использование математических операторов = и != для сравнения со псевдозначениями NULL допускается ради совместимости с другими системами, но в будущем эта поддержка может быть ликвидирована, поскольку она не предусмотрена в стандарте SQL. По той же причине она не гарантирована в других СУБД на базе SQL. <br> Все остальные операторы сравнения для операнда NULL возвращают NULL, поскольку NULL никогда не бывает больше или меньше другой величины, отличной от NULL (листинг 5.17). NULL можно рассматривать как своего рода «черную дыру» в мире SQL — для этого псевдозначения ни один оператор сравнения (кроме IS NULL и специального оператора преобразования =) не возвращает true; NULL не может участвовать в операциях сложения, конкатенации и т. д. <br> <br><br> <h1>Операторы и псевдозначение NULL</h1> <br> <br>Листинг 5.17. Операторы и псевдозначение NULL <br><br> booktown=# \pset null *nu11* Null display is <br> booktown=# SELECT 5 > <br> NULL; <br> ?column? <br> *null* <br> (1 row) <br> booktown=# SELECT NULL IS NULL; <br> ? column? <br> t (1 row) <br> booktown=# SELECT NULL || 'Test'; ?column? <br> *null* <br> (1 row)<br> <br><br> <h1>Приоритет операторов</h1> <br> <br>Листинг 5.18. Приоритет операторов <br><br> booktown=# SELECT 60 + 12 * 5 <br> AS "sixty plus twelve times five", <br> booktown-# 12 + 60 * 5 <br> AS "twelve plus sixty times five"; <br> sixty plus twelve times five | <br> twelve plus sixty times five <br> 120 | 312 <br> (1 row) <br> Как видно из листинга, результат выражения без круглых скобок, обеспечивающих нужный порядок выполнения операторов, в значительной степени зависит от порядка следования операндов. В приведенном примере первым всегда выполняется оператор умножения (несмотря на то, что оператор + расположен левее). <br> В табл. 5.8 перечислены группы операторов PostgreSQL в порядке убывания их приоритета. <br> <br><br> <h1>Использование агрегатных выражений</h1> <br> <br>Листинг 5.19. Использование агрегатных выражений <br><br> booktown=# SELECT count(location) AS setjocations, <br> booktown-# count(ALL location) AS all_set_locations, <br> booktown-# count(DISTINCT location) AS unique_locations, <br> booktown-# count(*) AS all_rows booktown-# FROM subjects; <br> setjocations | all_set_locations | uniquejocations all_rows <br> 15 15 | 7 16 <br> (1 row) <br> У агрегатных выражений также имеется специальная форма, продемонстрированная в столбце al l_rows выходных данных листинга 5.19. Если при вызове агрегатной функции передается звездочка (*), это означает, что функция должна обрабатывать все поля, в том числе и обычно игнорируемые поля со значениями NULL. Поскольку таблица subjects содержит одну запись с полем location, равным NULL, результат подсчета записей по полю 1 ocati on отличается от результата подсчета по тому же нолю с использованием символа *. <br> ВНИМАНИЕ <br> Записи, у которых в агрегатное выражение входит NULL, не обрабатываются агрегатными функциями (исключением является функция count(). <br> avg() <br> Синтаксис: avg(выражение) <br> Функция avg() получает агрегатное выражение, результат которого относится к любому из числовых типов (numeric, bigint, smallint, real или double precision) или к типу interval. <br> Функция возвращает среднее арифметическое всех данных, описываемых выражением. Возвращаемое значение относится к типу numeric для выражения типа integer или к типу double precision для выражения типа real. В остальных случаях тип возвращаемого значения совпадает с типом выражения. <br> <br><br> <h1>Неверное использование операторов</h1> <br> <br>Листинг 5.2. Неверное использование операторов <br><br> booktown=# SELECT id + lastjiame AS mistake <br> booktown-# FROM authors: <br> ERROR: Unable to identify an operator '+' for types 'int4' and 'text' You will have to retype this query using an explicit cast <br> К счастью, в сообщениях о недопустимом использовании операторов в PostgreSQL указывается причина ошибки. Эта информация поможет вам устранить ошибку и внести необходимые исправления в команду. <br> <br><br> <h1>Сравнение строк</h1> <br> <br>Листинг 5.3. Сравнение строк <br><br> booktown=# SELECT title FROM books <br> booktown=# WHERE substrCtitle, 1, 1) < 'D1; <br> title <br> 2001: A Space Odyssey <br> Bartholomew and the Oobleck <br> (2 rows) <br> <br><br> <h1>Конкатенация строк</h1> <br> <br>Листинг 5.4. Конкатенация строк <br><br> booktown=# SELECT 'The Title: ' | title || ', by ' | <br> booktown-# first_name || ' ' II lastjiame AS bookjinfo <br> booktown-# FROM books NATURAL JOIN authors AS a (authorjd) LIMIT 3; <br> book_info <br> The Title: The Shining, by Stephen King <br> The Title: Dune, by Frank Herbert <br> The Title: 2001: A Space Odyssey, by Arthur C. Clarke <br> (3 rows) <br> <br><br> <h1>Поиск по регулярному выражению</h1> <br> <br>Листинг 5.5. Поиск по регулярному выражению <br><br> booktown=# SELECT first_name, last_name <br> booktown-# FROM authors <br> booktown-# WHERE firstjiame - "AT1; <br> fi rstjiame lastjiame <br> Ariel Denham Tom Christiansen <br> Arthur C. | Clarke Andrew Brookins <br> Theodor Seuss j Geisel (5 rows) <br> Символ ~ в секции WHERE является оператором регулярного выражения, а само регулярное выражение задается строкой ЛА| ЛТ. В него входят специальные символы (метасимволы) л и |, а также литералы А и Т. Метасимволы регулярных выражений описаны ниже в этом пункте. <br> Важнейшее различие между функцией 11 ke() и операторами регулярных выражений заключается в том, что функция likeO ищет совпадение для всей строки, а операторы регулярных выражений ищут совпадение в произвольной позиции заданной строки, если только в самом регулярном выражении не указано обратное. <br> Операторы регулярных выражений перечислены в табл. 5.2. Их операндами всегда являются строка с регулярным выражением и текст, в котором ищется совпадение (идентификатор или константа). Все операторы регулярных выражении <br> возвращают результат логического типа, интерпретация которого зависит от специфики самого оператора. <br> <br><br> <h1>Простой поиск соответствия</h1> <br> <br>Листинг 5.6. Простой поиск соответствия <br><br> booktown=# SELECT title FROM books <br> booktown-# WHERE title - 'The'; <br> title <br> The Shining The Cat in the Hat The Velveteen Rabbit <br> The Tell-Tale Heart <br> (4 rows) <br> booktown=# SELECT title FROM books <br> booktown-f WHERE title -* 'The'; title <br> The Shining The Cat in the Hat Bartholomew and <br> the Oobleck Franklin in the Dark The Velveteen Rabbit <br> The Tell-Tale Heart <br> (6 rows) <br> Как видно из результатов, оператор ~* возвращает две дополнительные записи, поскольку выражение соответствует не только подстроке «the», но и любым модификациям в регистре символов этой подстроки (the, tHe, ThE и т. д.). <br> Если добавить в начало этого регулярного выражения символ л, оно будет соответствовать только подстроке «The», находящейся в начале исходного текста (листинг 5.7). <br> Конструкция . * обозначает любое количество произвольных символов до следующего подвыражения. В данном примере этим подвыражением является пара строк в круглых скобках (rabbit и heart), разделенных символом |, что соответствует любой из перечисленных строк. <br> <br><br> <h1>Нетривиальный поиск соответствия</h1> <br> <br>Листинг 5.7. Нетривиальный поиск соответствия <br><br> booktown=f SELECT title FROM books <br> booktown-# WHERE title -* IAThe.*(rabbit|heart)'; <br> title <br> The Velveteen Rabbit The Tell-Tale Heart <br> (2 rows) <br> Выражение AThe.*(rabbit|heart) означает следующее: соответствие находится лишь в том случае, если строка начинается с символов «The», далее идет любое количество произвольных символов, а после них следует либо подстрока «rabbit», либо подстрока «heart». Оператор ~* (вместо оператора ~) производит сравнение без учета регистра символов. <br> В листинге 5.8 приведен пример еще более сложного регулярного выражения. <br> <br><br> <h1>Сложный поиск соответствия</h1> <br> <br>Листинг 5.8. Сложный поиск соответствия <br><br> booktown=# SELECT title FROM books <br> booktown-# WHERE title ~* 'rt.*[ri]t) | (ingJjune$)' : <br> title <br> The Shining Dune <br> The Velveteen Rabbit The Tell-Tale Heart <br> (4 rows) <br> booktown=# <br> На первый взгляд регулярное выражение в листинге 5.8 выглядит устрашающе. Но если разбить его на элементы, становится видно, что оно состоит из двух выражений в круглых скобках, разделенных символом [.Таким образом, соответствие будет найдено, если хотя бы одно из этих выражений указывает на значение в поле title. <br> Продолжая анализ выражения, мы видим, что подвыражение слева от символа | состоит из следующих элементов (слева направо): метасимвол л, за которым следует символ t, затем последовательность .* и пара квадратных скобок с символами г и i, за которыми следует символ t. В переводе на русский язык это означает, что соответствие должно начинаться с буквы t, за которой следует ноль или более символов, пока не будет встречена буква г или 1, после которой немедленно следует буква t. Если хотя бы одно из этих условий не соблюдается, соответствия нет. <br> Выражение в правой части устроено проще. Оно состоит из двух литералов ing и une, разделенных очередным символом , причем за каждым литералом следует символ $. В переводе это означает, что совпадение должно заканчиваться подстрокой Ing или une. При выполнении любого (благодаря символу |) из этих условий соответствие считается найденным.<br> <br><br> <h1>Использование математических операторов</h1> <br> <br>Листинг 5.9. Использование математических операторов <br><br> booktown=# SELECT isbn, <br> booktown-# (retail / cost)::numeric(3, 2) - 1 AS margin <br> booktown-# FROM stock <br> booktowri-# ORDER BY margin DESC <br> booktown-# LIMIT 4; <br> isbn | margin <br> 0451457994 | 0.35 <br> 0760720002 | 0.33 <br> 0451198492 0.30 <br> 0441172717 | 0.29 <br> (4 rows) <br> Обратите внимание на определение временного псевдонима margin при помощи ключевого слова AS. Псевдоним представляет собой временное имя, которое существует только во время обработки запроса. <br> <br><br> <h1>Логические операторы</h1> <br> <br>Логические операторы <br><br> Ключевые слова AND, OR и NOT являются логическими (булевыми) операторами PostgreSQL. Обычно они используются для операций с логическими условиями в командах SQL, особенно в секциях WHERE и HAVING. <br> В табл. 5.7 приведена сводка результатов, возвращаемых логическими операторами AND, OR и NOT для всех возможных сочетаний операндов (true, false и NULL). <br> <br><br> <h1>Математические функции</h1> <br> <br>Математические функции <br><br> Математические функции PostgreSQL выполняют стандартные арифметические и тригонометрические операции и работают с разными типами данных. В большинстве случаев тип возвращаемого значения совпадает с типом аргументов функции. В табл. 5.9 приведена сводка основных математических функций PostgreSQL. <br> <br><br> <h1>Математические операторы</h1> <br> <br> Математические операторы <br><br> Математические операторы используются в целевых списках, в секции WHERE команды SELECT и вообще везде, где встречаются числовые данные. <br> В табл. 5.4 перечислены математические операторы PostgreSQL и приведены примеры их использования. <br> <br><br> <h1>Операторы и функции</h1> <br> <br>Операторы и функции <br><br> В этой главе рассматриваются операторы и функции PostgreSQL, то есть специальные символы и идентификаторы, предназначенные для модификации и сравнения данных в командах SQL. Результаты этих операций находят разнообразное применение, от обновления существующих записей в базе данных до ограничения результатов выборки по определенному критерию. <br> В PostgreSQL поддерживаются стандартные операторы и функции SQL, определенные в стандартах ANSI/ISO, — математические операторы, основные функции форматирования текста, выделение компонентов даты/времени и т. д. Кроме того, в PostgreSQL реализованы многочисленные нестандартные расширения, в том числе операторы поиска по регулярным выражениям и универсальная функция форматирования данных to_char(). <br> Ниже описаны встроенные операторы и функции. Одной из замечательных особенностей языка PostgreSQL является возможность его расширения в этой области. Когда вы освоите стандартные операторы и функции, вероятно, вам захочется определить свои собственные. Эта тема рассматривается в главе 7.<br> <br><br><br> <h1>Операторы и NULL</h1> <br> <br>Операторы и NULL <br><br> Если таблица содержит значения NULL, можно воспользоваться специальными операторами сравнения, чтобы учесть поля NULL при выборке или игнорировать их. Конструкция IS NULL проверяет, содержит ли поле значение NULL. Обратное условие проверяется конструкцией NOT IS NULL. <br> В листинге 5.15 конструкция IS NULL используется для поиска авторов, у которых отсутствуют данные в поле f 1 rst_name. <br> <br><br> <h1>Операторы регулярных выражений</h1> <br> <br> Операторы регулярных выражений <br><br> Если обычного сравнения строк оказывается недостаточно, в PostgreSQL предусмотрены специальные операторы для поиска совпадений по регулярным выражениям. Регулярное выражение похоже на строковую константу, с которой сравнивается исходная строка, но некоторые символы (квадратные скобки, вертикальная черта, обратная косая черта и т. д.) при сравнении интерпретируются особым образом. Если вам доводилось работать с такими программами Unix, как sed, grep или perl, возможно, вы уже знакомы с синтаксисом регулярных выражений. <br> Примечание 2 <br>Примечание 2<br><br><br> Общие сведения о регулярных выражениях приведены в книге Джеффри Фридла (Jeffrey Friedl) «Mastering Regular Expressions». <br> Регулярное выражение состоит из литералов и метасимволов (специальных символов). Обычно регулярные выражения могут совпадать с несколькими вариантами строковых значений. Пример приведен в листинге 5.5, где в таблице authors ищутся все имена (fi rstjiame), начинающиеся с символа А или Т. <br> <br><br> <h1>Операторы сравнения</h1> <br> <br> Операторы сравнения <br><br> Операторы сравнения работают со значениями таких типов, как integer или text, но всегда возвращают результат типа boo"! ean. Они часто встречаются в секции WHERE, но могут использоваться в любом контексте, в котором действителен тип boolean. Операторы сравнения PostgreSQL перечислены в табл. 5.5. <br> <br><br> <h1>Операторы</h1> <br> <br>Операторы <br><br> В главе 3 операторы SQL определялись как лексемы, предназначенные для выполнения операций с константами и идентификаторами и возвращающие результаты этих операций. Некоторые ключевые слова SQL тоже считаются операторами из-за воздействия на данные в командах SQL. В этом разделе термином «операторы» будут обозначаться как специальные символы, так и ключевые слова. Действия, выполняемые оператором, зависят от контекста его применения. Область применения операторов чрезвычайно широка, от выполнения математических операций и конкатенации строк до разнообразных сравнений. В следующем подразделе описываются общие правила применения операторов SQL, а далее подробно рассматриваются некоторые важнейшие категории операторов: <br> <ul> <li> строковые операторы; </li> <li> числовые операторы; </li> <li> логические операторы. </li> </ul> Примечание 1 <br>Примечание 1<br><br> <br> Самый «свежий» и наиболее полный список операторов PostgreSQL выводится в psql командой \do. Помните, что многие из перечисленных операторов существуют только в PostgreSQL и могут не поддерживаться в других СУБД на базе SQL. <br> После описания различных категорий операторов приводится информация о роли псевдозначений NULL в выражениях и о порядке выполнения операторов.<br> <br><br><br> <h1>Правила использования операторов</h1> <br> <br>Правила использования операторов <br><br> Оператор работает с одним операндом или с двумя операндами. Большинство операторов работает с двумя операндами, между которыми ставится сам оператор (например, а-b). Такие операторы называются бинарными. Операторы, работающие с одним операндом, называются унарными; в этом случае оператор либо предшествует операнду, либо следует за ним (например, знак @ перед значением является унарным оператором, возвращающим модуль числа). <br> Некоторые операторы имеют несколько интерпретаций в зависимости от типа данных, к которым они применяются. С другой стороны, часть операторов не имеет смысла для некоторых типов данных (дополнительная информация о типах данных PostgreSQL приведена в главе 3). <br> Например, оператор сложения (+) может использоваться для суммирования двух целочисленных величии, но он не может прибавить целое число к текстовой строке. Считается, что такой вариант использования оператора дает неопределенный результат и потому является недопустимым. При этом сам оператор (в данном случае +) опознается нормально, но PostgreSQL выводит сообщение об ошибке (вроде того, что приведено в листинге 5.2). <br> Для примера рассмотрим таблицу authors, связывающую имена авторов с числовыми кодами. <br> Таблица "authors" <br> Атрибут | Тип | Модификатор<br> id | integer not null <br> lastjiame j text firstjname 1 text <br> Индекс: authors_pkey <br> Код автора id относится к типу integer (4-байтовое целое), а фамилия автора — к типу text. Поскольку поле id относится к числовому типу, оно может использоваться в качестве операнда математического оператора с другим числовым значением. <br> В листинге 5.1 приведен пример правильного использования оператора сложения (+). <br> <br><br> <h1>возвращает арккосинус аргумента х, относящегося </h1> <br> testdb=# SELECT abs(lOO) AS abs_positive. <br> testdb-# abs(-lOO) AS absjiegative: <br> abs_positive | absjiegative <br> 100 100 <br> (1 row) <br> acos()<br> Синтаксис: <br> acos(x) <br> Функция acos () возвращает арккосинус аргумента х, относящегося к типу doubl e precision и лежащему в интервале допустимых значений косинуса (от -1 до 1). Фактически является обратной по отношению к функции cos(). Результат представляет собой угол (в радианах) в интервале от 0 до я, выраженный типом double precision. <br><br> <h1>и возвращает его экспоненту, то </h1> <br> testdb=# SELECT degrees(acos(-D) AS half_circle. <br> testdb-# degrees(pi) * 2) AS ful1_circle: <br> half_circle | full_circle <br> 180 | 360 <br> (1 row) <br> exp() <br> Синтаксис: <br> exp(x) <br> Функция получает один аргумент х типа numeri с или doubl e preci si on и возвращает его экспоненту, то есть результат возведения константы е в заданную степень. <br><br> <h1>получает один или два аргумента </h1> <br> booktown=# SELECT rpad('whitespace example'. 30): rpad <br> whitespace example (1 row) <br> booktown=# SELECT title. rpacKtitle. 12, ' -') AS right_dashed. <br> booktown-# rpad(title, 12, '-+-') AS right_plus_dashed <br> booktown-# FROM books <br> booktown-f LIMIT 3: <br> title [ right_dashed | right_plus_dashed <br> The Shining The Shining- | The Shining-Dune Dune <br> 2001: A Space Odyssey 2001: A Spac 2001: A Spac <br> (3 rows) <br> rtrim()<br> Синтаксис: <br> rtrim(s) <br> trlm(s. f) <br> Функция rtri m() получает один или два аргумента типа text (аргумент f не обязателен). Если аргумент f не задан, функция возвращает строку s, из которой удалены все завершаю nine пробелы. В противном случае удаляется завершающая подстрока, состоящая только из символов, содержащихся в f. Если такая подстрока не найдена, s остается без изменений. <br><br> <h1>и округляет его до максимального </h1> <br> testdb=# SELECT exp(O.O) AS one. <br> testdb-# exp(l.O) AS e. <br> testdb-* exp(2.0) AS "e squared": <br> one I e I e squared <br> 1 | 2.71828182845905 | 7.38905609893065 <br> (1 row) <br> floor()<br> Синтаксис: <br> floor(x) <br> Функция f 1 оог() получает один аргумент х типа numeri с и округляет его до максимального целого, не большего переданной величины. Целые числа остаются без изменений. <br><br> <h1>Функция substrO эквивалентна функции SQL92 </h1> <br> booktown=# SELECT title, strposdower(title), 'rabbit') <br> booktown-l FROM books <br> booktown-# WHERE strposdower(title), 'rabbit') != 0; <br> title | strpos <br> The Velveteen Rabbit | 15 <br> (1 row) <br> substr()<br> Синтаксис: <br> substr(s. n) substr(s. n. 1) <br> Функция substrO эквивалентна функции SQL92 substring!), но аргументы передаются ей в стиле С. Функция вызывается с двумя или тремя аргументами s, n и 1 (необязательный аргумент), относящимися к типам text, т nteger и i nteger соответственно. Возвращаемое значение представляет собой подстроку s, начинающуюся с позиции п. Необязательный аргумент 1 определяет максимальную длину подстроки в символах. <br> Если заданная длина подстроки превышает количество оставшихся символов в строке s, возвращается только остаток строки. Иначе говоря, возвращаемое значение не дополняется до заданной длины. <br><br> <h1>one one point one one </h1> <br> testdb=# SELECT floor(l.O) AS one. <br> testdb-# floor(1.1) AS "one point one", <br> testdb-# floord.8) AS "one point eight"; <br> one one point one one point eight <br> 1 | 1 | 1 <br> (1 row) <br> ln() <br> Синтаксис: <br> ln(x) <br> Функция ln(x) получает один аргумент х типа numeric или double precision и возвращает его натуральный логарифм. Фактически является обратной по отношению к функции ехр(). Эквивалентна вызову функции log() с передачей основания е. <br><br> <h1>с двумя или тремя аргументами </h1> <br> booktown=# SELECT title, substr(title, 15). substr(title. 5. 9) <br> booktown-# FROM books <br> booktown-# ORDER BY title DESC <br> booktown-# LIMIT 3; <br> title | substr | substr <br> The Velveteen Rabbit Rabbit | Velveteen <br> The Tell-Tale Heart Heart Tell-Tale <br> The Shining | | Shining <br> (3 rows) <br> substring()<br> Синтаксис: <br> substrts. n) substr(s, n. 1) <br> Функция SQL92 substring() эквивалентна функции PostgreSQLsubstr(). Функция вызывается с двумя или тремя аргументами s, n и 1 (необязательный аргумент), относящимися к типам text, integer и integer соответственно. Возвращаемое значение представляет собой подстроку s, начинающуюся с позиции п. Необязательный аргумент 1 определяет максимальную длину подстроки в символах. <br><br> <h1>получает один или два аргумента </h1> <br> testdb=# SELECT In(lO.O) AS naturaljog. <br> testdb-| log(expd.O). 10.0) AS naturaljog, <br> testdb-# In(expdO.O)) AS inverse_example: <br> naturaljog | naturaljog | inverse_example <br> 2.30258509299405 | 2.30258509299404 | 10 <br> (1 row) <br> log() <br> Синтаксис: <br> log(x) log(b.x) <br> Функция log() получает один или два аргумента типа numeric. Если передан один аргумент, возвращается его десятичный логарифм. Если переданы два аргумента, функция log(b.x) возвращает логарифм х по основанию Ь. <br><br> <h1>в строку f, заменяются символами </h1> <br> booktown=# SELECT to_ascii('Multibyte Source', 'LATIN1'); <br> to_ascii <br> Multibyte Source <br> (1 row) <br> translate()<br> Синтаксис: translate(s. f. r) <br> Функция transl ate() получает три аргумента s, f и г, относящихся к типу text. В строке s все символы, входящие в строку f, заменяются символами с тем же индексом из строки г. Возвращаемое значение относится к типу text. <br> Обратите внимание: функция заменяет не экземпляры всей строки f, а любые символы, входящие в эту строку. Если f содержит больше символов, чем г, то все символы f, не имеющие аналогов в г, просто удаляются из s (удобный способ удаления ненужных символов). <br> В следующем примере все вопросительные знаки заменяются восклицательными. <br><br> <h1>logJ2 logJ2 log 12. base </h1> <br> testdb=# SELECT log(12.0) AS logj.2. <br> testdb-# logdO. 12.0) AS logj.2. <br> testdb-# log(3, 12.0) AS "log 12. base 3"; <br> logJ2 logJ2 log 12. base 3 <br> 1.07918124604762 | 1.0791812460 | 2.2618595071<br> (1 row) <br> mod() <br> Синтаксис: <br> mod(x.y) <br> Функция mocK) получает два аргумента х и у, относящихся к числовым типам numeric, Integer, smallint или bigint. Возвращаемое значение представляет собой остаток от деления х на у. <br><br> <h1>В следующем примере все вхождения </h1> <br> booktown=# SELECT translated am an example?', '?', '!'): <br> translate <br> I am an example! <br> (1 row) <br> В следующем примере все вхождения символа «i» заменяются символом «w», а все вхождения символа «s» — символом «а». Лишний символ в конце строки «was» игнорируется. <br><br> <h1>и возвращает константу п, примерно </h1> <br> testdb=# SELECT mod(5. 5) AS no_remainder. <br> testdo-# mod(6, 5) AS remainder_one, <br> mod(19. 5) AS remainder_four; <br> no_remainder | rema1nder_one | remainder_four <br> 0 | 1 | 4 <br> (1 row) <br> pi() <br> Синтаксис: <br> pi()<br> Функция pi () вызывается без аргументов и возвращает константу п, примерно равную 3,14159265358978. <br><br> <h1>В последнем примере все гласные </h1> <br> booktown=# SELECT translate('This is a mistake.', 'is', 'was');<br> translate <br> Thwa wa a mwatake. <br> (1 row) <br> В последнем примере все гласные буквы заменяются пустой строкой, то есть удаляются из входной строки. <br><br> <h1>i on. Возвращаемое значение представляет </h1> <br> testdb=# SELECT pi() AS "the pi constant": <br> the pi constant <br> 3.14159265358979 <br> (1 row) <br> pow() <br> Синтаксис: <br> pow(x.y) <br> Функция pow() получает два аргумента х и у, относящихся к числовым типам numeri с или doubl e preci s i on. Возвращаемое значение представляет собой результат возведения х в степень у. Тип данных результата совпадает с типом переданных аргументов. Следует помнить, что аргументы должны содержать десятичную точку. <br><br> <h1>The Cat In the Hat </h1> <br> booktown=# SELECT title. <br> booktown-# translateCtitle, 'aeiouAEIOU', '') AS vowelless <br> booktown-# FROM books <br> booktown-f LIMIT 5; <br> title | vowelless <br> The Shining Th Shnng <br> Dune I Dn <br> 2001: A Space Odyssey | 2001: Spc dyssy <br> The Cat In the Hat | Th Ct n th Ht <br> Bartholomew and the Oobleck Brthlmw nd th blck <br> (5 rows) <br> trim() <br> Синтаксис: <br> trim(направление f FROM s) <br> Функция SQL92 trim() способна заменить функции PostgreSQL rtrim(), ltrim() и btrim(). При вызове она получает три аргумента: ключевое слово (LEADING, TRAILING или BOTH) и две строки, f и s. <br> С ключевым словом LEADING функция trim() работает аналогично функции ItrimO, удаляя в начале строки s наибольшую подстроку, все символы которой входят в f. <br> С ключевым словом TRAILING функция trim() работает аналогично функции rtrim(), удаляя в конце строки s наибольшую подстроку, все символы которой входят в f. <br> С ключевым словом BOTH функция trim() работает аналогично функции btrim(), удаляя в начале и в конце строки s наибольшие подстроки, все символы которых входят в f. <br><br> <h1>d типа double precision, представляющий </h1> <br> testdb=# SELECT pow(2.0, 3.0) AS "two cubed". <br> testdb-# pow(2.0, 2.0) AS "two squared". <br> testdb-# pow(2.0, 1.0) AS "just two"; <br> two cubed | two squared just two <br> 8 | 4 2 <br> (1 row) <br> radlans()<br> Синтаксис: <br> radians(d) <br> Функция radians () получает аргумент d типа double precision, представляющий угол в градусах, и преобразует его в радианы. Возвращаемое значение относится к типу double precision. Фактически функция radiansO является обратной по отношению к функции degrees (). <br><br> <h1>ORDER BY id ASC </h1> <br> booktown=# SELECT title, upper(title) <br> booktown-# FROM books <br> booktown-# ORDER BY id ASC <br> booktown-# LIMIT 3; <br> title | upper <br> The Tell-Tale Heart | THE TELL-TALE HEART <br> Little Women j LITTLE WOMEN <br> The Velveteen Rabbit | THE VELVETEEN RABBIT <br> (3 rows) <br><br> <h1>и возвращает псевдослучайное число типа </h1> <br> testdb=# SELECT radians(180) AS ha1f_circle. <br> testdb-# radians(360) AS fu11_circle; <br> half_circle | full_cnrcle <br> 3.14159265358979 | 6.28318530717959 <br> (1 row) <br> random ()<br> Синтаксис: <br> randon ()<br> Функция random() вызывается без аргументов и возвращает псевдослучайное число типа double precision в интервале от 0,0 до 1,0. При каждом вызове randonK) генерируется новое значение, даже если функция вызывается несколько раз в одном запросе. <br> Обычно функция random() используется в сочетании с математическими операторами (например, + и *) для получения псевдослучайных чисел в заданном интервале и последующим вызовом одной из функций округления (roundC), trunc() и т. д.). <br><br> <h1>SELECT randonK) AS natural random, </h1> <br> testdb=# SELECT randonK) AS natural random, <br> testdb-# round(randomO * 9) + I AS one_through_ten. <br> testdb-# truncC randonK) * 99) + 1 AS one_through_one_hundred: <br> natural_random | one_through_ten | one_through_one_hundred <br> 0.478887704424042 | 2 | 37 <br> (1 row) <br> round ()<br> Синтаксис: <br> round(x) round(x.s) <br> Функция roundO вызывается с одним или с двумя аргументами. Первый аргумент х относится к типу numeric или double precision и определяет округляемое число. Второй необязательный аргумент s относится к типу integer и определяет количество цифр в дробной части после округления. Тип возвращаемого значения совпадает с типом первого аргумента. <br> Если значение аргумента s больше количества цифр в дробной части х, недостающие позиции заполняются нулями. <br><br> <h1>Функция получает один или два </h1> <br> booktown=# SELECT asciitТ); ascii <br> 84 <br> (1 row) <br> booktown=# SELECT DISTINCT ON (substr) <br> booktown-# title. substrCtitle, 1, 1), <br> booktown-# ascii(tltle) <br> booktown-# FROM books <br> booktOMl-f ORDER BY substr ASC:<br> title | substr ascii <br> 2001: A Space Odyssey | 2 | 50 <br> Bartholomew and the Oobleck j В I 66 <br> Dune |D 68 <br> Franklin in the Dark | 70 <br> Goodnignt Moon | G j 71 <br> Little Women L 76 <br> Practical PostgreSQL | P j 80 <br> The Shining Т 84 <br> (8 rows) <br> btrim() <br> Синтаксис: <br> btrim(s) btrim(s. t) <br> Функция получает один или два аргумента типа text, второй аргумент t не является обязательным. Если аргумент t задан, функция удаляет в начале и в конце строки s все символы, входящие в строку t. Если функция вызвана с одним аргументом, удаляются начальные и конечные пропуски — пробелы, символы табуляции и т. д. <br> Порядок перечисления символов в строке t для функции btrim() значения не имеет. В начале и конце строки s удаляются подстроки, полностью состоящие из символов, входящих в строку t. <br><br> <h1>Функция current_time вызывается без аргументов </h1> <br> booktown=# SELECT current_date, <br> booktown-# 'now'::date AS date; <br> date date <br> 2001-08-31 | 2001-08-31 <br> (1 row) <br> current_time <br> Синтаксис: <br> current_time <br> Функция current_time вызывается без аргументов и возвращает текущее время в виде значения типа time. Результат эквивалентен преобразованию специальной константы now к типу time. <br><br> <h1>фактически является обратной по отношению </h1> <br> booKtown=# SELECT bitfronrint4(16385); <br> bitfromint4 <br> 00000000000000000100000000000001 <br> (1 row) <br> bittoint4() <br> Синтаксис: <br> bittoint4(b) <br> Функция bittoint4() фактически является обратной по отношению к bitfromint4() — она получает один аргумент b тина bit п возвращает его десятичное числовое значение в виде тина integer. <br> Соответственно аргумент функции bitfrwint4() содержит до 32 двоичных цифр, а возвращаемое значение лежит в интервале от -2 147 483 648 до 2 147 483 647. <br><br> <h1>возвращает арксинус аргумента х, относящегося </h1> <br> testdb=# SELECT acos(l). acos(O), <br> acos(-l). testdb-# acos(cosd)) AS inverse_example: <br> acos | acos | acos | inverse_example <br> 0 | 1.5707963267949 | 3.14159265358979 | <br> (1 row) <br> asin()<br> Синтаксис: <br> asln(x) <br> Функция as1n() возвращает арксинус аргумента х, относящегося к типу double jrecisi on и лежащему в интервале допустимых значений синуса (от -1 до 1). Факти-lecKii является обратной по отношению к функции sin(). Результат представляет со-юй угол (в радианах) в интервале от -я/2 до л/2, выраженный типом doubl e preci s I on. <br><br> <h1>e preci si on, представляющий </h1> <br> testdb=# SELECT round(l.O) AS one, <br> testdb-# round(l.l) AS "one point one", <br> testdb | round(1.5) AS "one point five", <br> testdb-# roundd.8) AS "one point eight"; <br> one | one point one | <br> one point five | one point eight <br> 1 | 1 | 2 | 2 <br> (1 row) <br> testdb=# SELECT round(1.4949. 1) AS one_digit_scale.<br> testdb-# roundd.4949, 3) AS three_digit_scale. <br> testdb-# roundd.4949, 10) AS ten_digit_scale. <br> testdb-# roundd.4949. 0) AS rounded; <br> one_digit_scale | three_digit_scale | ten_digit_scale rounded <br> 1.5 1.495 | 1.4949000000 1 <br> (1 row) <br> Sin() <br> Синтаксис: <br> Sin(x) <br> Функция si n () получает один аргумент х типа doubl e preci si on, представляющий угол в радианах, и возвращает синус этого угла в виде значения типа doubl e preci si on. <br><br> <h1>х типа double precision или </h1> <br> testdb=# SELECT sin(pi() / 4) AS quarter_pi, <br> testdb-# sin(pi() / 2) AS half_pi: <br> quarter_pi | half_pi <br> 0.707106781186547 | <br> (1 row) <br> sqrt() <br> Синтаксис: <br> sqrt() <br> Функция sqrt() получает один числовой аргумент х типа double precision или lumeric и возвращает квадратный корень, при этом тип возвращаемого значения ювпадает с типом аргумента. Фактически является обратной по отношению к Ьункции pow(), выполняющей возведение во вторую степень. <br><br> <h1>e preci si on, представляющий </h1> <br> estdb=# SELECT sqrt(2.0), sqrt(4.0), <br> estdb-# sqrt(pow(2.0, 2)) AS inverse_example: <br> sqrt | sqrt | inverse_exampl <br> 1.4142135623731 2 | 2 <br> (1 row) <br> tan() <br> Синтаксис: <br> tan(x) <br> Функция tan() получает один аргумент х типа doubl e preci si on, представляющий тол в радианах, и возвращает тангенс этого угла в виде значения типа doubl e preci s i on. <br><br> <h1>с двумя аргументами. Первый аргумент </h1> <br> testdb=# SELECT tan(pi() / 8). <br> testdb-# tan(O): tan | tan <br> 0.414213562373095 | <br> (1 row) <br> trunc()<br> Синтаксис: <br> trunc(x) trunc(x.s) <br> Функция trunc() вызывается с одним или с двумя аргументами. Первый аргумент х относится к типу numeric или double precision и определяет исходное число. Второй необязательный аргумент s относится к типу integer и определяет количество цифр в дробной части после усечения. <br> Если аргумент s не задан, отсекаются все цифры в дробной части числа. Если значение аргумента s больше количества цифр в дробной части х, недостающие позиции заполняются нулями. <br><br> <h1>AS one_decima1_point, </h1> <br> testdb=# SELECT trunc(1.598) AS natural-truncation. <br> testdb-# trunc(1.598. 1) AS one_decima1_point, <br> testdb-# trunc(1.598, 8) AS extra_places: <br> natural_truncation one_decimal_point | extra_places <br> 1 | 1.5 | 1.59800000 <br> (1 row) <br><br> <h1>Функция SQL92 char_l engthC) получает </h1> <br> booktown=# SELECT btrimC whitespace example ') AS trim_blanks, <br> booktown-# btr1m('123example 332', '123') AS trimjnumbers: <br> trim_blanks | trim_numbers <br> whitespace example example <br> (1 row) <br> char_length() <br> Синтаксис: <br> charjength(s) <br> Функция SQL92 char_l engthC) получает один аргумент s типа text, varchar или character и возвращает длину полученной строки в символах. Возвращаемое значение относится к типу integer. <br><br> <h1>Функция current_timestamp вызывается без аргументов </h1> <br> booktown=# SELECT current_time, <br> booktown-# 'now'::time AS time; <br> time | time <br> 11:36:52 | 11:36:52 <br> (1 row) <br> current_timestamp <br> Синтаксис: <br> current_timestamp <br> Функция current_timestamp вызывается без аргументов и возвращает текущее время в виде значения типа timestamp. Результат эквивалентен преобразованию специальной константы now к типу timestamp или вызову функции now(). <br><br> <h1>f типа text, форматирует число </h1> <br> booktown=# SELECT bittoint4(B'101010'). <br> booktown-# Mttoint4(bitfromint4(99)) <br> AS inverse_example: bittoint4 inverse_example <br> 42 | 99 <br> (1 row) <br> to_char() для чисел <br> Синтаксис: <br> to_char(n. f) <br> Функция to_char(), вызываемая с аргументом п типа numeri с и аргументом f типа text, форматирует число п в строку типа text. Строка f описывает формат выходного значения. <br> Форматная строка f состоит из метасимволов, вместо которых PostgreSQL подставляет представляемые ими значения. Метасимволы, используемые в форматных строках, перечислены в табл. 5.14. <br><br> <h1>О возвращает арктангенс аргумента х, </h1> <br> testdb=# SELECT asin(l), asin(O), asin(-l), <br> testdb-# asin(sind)) AS inverse_examp1e; <br> asin | asin [ asin [ lnverse_example <br> 1.5707963267949 0 | -1.5707963267949 | 1 <br> (1 row) <br> itan()<br> Синтаксис: <br> itan(x) <br> Функция atari О возвращает арктангенс аргумента х, относящегося к типу doubl e )reci slon. Фактически является обратной по отношению к функции tan(). Результат представляет собой угол (в радианах) в интервале от -л/2 де я/2, выраженный типом double precision. <br><br> <h1>равным п. Возвращаемое значение относится </h1> <br> booktown=# SELECT charjength(title). title <br> booktown-l FROM books Dooktown-# LIMIT 3: charjength | title <br> 11 | The Shining <br> 4 Dune <br> 21 I 2001: A Space Odyssey <br> (3 rows) <br> chr() <br> Синтаксис: chr(n) <br> Функция chr() получает один числовой аргумент п типа integer и возвращает символ с ASCII-кодом, равным п. Возвращаемое значение относится к типу text. Функция chr() фактически является обратной по отношению к функции asci 1 (). <br><br> <h1>получает два аргумента. Первый аргумент </h1> <br> booktown=# SELECT current_timestamp. <br> booktown-# now() AS timestamp; <br> timestamp | timestamp <br> 2001-08-31 11:39:42-07 2001-08-31 11:39:42-07 <br> (1 row) <br> date_part() <br> Синтаксис: <br> date_part(s. t) date_part(s. i) <br> Функция date_part() получает два аргумента. Первый аргумент s относится к типу text, а второй, t или I, — к типу timestamp или interval соответственно. Функция выделяет во втором аргументе компонент, определяемый строкой s, и возвращает его в виде значения типа doubl e preci si on. <br> Чтобы лучше понять, как работает функция date_part(), представьте, что значение типа timestamp или interval делится на компоненты — часы, минуты и т. д. Эти компоненты (и соответственно допустимые значения аргумента s) перечислены в табл. 5.12. Помните, что некоторые значения относятся только к типу tlmestamp и не поддерживаются для типа Interval. <br><br> <h1>Модификатор FM имеет важное значение </h1> <br> booktown=# SELECT timestamp('197825thJuly01:12am') <br> booktown-# AS non_standard_timestamp, <br> booktown-l to_fimestamp('197825July01:12am', <br> booktown(# 'YYYYDDFMMonthHH12:MIam') <br> booktown-# AS correcMnterpretation; <br> non_standard_timestamp | correctjnterpretation <br> 2025-06-27 01:12:00-07 1978-07-25 01:12:00-07 <br> (1 row) <br> Примечание 3 <br>Примечание 3<br><br> Модификатор FM имеет важное значение для правильной интерпретации данных, следующих за названием месяца или дня недели, поскольку эти названия часто дополняются пробелами до 9 символов. Помните, что модификатор FM не является глобальным — он должен предшествовать каждом/элементу, к которому он применяется. <br> timestamp()<br> Синтаксис: <br> timestamp(d) timestamptd, t) <br> Функция ti mestampC) получает либо один аргумент типа date, либо два аргумента типов date и time соответственно. Переданные аргументы преобразуются в значение типа tlmestamp и возвращаются функцией. При передаче одного аргумента предполагается, что время соответствует полуночи заданной даты. <br><br> <h1>возвращает арктангенс, то есть угол </h1> <br> testdb=# SELECT atan(l). atan(O). atan(-l), <br> testdb-# atan(tand)) AS inverse_example; <br> atan atan | atan | inverse_example <br> 0.785398163397448 | 0 | -0.785398163397448 | 1 <br> (1 row) <br> itan2()<br> Синтаксис: <br> 3tari2(x.y) <br> По аналогии с функцией atan(), функция atan2() возвращает арктангенс, то есть угол (в радианах) в интервале от -я/2 до я/2, выраженный типом doubl e preci si on. Однако в отличие от atan() она получает два аргумента типа double precision вместо одного и возвращает арктангенс величины, полученной делением первого аргумента на второй. <br> В общем случае вызов функции atan2(x,y) эквивалентен вызову atan(x/y), но при передаче аргумента у=0 функции atan2() не происходит ошибки деления на ноль, как при вызове atan() для величины х/у. Если аргумент у равен нулю, функция atan2() возвращает я/2 для положительных значений х, -я/2 для отрицательных х и 0 для х=0. <br><br> <h1>s типа text, varchar или </h1> <br> booktown=# SELECT initcapCa prospective book title'): <br> initcap <br> A Prospective Book Title <br> (1 row) <br> length()<br> Синтаксис: <br> length(s) <br> Аналог функции SQL92 charj ength(). Получает один аргумент s типа text, varchar или character и возвращает длину полученной строки в символах в виде значения типа integer. <br><br> <h1>Функция SQL92 extractO представляет собой </h1> <br> booktown=# SELECT date_trune('minute', now()); <br> date trunc <br> 2001-08-31 09:59:00-07 <br> (1 row) <br> booktown=# SELECT date_trunc( 'hour', now()); <br> date trunc <br> 2001-08-31 09:00:00-07 (1 row) <br> booktown=# SELECT date_trunc('year', now()); <br> date trunc <br> 2001-01-01 00:00:00-08 <br> (1 row) <br> extract()<br> Синтаксис: <br> extract(k FROM t) extract(k FROM 1) <br> Функция SQL92 extractO представляет собой аналог функции PostgreSQL date_part() со слегка измененным синтаксисом. При перечислении аргументов вместо запятой используется ключевое слово FROM. Аргументы аналогичны аргументам функции date_part(), хотя первый аргумент является ключевым словом SQL, а не строкой и поэтому не заключается в кавычки. Допустимые значения k перечислены в табл. 5.12. <br> Учтите, что функция extractO является «псевдонимом» функции PostgreSQL date_part () в синтаксисе SQL92, поэтому по умолчанию в выходных данных функция extract() представляется именем date_part. <br><br> <h1>AS today_at_midnight, </h1> <br> booktown=# SELECT timestamp(date('now')) <br> AS today_at_midnight, <br> booktown-# timestamp(dateCnow'), <br> booktownd time('now')) AS right_now; <br> today_at_m1dnight | rightjiow <br> 2001-09-01 00:00:00-07 | 2001-09-01 18:04:16-07 <br> (1 row) <br><br> <h1>и возвращает кубический корень, также </h1> <br> testdb=# SELECT atan2(0, 1). atan2(l, 1), <br> testdb-# atanCO / 1) AS functionally. <br> testdb-# atand / 1) AS identical; <br> atan2 atan2 | functionally identical <br> 0 i 0.785398163397448 | 0 | 0.785398163397448 (1 row) <br> testdb=# SELECT atan2(l, 0) AS positive_x. <br> testdb-# atan2(-l, 0) AS negative_x, <br> testdb-# atan2(0, 0) AS zero_x, <br> testdb-i pi() / 2 AS pi_over_two: <br> positive_x | negative_x | zero_x \ pi_over_two <br> 1.5707963267949 | -1.5707963267949 | 0 | 1.5707963267949 <br> (1 row) <br> cbrt() <br> Синтаксис: <br> cbrt()<br> Функция cbrt () получает один числовой аргумент х типа doubl e preci si on и возвращает кубический корень, также представленный типом double precision. Фактически является обратной по отношению к функции pow(), выполняющей возведение в третью степень. <br><br> <h1>В стандарт SQL92 включены две </h1> <br> booktown=# SELECT length(title), title <br> booktown-# FROM books <br> booktown-# LIMIT 3; length title <br> 11 | The Shining 4 I Dune <br> 21 | 2001: A Space Odyssey <br> (3 rows) <br> Примечание 1 <br>Примечание 1<br><br> В стандарт SQL92 включены две функции определения длины строки: char_length() и octet_length(). Следовательно, эти две функции с большей, чем функция length(), вероятностью будут поддерживаться другими реляционными СУБД. <br> like() и ilike() <br> Синтаксис: <br> s like (f) s LIKE f like(s.f) s ilike(f) s HIKE f <br> Функция 1 i ke() проверяет, совпадает ли выражение, заданное аргументом f, со строкой s. При вызове функции либо передаются два аргумента типа text, либо используется специальный синтаксис SQL, в котором аргумент s предшествует имени функции. Функция 11 i ke() является нестандартной версией функции 11 ke(), игнорирующей регистр символов при сравнении, и вызывается только в синтаксисе SQL. <br> Примечание 2 <br>Примечание 2<br><br> Ключевое слово SQL LIKE в PostgreSQL заменяется вызовом функции likeO. Возможность использования ключевого слова LIKE без круглых скобок — всего лишь синтаксическое удобство, на практике оба варианта эквивалентны. <br> Использование функции 1 ike() отличается от обычного сравнения с помощью оператора =, поскольку строка f может содержать символы подчеркивания (_) или процента (%), интерпретируемые особым образом. PostgreSQL интерпретирует символ _ как один произвольный символ, а символ % — как ноль или более произвольных символов. Эти специальные символы могут находиться в любом месте строки f. <br> В PostgreSQL существуют и более совершенные средства поиска по шаблону, о которых говорилось в пункте «Операторы регулярных выражений» подраздела «Строковые операторы» раздела «Операторы» этой главы. <br><br> <h1>в виде значения типа timestamp. </h1> <br> booktown=# SELECT isfinite('now'::timestamp) AS now_is_finite, <br> booktown-# isfinite('infinity'::timestamp) AS Infinity, <br> booktown-# isfiniteC'invalid'::timestamp) AS invalid; <br> now_is_finite | infinity | invalid <br> (1 row) <br> now() <br> Синтаксис: <br> now() <br> Функция now() вызывается без аргументов и возвращает текущую дату и время в виде значения типа timestamp. <br><br> <h1>получает один числовой аргумент х, </h1> <br> testdb=# SELECT pow(2.0. 3) AS "two cubed". <br> testdb-# cbrt(8.0) AS "eight's cube root"; <br> two cubed | eight's cube root <br> 8 | 2 <br> (1 row) <br> ceil()<br> Синтаксис: <br> ceil(x) <br> Функция cei 1 () получает один числовой аргумент х, относящийся к любому из числовых типов данных (numeric, bigint, smallint, real или double precision), и округляет его до минимального целого, не меньшего переданной величины. Целые числа остаются без изменений. <br><br> <h1>с двумя или тремя аргументами </h1> <br> booktown=# SELECT lower(title) <br> booktown-# FROM books <br> booktown-# LIMIT 3; <br> lower <br> tne shining <br> dune <br> 2001: a space odyssey <br> lpad() <br> Синтаксис: <br> lpad(s. n) 1pacl(s. n. c) <br> Функция lpad() вызывается с двумя или тремя аргументами s, n и с (необязательный аргумент), относящимися к типам text, Integer и text соответственно. Строка s дополняется слева до длины n символов пробелами или содержимым необязательного аргумента с. <br> Если начальная длина строки s больше п, строка усекается справа до длины п. <br><br> <h1>и дату. Она похожа на </h1> <br> booktown=# SELECT now(); <br> now <br> 2001-08-31 10:31:18-07 <br> (1 row) <br> timeofday()<br> Синтаксис: timeofdayO <br> Функция timeofday() вызывается без аргументов и возвращает текущие время и дату. Она похожа на функцию now(), но возвращает значение типа text. Это делает ее менее удобной, поскольку значение не разделяется на компоненты функциями date_part() и to_char() без предварительного преобразования к другому типу. <br><br> <h1>х типа double precision, представляющий </h1> <br> testdb=# SELECT ceil(1.0). ceil(1.1), ceil(1.5); <br> ceil | ceil ceil <br> 1 | 2 | 2 <br> (1 row) <br> COS() <br> Синтаксис: <br> COSU) <br> Функция cos О получает один аргумент х типа double precision, представляющий угол в радианах, и возвращает косинус этого угла в виде типа doubl e preci si on. <br><br> <h1>SELECT title. IpadCtitle, 12, AS </h1> <br> booktown=# SELECT title. IpadCtitle, 12, AS dashed, <br> booktown-# IpadCtitle. 12. '-+-') AS pius_dashed <br> booktown-# FROM books LIMIT 4; <br> title | dashed | plus_dashed _<br> The Shining | -The Shining | -The Shining <br> Dune |Dune Dune <br> 2001: A Space Odyssey | 2001: A Spac | 2001: A Spac <br> The Cat in the Hat | The Cat in t | The Cat in t <br> (4 rows) <br> Itrim()<br> Синтаксис: <br> Itrim(s) ItrimCs. f) <br> Функция 11 ri m() получает один или два аргумента типа text (аргумент f не обязателен). Если аргумент f не задан, функция возвращает строку s, из которой удалены все начальные пробелы. В противном случае удаляется начальная подстрока, состоящая только из символов, содержащихся в f. Если такая подстрока не найдена, s остается без изменений. <br><br> <h1>Fn Aug 31 </h1> <br> Dooktown=# SELECT timeofday(); <br> timeofday <br> Fn Aug 31 10:33:00.837338 2001 PDT <br> (1 row) <br><br> <h1>х типа double precision, представляющий </h1> <br> testdb=# SELECT cos (pi О) AS cosj>i. <br> testdb-# cos(O) AS cos_zero: <br> cos_pi | cos_zero <br> 1 | 1 <br> (1 row) <br> cot() <br> Синтаксис: <br> cot(x) <br> Функция cot() получает один аргумент х типа double precision, представляющий угол в радианах, и возвращает котангенс этого угла в виде типа doubl e preci s i on. Аргумент должен быть отличным от нуля. <br><br> <h1>The Cat in the Hat </h1> <br> booktown=# SELECT title, positiorK'the' IN title) AS the_pos <br> booktown-# FROM books <br> booktown-# WHERE positionCthe1 IN title) != 0: <br> title | the_pos <br> The Cat in the Hat | 12 <br> Bartholomew and the Oobleck | 17 <br> Franklin in the Dark 13 <br> (3 rows) <br> repeat()<br> Синтаксис: repeat(s. n) <br> Функция repeat О получает два аргумента s и п, относящихся к типам text и integer соответственно. Функция возвращает символьную строку s, повторенную п раз, в виде значения типа text. <br><br> <h1>г типа double precision, представляющий </h1> <br> testdb=# SELECT cot(l). cot(-l): <br> cot cot <br> 0.642092615934331 | -0.642092615934331 <br> (1 row) <br> degrees()<br> Синтаксис: <br> degrees(r) <br> Функция degreesO получает аргумент г типа double precision, представляющий угол в радианах, и преобразует его в градусы. Возвращаемое значение относится к типу double precision. Фактически функция degreesO является обратной по отношению к функции radians(). <br><br> <h1>Функция rpadO похожа на функцию </h1> <br> booktown=# SELECT repeat(lastjname. 2) <br> booktown-l FROM authors booktown-# LIMIT 3; repeat <br> DenhamDenham BourgeoisBourgeois BiancoBianco <br> (3 rows) <br> rpad()<br> Синтаксис: <br> rpad(s. n) rpad(s. n. c) <br> Функция rpadO похожа на функцию IpadO, но дополняет строку справа, а не слева. Она вызывается с двумя или тремя аргументами s, n и с (необязательный аргумент), относящимися к типам text, integer и text соответственно. Строка s дополняется справа до длины п символов пробелами или содержимым необязательного аргумента с. <br> Если начальная длина строки s больше п, строка усекается слева до длины п. <br><br> <h1>Функция initcapO получает один аргумент </h1> <br> booktowrHf SELECT chr(65), ascii('A'); <br> chr ! ascii <br> A | 65 <br> (1 row) <br> initcap()<br> Синтаксис: initcap(s) <br> Функция initcapO получает один аргумент s типа text, преобразует первые буквы всех слов к верхнему регистру и возвращает полученную строку. В данном контексте «словом» считается любая последовательность символов, отделенная от других слов пробелами. <br><br> <h1>получает два аргумента типа text. </h1> <br> booktown=# SELECT to_char(now(). 'HH:MI PM1) AS the_time; <br> the_time <br> 05:04 PM <br> (1 row) <br> booktown=# SELECT to_char(now(), 'Dy (Day), Mon (Month)') <br> booktown-# AS abbreviations, <br> booktown-# to_char('yesterday'::timestamp, 'FMMonth FMDDth') <br> booktown-# AS yesterday. <br> booktown-# to_char('yesterday':itimestamp, 'FMDDth FMMonth') <br> booktown-# AS "yesterday UK"; <br> abbreviations | yesterday j yesterday UK <br> Sat (Saturday ). Sep (September) | August 31st | 31st August <br> (1 row) <br> booktown=# SELECT isbn, <br> booktown-# to_char(publication, 'FMMonth FMDDth, YYYY') <br> booktown-# AS informal, <br> booktown-# to_char(publication, 'YYYY-MM-DD') AS formal, <br> booktown-# to_char(publication. 'Y.YYY "years" A.D.') <br> booktown-# AS firstj)ublished <br> booktown-# FROM editions LIMIT 3; <br> isbn | informal | formal first_pub1ished <br> 039480001X | March 1st. 1957 1957-03-01 1.957 years A.O. <br> 0451160916 | August 1st. 1981 | 1981-08-01 | 1.981 years A.D. <br> 0394800753 | March 1st. 1949 | 1949-03-01 | 1.949 years A.D. <br> (3 rows) <br> to date() <br> Синтаксис: <br> to_date(s. f) <br> Функция to_date() получает два аргумента типа text. Аргумент f описывает формат даты, представленной строкой s, и содержит метасимволы из табл. 5.15. Результат возвращается в виде значения типа date. <br> В PostgreSQL поддерживается много распространенных форматов данных, однако предусмотреть все форматы невозможно. Функция to_date() гарантирует, что практически любой формат даты, описываемый метасимволами из табл. 5.14, может быть преобразован в значение типа date. <br> Пример<br> booktown=# SELECT date('198025thJune') <br> booktown-f AS non_standard_date_format, <br> booktown -# toJate (' 198025thJune', ' YYYYDDthMonth')<br> booktown-# AS correct_interpretation; <br> non_standard_date_format correct_interpretation <br> 2025-08-27 | 1980-06-25 <br> (1 row) <br> to_number() <br> Синтаксис: <br> to_number(s. f) <br> Функция to_number() получает два аргумента типа text. Аргумент f описывает формат числа, представленного строкой s, и содержит метасимволы из табл. 5.14. Результат возвращается в виде значения типа numeric. <br><br> <h1>получает два аргумента типа text. </h1> <br> booktown=# SELECT to_number('$2,900.00', 'L9G999D99') <br> booktown-# AS monetary: monetary <br> 2900.00 (1 row) <br> booktown=# SELECT tojiumber('123.456.789.00' . '999G999G999D99') <br> booktown-# AS formatted, <br> booktown-# to_numberС123456789'. '999999999') <br> booktown-# AS just_digits, <br> booktown-# to_number('00123456789'. '00999999999') <br> booktown-# AS leading_zeroes; <br> formatted | just_d1gits | leading_zeroes <br> 123456789.00 123456789 | 123456789 <br> (1 row) <br> to_timestamp()<br> Синтаксис: <br> to_timestamp(s. f) <br> Функция to_timestamp() получает два аргумента типа text. Аргумент f описывает формат даты/времени, представленного строкой s, и содержит метасимволы из табл. 5.15. Результат возвращается в виде значения типа date. <br> Эта функция, как и to_date(), прежде всего обеспечивает возможность правильной интерпретации нестандартных строк, содержащих дату и время. <br><br> <h1>FROM stock JOIN editions USING </h1> <br> booktown=# SELECT avg(cost) AS average_cost, <br> booktown-# avg(retail) AS average_price, <br> booktown-# avg(retail - cost) AS average_profit <br> booktown-# FROM stock: <br> average_cost | average_price | average_prof1t <br> 24.8235294118 | 30.0088235294 5.1852941176 <br> (1 row) <br> x>oktown=# SELECT avg(cost) <br> AS average_cost, p.name AS publisher <br> booktown-# FROM stock JOIN editions USING (isbn)) <br> booktown-l JOIN publishers AS p (publisheMd) <br> booktown-# USING (publisheMd) <br> booktown-# GROUP BY p.name; <br> average_cost | publisher <br> 26.5000000000 | Ace Books <br> 19.0000000000 | Books of Wonder <br> 26.5000000000 I Doubleday <br> 25.0000000000 | HarperCollins <br> 18.0000000000 | Henry Holt & Company. Inc. <br> 23.0000000000 I Kids Can Press <br> 23.0000000000 | Mojo Press <br> 20.0000000000 I Penguin <br> 23.0000000000 Random House <br> 26.5000000000 | Roc <br> 26.0000000000 | Watson-Guptill Publications <br> (11 rows) <br> count()<br> Синтаксис: <br> count(выражение) <br> Функция countO возвращает количество значений, для которых выражение отлично от NULL. Тип выражения не ограничивается. Следует помнить, что функция count () подсчитывает только значения, отличные от NULL, поэтому для получения осмысленных результатов используемое выражение не должно возвращать NULL для подсчитываемых записей. <br> Если при вызове count() передается символ *, функция просто подсчитывает все записи, в том числе и содержащие NULL. <br><br> <h1>FROM editions JOIN publishers AS </h1> <br> booktown=# SELECT countC*) FROM editions; <br> count <br> 17 <br> (1 row) <br> booktown=# SELECT count(isbn). p.name <br> booktown-# FROM editions JOIN publishers AS p (publisheMd) <br> booktown-# USING (publisheMd) <br> booktown-# GROUP BY p.name <br> booktown-# ORDER BY count DESC; <br> count | name <br> 3 | Random House <br> 2 | Ace Books <br> 2 | Doubleday <br> 2 Roc <br> 1 | Books of Wonder <br> 1 | HarperCollins <br> 1 | Henry Holt & Company. Inc. <br> 1 | Kids Can Press <br> 1 | Mojo Press <br> 1 | O'Reilly & Associates <br> 1 | Penguin <br> 1 | Watson-Gupti11 Publications <br> (12 rows) <br> max() <br> Синтаксис: <br> max(выражение) <br> Функция max() возвращает максимальное значение заданного выражения в группе. Результатом выражения может быть значение любого числового или строкового типа, а также типа даты или времени. Тип возвращаемого значения совпадает с типом выражения. <br><br> <h1>возвращает минимальное значение заданного выражения </h1> <br> booktown=# SELECT max(cost), max(retail) FROM stock; <br> max max <br> 36.00 I 46.95 <br> (1 row) <br> booktown=# SELECT max(retail), p.name <br> booktown-# FROM (stock NATURAL JOIN editions) <br> booktown-# JOIN publishers AS p (publisher_id) <br> booktown-# USING (publisherjd) <br> booktown-# GROUP BY p.name <br> booktown-# ORDER BY max DESC; <br> max | name <br> 46.95 | Roc <br> 45.95 i Ace Books 36.95 Doubleday 32.95 <br> Random House 28.95 HarperCollins <br> 28.95 I Watson-Guptill Publications <br> 24.95 | Mojo Press <br> 24.95 | Penguin <br> 23.95 1 Henry Holt & Company. Inc. 23.95 <br> Kids Can Press 21.95 Books of Wonder <br> (11 rows) <br> min() <br> Синтаксис: <br> min (выражение) <br> Функция min() возвращает минимальное значение заданного выражения в группе. Результатом выражения может быть значение любого числового или строкового типа, а также типа даты или времени. Тип возвращаемого значения совпадает с типом выражения. <br><br> <h1>О получает выражение, описывающее значения </h1> <br> booktown=# SELECT min(cost). min(retail) FROM stock; <br> min | min <br> 16.00 16.95 <br> (1 row) <br> booktown=# SELECT min(retail), p.name <br> booktown-# FROM (stock NATURAL JOIN editions) <br> booktown-# JOIN publishers AS p (publisheMd) <br> booktown-# USING (publisheMd) <br> booktown-l GROUP BY p.name <br> booktown-# ORDER BY min ASC; <br> miP 1 ..mme._ <br> 16.95 | Random House <br> 21.95 Ace Books <br> 21.95 I Books of Wonder <br> 22.95 | Roc <br> 23.95 | Henry Holt & Company. Inc. <br> 23.95 | Kids Can Press <br> 24.95 | Mojo Press <br> 24.95 I Penguin <br> 28.95 | Doubleday <br> 28.95 I HarperCollins <br> 28.95 | Watson-Guptill Publications <br> (11 rows) <br> stddev() <br> Синтаксис: <br> stddev(выражение) <br> Функция stddev О получает выражение, описывающее значения любого числового типа (numeri с, bigi nt, smal 1 i nt, real или doubl e preci si on), и возвращает среднеквадратичное отклонение для группы. Для вещественных выражений результат возвращается в виде значения типа double precision, а для остальных типов —в виде значения типа numeric. <br><br> <h1>получает выражение, описывающее значения любого </h1> <br> booktown=# SELECT stddev(retail) FROM stock; <br> stddev <br> 8.46 <br> (1 row) <br> booktown=# SELECT stddev(retail), p.name <br> booktown-# FROM (stock NATURAL JOIN editions) <br> booktown-# JOIN publishers AS p ON (publisheMd = p.id) <br> booktown-# GROUP BY p.name <br> booktown-# ORDER BY stddev DESC <br> booktown-# LIMIT 4: <br> stddev | name <br> 16.97 | Ace Books <br> 16.97 | Roc 8.02 Random House <br> 5.66 | Doubleday <br> (4 rows) <br> sum() <br> Синтаксис: <br> sum (выражение) <br> Функция sum() получает выражение, описывающее значения любого числового типа (numeric, bigint, smallint, real или double precision), и возвращает сумму значений в группе. Для выражений типа integer результат возвращается в виде значения типа numeric, а для выражений типа real — в виде значения типа double precision. В остальных случаях тип возвращаемого значения совпадает с типом выражения. <br><br> <h1>получает выражение, описывающее значения любого </h1> <br> booktown=# SELECT sum(stock) FROM stock; <br> sum <br> "BOB" <br> (1 row) <br> booktown=# SELECT sum(stock). s.subject <br> booktown-# FROM ((stock NATURAL JOIN editions) <br> booktown(# JOIN books ON (books.id = bookjd)) <br> booktown-f JOIN subjects AS s <br> booktown-# ON (books.subject_id = s.id) <br> booktown-# GROUP BY s.subject <br> booktown-# ORDER BY sum DESC; <br> 189 | Horror <br> 166 I Science Fiction <br> 91 | Children's Books <br> 28 | Drama <br> 18 | Classics <br> 16 | Arts <br> (6 rows) <br> variance()<br> Синтаксис: variance(выражение) <br> Функция variance() получает выражение, описывающее значения любого числового типа (numeric, bigint, small int, real или double precision), и возвращает дисперсию для группы (stddevO в квадрате). Для вещественных выражений результат возвращается в виде значения типа double precision, а для остальных типов — в виде значения типа numeric. <br> Примеры <br> booktown=# SELECT variance(retaiT) FROM stock; <br> variance <br> 71.60 <br> (1 row) <br> booktown=# SELECT varianceCretail), p.name <br> booktown-# FROM (stock NATURAL JOIN editions) <br> booktown-# JOIN publishers AS p <br> booktown-# ON (editions.pub!isher_id = p.id) <br> booktown-# GROUP BY p.name <br> booktown-# ORDER BY variance DESC <br> booktown-# LIMIT 4: variance name <br> 288.00 | Ace Books 288.00 I Roc 64.33 ! <br> Random House 32.00 | Doubleday <br> (4 rows) <br><br> <h1>получает один аргумент типа text, </h1> <br> booktown=# SELECT * FROM books <br> booktown-# WHERE title LIKE ('XRabbit1): <br> id i title | authorjd subjectjd <br> 1234 | The Velveteen Rabbit | 25041 | 3 <br> (1 row) <br> booktown=# SELECT * FROM books <br> booktown-# WHERE title LIKE <br> id | title | authorjd | subjectjd <br> 4513 | Dune | 1866 | 15 <br> 25908 | Franklin in the Dark | 15990 | 2 (2 rows) <br> booktown=# SELECT * FROM books <br> booktown-# WHERE title ILIKE '«python*': <br> id | title | authorjd | subjectjd <br> 41473 | Programming Python | 7805 | 4 41477 <br> Learning Python | 7805 4 <br> (2 rows) <br> lower()<br> Синтаксис: lower(s) <br> Функция SQL92 1 ower () получает один аргумент типа text, преобразует все символы строки к нижнему регистру и возвращает полученную строку в виде значения типа text. <br><br> <h1>The Cat in the Hat </h1> <br> booktown=# SELECT ItrimC whitespace example'): <br> Itrim <br> whitespace example (1 row) <br> booktown=# SELECT title. ItrimCtitle, 'TD2he ') <br> booktown-# FROM books booktown-# LIMIT 4: <br> title | Itritn <br> The Shining | Shining <br> Dune I une <br> 2001: A Space Odyssey | 001: A Space Odyssey <br> The Cat in the Hat j Cat In the Hat <br> (4 rows) <br> octet_length() <br> Синтаксис: octetjength(s) <br> Функция SQL92 octetj ength() получает один аргумент s типа text, varchar или character и возвращает длину полученной строки в байтах. Возвращаемое значение относится к типу integer. <br> В большинстве случаев длина строки в байтах совпадает с количеством символов, хотя в расширенных кодировках не всегда, поскольку в них символ по определению может состоять из нескольких байтов. <br> Пример<br> booktown=# SELECT title, octetjength(title) <br> booktown-# FROM books <br> booktown-# ORDER BY title ASC <br> booktown-# LIMIT 3: <br> title octet Jength <br> 2001: A Space Odyssey | 21 <br> Bartholomew and the Oobleck | 27 <br> Dune | 4 <br> (3 rows) <br> position()<br> Синтаксис: position(b IN s) <br> Функция SQL92 position^) получает два аргумента, относящихся к типу text, и возвращает начальную позицию подстроки b в строке s (отсчет начинается с 1). Возвращаемое значение относится к типу i nteger. Если подстрока не найдена, функция возвращает 0. <br><br> <h1>The Cat in the Hat </h1> <br> booktown=# SELECT rtrimC'whitespace example '); <br> rtrim <br> whitespace example <br> (1 row) <br> booktown=# SELECT title, rtrinKtitle, 'yes') <br> booktown-# FROM books <br> booktown-# LIMIT 4; <br> title rtrim <br> The Shining | The Shining <br> Dune Dun 2001: A Space Odyssey 2001: A Space Od <br> The Cat in the Hat j The Cat in the Hat <br> (4 rows) <br> strpos()<br> Синтаксис: strpos(s. b) <br> Функция strposO эквивалентна функции SQL92 positionO, но аргументы передаются ей в стиле С. Функция получает два аргумента, относящихся к типу text, и возвращает начальную позицию подстроки b в строке s (отсчет начинается с 1). Возвращаемое значение относится к типу 1 nteger. Если подстрока не найдена, функция возвращает 0. <br><br> <h1>Tale Heart Heart The Shining </h1> <br> booktown=# SELECT title, substring(title FROM 15) <br> booktown-# FROM books <br> booktown-* ORDER BY title DESC <br> booktown-# LIMIT 3; <br> title | substring <br> The Velveteen Rabbit | Rabbit <br> The Tell- Tale Heart Heart The Shining <br> (3 rows) <br> booktown=# SELECT title, substring(title FROM 5 FOR 9) <br> booktown-# FROM books <br> booktown-# ORDER BY title DESC booktown-# LIMIT 3; <br> title | substring <br> The Velveteen Rabbit Velveteen <br> The Tell-Tale Heart Tell-Tale <br> The Shining | Shining <br> (3 rows) <br> to_ascii() <br> Синтаксис: <br> to_ascii(s, f) <br> Функция to_asci i () получает строковый аргумент s, относящийся к типу text, и обозначение расширенной кодировки f, а возвращает обычный ASCII-текст в виде значения типа text. <br> Допустимы следующие обозначения расширенных кодировок: LATIN1 (ISO 8859-1), LATIN2 (ISO 8859-2) и WIN1250 (Windows CP1250 или WinLatin2). Для работы функции необходима поддержка расширенных кодировок (устанавливается при помощи ключа командной строки компилятора при установке PostgreSQL). <br><br> <h1>получает один аргумент типа text, </h1> <br> booktowrH1 SELECT isbn, trim(LEADING '0' FROM isbn) <br> booktown-# FROM editions booktown-# LIMIT 2; isbn | Itrim <br> 039480001X 39480001X 0451160916 451160916 <br> (2 rows) <br> booktown=# SELECT isbn, trimCTRAILING 'X' FROM isbn) <br> booktown-# FROM editions booktown-# LIMIT 2; <br> 1Sbn rtrim <br> 039480001X j 039480001 0451160916 j 0451160916 <br> (2 rows) <br> booktowrHf SELECT isbn, trimCBOTH 'OX' FROM isbn) <br> booktown-# FROM editions booktown-# LIMIT 2; isbn I btrim <br> 039480001X | 39480001 0451160916 | 451160916 <br> (2 rows) <br> upper()<br> Синтаксис: <br> upper(s) <br> Функция SQL92 upper() получает один аргумент типа text, преобразует все символы строки к верхнему регистру и возвращает полученную строку в виде значения типа text. <br><br> <h1>s определяет компонент, до которого </h1> <br> booktown=# SELECT date_part('minute'. <br> booktown(# intervalC3 days 4 hours 12 minutes')): <br> date_part <br> 12 <br> (1 row) <br> booktown=# SELECT isbn, <br> booktown-l date_part('year', publication) <br> booktown-# FROM editions <br> booktown-# ORDER BY date_part ASC <br> booktown-# LIMIT 3; <br> isbn | date_part <br> 0760720002 | 1868 <br> 0679803335 | 1922 <br> 0694003611 | 1947 <br> (3 rows) <br> Примечание 1 <br>Примечание 1<br><br> Аналогом функции date_part() в SQL является функция extract(). <br> date_trunc() <br> Синтаксис: date_trunc(s. t) <br> Функция date_trunc () получает два аргумента s и t, относящихся к типам text и timestamp соответственно. Строка s определяет компонент, до которого усекается аргумент t. В данном контексте под усечением понимается удаление всех компонентов, детализация которых превышает заданную. <br> Допустимые значения аргумента s перечислены в табл. 5.12. <br><br> <h1>получает один аргумент типа timestamp </h1> <br> booktown=# SELECT extract(MINUTE FROM <br> interval('3 days 12 minutes1)): datejpart <br> 12 <br> (1 row) <br> booktown=# SELECT extractCMONTH FROM now()): <br> date_part <br> 8<br> (1 row) <br> isfinite()<br> Синтаксис: <br> isfinite(t) isfinite(i) <br> Функция 1 sf 1 ni te() получает один аргумент типа timestamp или 1 interval. Она возвращает true, если переданное значение не является бесконечным, созданным при помощи специальной константы Infinity или invalid (используется только для timestamp). <br><br> <h1>в форматной строке отсутствует последовательность </h1> <br> booktown=# SELECT to_char(123456789. '999G999G999D99') AS formatted, <br> booktown-# to_char(123456789. '999999999') AS justjrigits, <br> booktown-f to_char(123456789, '00999999999') AS with_zeroes; <br> formatted | justjrigits | with_zeroes<br> 123.456.789.00 | 123456789 | 00123456789 <br> (1 row) <br> booktown=# SELECT cost * 100 AS cost_to_order. <br> booktown-# to_char(cost * 100, '$99.999.99') AS monetary, <br> booktown-# translate(to_char(cost * 100. '$9,999.99'),' ',"). <br> booktown-# AS translated <br> booktown-# FROM stock <br> booktown-* LIMIT 3; <br> cost_to_order monetary translated <br> 2900.00 | $ 2.900.00 $2.900.00 <br> 3000.00 $ 3.000.00 $3.000.00 <br> 1600.00 $ 1,600.00 i $1.600.00 <br> (3 rows) <br> booktown=# SELECT tojrhard.O. '9th "Place"') AS first. <br> booktown-# to_char(2.2, '9th "Place"') AS second, <br> booktown-# to_char(pi( ), '9th "Place"') AS third, <br> booktown-# to_char(10, '99V99th "\\"Place\\.....) AS shifted jjp; <br> first | second | third | shifted_up <br> 1st Place | 2nd Place | 3rd Place | 1000th "Place" <br> (1 row) <br> Примечание 2 <br>Примечание 2<br><br> В PostgreSQL версии 7.1.x ошибка в реализации метасимволов RN (римская запись) приводит к тому, что функция to_char() возвращает неправильный результат, если в форматной строке отсутствует последовательность FM. Ошибка должна быть исправлена в версии 7.2, а в качестве временной меры можно использовать полную последовательность FMRN. <br> to_char() для типа timestamp <br> Синтаксис: <br> to_char(t. f) <br> При вызове с аргументом t типа timestamp и аргументом f типа text функция to_char() форматирует дату и время в строку, возвращаемую в виде значения типа text. <br> Как и в случае с предыдущей версией to_char(), строка f содержит метасимволы, вместо которых PostgreSQL подставляет литералы. Метасимволы, используемые в форматных строках даты и времени, перечислены в табл. 5.15. <br><br> <h1>Приоритет операторов</h1> <br> <br>Приоритет операторов <br><br> При работе с большими выражениями, содержащими несколько операторов, полезно знать, в каком порядке выполняются операторы в PostgreSQL. Было бы неправильно полагать, что операторы выполняются слева направо в порядке их следования в выражении. При неправильном понимании этой темы нередко возникают нежелательные побочные эффекты (листинг 5.18). <br> <br><br> <h1>Сравнение с использованием ключевых слов</h1> <br> <br> Сравнение с использованием ключевых слов <br><br> Ключевое слово BETWEEN (также иногда называемое оператором) позволяет проверить, входит ли значение в некоторый интервал. Например, команда SELECT, приведенная в листинге 5.11, находит книги, цена которых находится в интервале от 10 до 17 долларов. <br> <br><br> <h1>Строковые функции</h1> <br> <br>Строковые функции <br><br> В PostgreSQL существует множество разнообразных строковых функций, предназначенных для форматирования, анализа и сравнения строк. К их числу относятся как функции стандарта SQL92, так и нестандартные расширения PostgreSQL (например, ItrimO, rtrimO и substrO). Строковые функции PostgreSQL перечислены в табл. 5.10. В общем случае все, что говорится о типе text, в равной степени относится к значениям типа character и varchar. <br> <br><br> <h1>Строковые операторы</h1> <br> <br>Строковые операторы <br><br> В PostgreSQL существует обширный набор строковых операторов для выполнения различных действий, от простой конкатенации текста и сравнения строк до поиска по регулярным выражениям. Строковые операторы работают с типами char, varchar, а также с собственным типом PostgreSQL text. <br> Ниже описаны основные операторы сравнения и конкатенации, а также реализация операторов регулярных выражений с учетом и без учета регистра символов. <br> Базовые операторы сравнения <br> Базовые операторы сравнения строк и конкатенации, поддерживаемые в PostgreSQL, перечислены в табл. 5.1. <br> Примечание 1 <br>Примечание 1<br><br><br> Ключевые слова LIKE и ILIKE, приводящие к вызову функции 11ke(), иногда называются операторами сравнения строк. Эти ключевые слова рассматриваются ниже в разделе «Функции». <br> <br><br> <h1>Базовые строковые операторы</h1> <br> <br> Таблица 5.1. Базовые строковые операторы <br><br> <table border=1> <tr> <td> Оператор<br> </td> <td> Синтаксис</td> <td> Описание<br> </td> </tr> <tr> <td>=</td> <td>'строка!' = ' строка2'</td> <td>Возвращает true, если первая строка точно совпадает со второй</td> </tr> <tr> <td> ! =</td> <td> 'строка!' != ' строка2'</td> <td> Возвращает true, если первая строка не совпадает со второй</td> </tr> <tr> <td> о</td> <td> 'строка!' <> ' строка2'</td> <td> Идентичен оператору !=</td> </tr> <tr> <td> <</td> <td> 'строка!' < ' строка2'</td> <td> Возвращает true, если при лексикографической сортировке первая строка предшествует второй</td> </tr> <tr> <td> <=</td> <td> 'строка!' <= ' строка2'</td> <td> Возвращает true, если при лексикографической сортировке первая строка предшествует второй или их значения совпадают</td> </tr> <tr> <td> ></td> <td> 'строка!' > ' строка2'</td> <td> Возвращает true, если при лексикографической сортировке вторая строка предшествует первой</td> </tr> <tr> <td> >=</td> <td> 'строка!' >= ' строка2'</td> <td> Возвращает true, если при лексикографической сортировке вторая строка предшествует первой или их значения совпадают</td> </tr> </table> Все операторы сравнения строк возвращают логическое значение (true или false). Лексикографическая сортировка, упоминаемая в табл. 5.1, последовательно сравнивает символы строк и определяет, какой из символов «больше» другого. Если начальные символы двух строк совпадают, проверяются следующие символы (слева направо). Перебор продолжается до тех пор, пока не будут найдены два различающихся символа. В этом алгоритме сортировки «больший» символ выбирается сравнением ASCII-кодов, как показывает следующий пример: <br> booktown=# SELECT letter, ascii(letter) <br> booktown-# FROM text_sorting <br> booktown-# ORDER BY letter ASC; <br> letter ascii <br> 0 48 <br> 1 49 <br> 2 50 <br> 3 51 <br> A 65 <br> В 66 <br> С 67 <br> D 68 <br> a 97 <br> b 98 <br> с 99 <br> d I 100 <br> (12 rows) <br> Если вы не уверены в порядке сортировки того или иного символа, воспользуйтесь функцией ascii О для получения его ASCII-кода (функция asci i () описана ниже в разделе «Функции»). В листинге 5.3 из таблицы books выбираются названия всех книг, первая буква которых при сортировке предшествует символу «D». <br> <br><br> <h1>Строковые функции</h1> <br> <br> Таблица 5.10. Строковые функции <br><br> <table border=1> <tr> <td> Функция</td> <td> Описание</td> </tr> <tr> <td> ascii(s)</td> <td> Возвращает ASCII-код символа, переданного в виде строковой переменной s</td> </tr> <tr> <td> btrim(s [, t])</td> <td> Возвращает строку s, в начале и в конце которой удалены все символы, входящие в строку t (если аргумент t не задан, усекаются начальные и конечные пропуски — пробелы, символы табуляции и т. д.)</td> </tr> <tr> <td> char length(s)</td> <td> Возвращает длину строки s в символах</td> </tr> <tr> <td> chr(n)</td> <td> Возвращает символ с ASCII-кодом n</td> </tr> <tr> <td> s ilike(f)</td> <td> Возвращает true, если выражение f совпадает (без учета регистра символов) с s</td> </tr> <tr> <td> imtcap(s)</td> <td> Возвращает строку s, в которой первая буква каждого слова преобразуется к верхнему регистру</td> </tr> <tr> <td> length(s)</td> <td> Возвращает длину строки s в символах</td> </tr> <tr> <td> s like(f)</td> <td> Возвращает true, если выражение f совпадает с s</td> </tr> <tr> <td> lower (s)</td> <td> Возвращает строку s, преобразованную к нижнему регистру</td> </tr> <tr> <td> lpad(s. n [. c])</td> <td> Возвращает строку s, дополненную слева содержимым строки с (или пробелами, если аргумент с не задан) до длины n (или усеченную справа до n символов)</td> </tr> <tr> <td> ltrim(s [. f])</td> <td> Возвращает строку s, в начале которой удалены все символы, входящие в строку f (если аргумент f не задан, усекаются начальные пропуски — пробелы, символы табуляции и т. д.)</td> </tr> <tr> <td> octet_length(s)</td> <td> Возвращает длину строки s в байтах</td> </tr> <tr> <td> pos1tion(b IN s)</td> <td> Возвращает позицию подстроки b в строке s (отсчет начинается с 1)</td> </tr> <tr> <td> repeat (s, n)</td> <td> Возвращает строку s, повторенную n раз</td> </tr> <tr> <td> rpad(s. n. [. c])</td> <td> Возвращает строку s, дополненную справа содержимым строки с (или пробелами, если аргумент с не задан) до длины n (или усеченную слева до n символов)</td> </tr> <tr> <td> rtrim(s [. f])</td> <td> Возвращает строку s, в конце которой удалены все символы, входящие в строку f (если аргумент f не задан, усекаются конечные пропуски — пробелы, символы табуляции и т. д.)</td> </tr> <tr> <td> strpos(s. b)</td> <td> Возвращает позицию подстроки b в строке s (отсчет начинается с 1). Относится к числу функций PostgreSQL и дублирует функцию SQL positionO, но с передачей аргументов в стиле С</td> </tr> <tr> <td> substr(s. b [. 1])</td> <td> Выделяет из строки s подстроку, начинающуюся с позиции n (отсчет начинается с 1). Необязательный аргумент 1 определяет максимальную длину подстроки в символах</td> </tr> <tr> <td> substring<br> FROM n FOR 1 )<br> </td> <td> Выделяет из строки s подстроку, начинающуюся с позиции n (отсчет начинается с 1). Необязательный аргумент 1 определяет максимальную длину подстроки в символах</td> </tr> <tr> <td> to_ascii (s. f)</td> <td> Возвращает строку s, преобразованную из расширенной кодировки f в ASCII</td> </tr> <tr> <td> translate(s. f. r)</td> <td> Возвращает строку s, в которой все символы, входящие в строку f, заменяются соответствующими символами строки г</td> </tr> <tr> <td> trim(направление f FROM s)</td> <td> Возвращает строку s, в начале и/или в конце которой удалены все символы, входящие в строку f. В аргументе направление передается ключевое слово SQL, определяющее направление усечения (LEADING, TRAILING или BOTH)</td> </tr> <tr> <td> upper(s)</td> <td> Возвращает строку s, преобразованную к верхнему регистру</td> </tr> </table> Ниже приведены более подробные описания всех функций, перечисленных в таблице, с указанием аргументов, типов данных и выполняемых действий. <br> ascii()<br> Синтаксис: ascii(s) <br> Функция asci i () получает один аргумент — отдельный символ или строку типа text, и возвращает числовой ASCII-код первого интерпретированного символа. Результат возвращается в виде значения типа integer. <br> <br><br> <h1>Функции для работы с датой и временем</h1> <br> <br> Таблица 5.11. Функции для работы с датой и временем <br><br> <table border=1> <tr> <td> Функция</td> <td> Описание</td> </tr> <tr> <td> current date</td> <td> Возвращает текущую дату в виде значения типа date</td> </tr> <tr> <td> current time</td> <td> Возвращает текущее время в виде значения типа time</td> </tr> <tr> <td> current timestamp</td> <td> Возвращает текущие дату и время в виде значения типа timestamp</td> </tr> <tr> <td> date_part(s. t)</td> <td> Выделяет из значения типа timestamp компонент даты или времени, определяемый строкой s</td> </tr> <tr> <td> date_part(s. i)</td> <td> Выделяет из значения типа interval компонент даты или времени, определяемый строкой s</td> </tr> <tr> <td> date trunc(s, t)</td> <td> Возвращает значение типа timestamp, усеченное до точности s</td> </tr> <tr> <td> extract (k FROM t)</td> <td> Выделяет из значения типа timestamp компонент даты или времени, определяемый ключевым словом k</td> </tr> <tr> <td> extracttk FROM i)</td> <td> Выделяет из значения типа interval компонент даты или времени, определяемый ключевым словом k</td> </tr> <tr> <td> isfinite(t)</td> <td> Возвращает true, если значение типа timestamp соответствует конечной величине (не invalid и не infinity)</td> </tr> <tr> <td> isfinite(i)</td> <td> Возвращает true, если значение типа interval соответствует конечной величине (не infinity)</td> </tr> <tr> <td> now()</td> <td> Возвращает текущие дату и время в виде значения типа timestamp. Эквивалент константы now</td> </tr> <tr> <td> timeofdayO</td> <td> Возвращает текущие дату и время в виде значения типа text</td> </tr> </table> Ниже приведены более подробные описания всех функций, перечисленных в таблице. Обратите внимание на отсутствие круглых скобок в определениях функций current_date, current_time и current_timestamp — это сделано для сохранения совместимости со стандартом SQL92. <br> current_date <br> Синтаксис: <br> current_date <br> Функция current_date вызывается без аргументов и возвращает текущую дату в виде значения типа date. Результат эквивалентен преобразованию специальной константы now к типу date. <br> <br><br> <h1>Компоненты типов timestamp и interval</h1> <br> <br> Таблица 5.12. Компоненты типов timestamp и interval <br><br> <table border=1> <tr> <td> Компонент</td> <td> Описание</td> </tr> <tr> <td> century</td> <td> Год, разделенный на 100 (не совпадает с текущим веком!)</td> </tr> <tr> <td> day</td> <td> День месяца (от 1 до 31) для типа timestamp, продолжительность интервала в днях для типа interval</td> </tr> <tr> <td> decade</td> <td> Год, разделенный на 10</td> </tr> <tr> <td> dow</td> <td> День недели (от 0 до 6), начиная с воскресенья. Для типа interval не поддерживается</td> </tr> <tr> <td> doy</td> <td> День года (от 1 до 366). Для типа interval не поддерживается</td> </tr> <tr> <td> epoch</td> <td> Количество секунд от начала эпохи (1 января 1970 г.) для типа timestamp, продолжительность интервала в секундах для типа interval</td> </tr> <tr> <td> hour</td> <td> Час в значении типа timestamp</td> </tr> <tr> <td> microseconds</td> <td> Количество миллионных долей в дробной части секунд для значения типа timestamp<br> </td> </tr> <tr> <td> millennium</td> <td> Год, разделенный на 1000 (не совпадает с текущим тысячелетием!)</td> </tr> <tr> <td> mi 11 i seconds</td> <td> Количество тысячных долей в дробной части секунд для значения типа timestamp</td> </tr> <tr> <td> minute</td> <td> Минуты в значении типа timestamp или interval</td> </tr> <tr> <td> month</td> <td> Месяц в значении типа timestamp или остаток от деления продолжительности интервала в месяцах на 12 для типа interval</td> </tr> <tr> <td> quarter</td> <td> Квартал (от 1 до 4) для значений типа timestamp</td> </tr> <tr> <td> second</td> <td> Секунды в значении типа timestamp или interval</td> </tr> <tr> <td> week</td> <td> Номер недели в году для значений типа timestamp. В стандарте ISO-8601 первая неделя года определяется как неделя, в которую входит 4 января</td> </tr> <tr> <td> year</td> <td> Год в значении типа timestamp или interval</td> </tr> </table> <br><br> <h1>Функции преобразования типов</h1> <br> <br> Таблица 5.13. Функции преобразования типов <br><br> <table border=1> <tr> <td> Функция</td> <td> Описание</td> </tr> <tr> <td> t>1tfromint4(n)</td> <td> Преобразует число в битовую последовательность</td> </tr> <tr> <td> DlttOinW(b)</td> <td> Преобразует битовую последовательность в десятичное представление</td> </tr> <tr> <td> to_cnar(n. f)</td> <td> Преобразует число в строку в формате f</td> </tr> <tr> <td> to_char(t. f)</td> <td> Преобразует значение типа timestamp в строку в формате f</td> </tr> <tr> <td> to_date(s. f)</td> <td> Преобразует строку в формате даты f в значение типа date</td> </tr> <tr> <td> to_number(s. f)</td> <td> Преобразует строку в формате даты f в значение типа numeric</td> </tr> <tr> <td> to timestamp(s. f)</td> <td> Преобразует строку в формате даты f в значение типа timestamp</td> </tr> <tr> <td> timestamp(d)</td> <td> Преобразует значение типа date к типу timestamp</td> </tr> <tr> <td> timestamp(d. t)</td> <td> Преобразует два значения типов date и time к типу timestamp</td> </tr> </table> bitfromint4() <br> Синтаксис: <br> bit.fromint4(n) <br> Функция bitfromint4() получает один аргумент п типа integer и возвращает его представление в виде битовой последовательности. Поскольку явного преобразования между двоичным и целочисленным типом не существует, преобразование десятичных данных в двоичную систему счисления должно Осуществляться специальной функцией. <br> Возвращаемое значение относится к типу bi t, а его длина не превышает 32 бита. Поскольку тип i nteger является знаковым, допустимые значения аргумента лежат в интервале от -2 147 483 648 до 2 147 483 647. <br> <br><br> <h1>Метасимволы форматирования чисел</h1> <br> <br> Таблица 5.14. Метасимволы форматирования чисел <br><br> <table border=1> <tr> <td> Символ</td> <td> Описание</td> </tr> <tr> <td> 9</td> <td> Цифра</td> </tr> <tr> <td> 0</td> <td> Цифра или начальный/конечный ноль, если количество цифр в f превышает количество цифр в п; может использоваться для принудительного вывода цифр в левой или правой части результата</td> </tr> <tr> <td>.</td> <td> Точка, отделяющая целую часть числа от дробной. Число может содержать только одну точку</td> </tr> <tr> <td> '</td> <td> Запятая. Число может содержать несколько запятых, используемых для разделения групп разрядов (тысячи, миллионы и т. д.)</td> </tr> <tr> <td> D</td> <td> Десятичный разделитель (например, точка), определяемый в локальном контексте</td> </tr> <tr> <td> G</td> <td> Разделитель групп разрядов (например, запятая), определяемый в локальном контексте</td> </tr> <tr> <td> PR</td> <td> Если PR находится в конце строки f, для отрицательных значений п результат заключается в угловые скобки</td> </tr> <tr> <td> SG</td> <td> Знак плюс (+) или минус (-) в зависимости от значения п</td> </tr> <tr> <td> MI</td> <td> Знак минус (-), если число п является отрицательным</td> </tr> <tr> <td> PL</td> <td> Знак плюс (+), если число п является положительным</td> </tr> <tr> <td> S</td> <td> Знак плюс (+) или минус (-), определяемый в локальном контексте</td> </tr> <tr> <td> L</td> <td> Денежный знак, определяемый в локальном контексте</td> </tr> <tr> <td> RN</td> <td> Римские цифры для значений п в интервале от 1 до 3999</td> </tr> <tr> <td> TH. th</td> <td> Суффикс числительного для числа п (например, 4th или 2nd)</td> </tr> <tr> <td> V</td> <td> Для каждого метасимвола 9 после V добавляется лишний ноль, то есть фактически происходит умножение на степень 10</td> </tr> <tr> <td> FM</td> <td> Из числа удаляются все начальные и завершающие нули (созданные символами 9, но не 0), а также все лишние пробелы</td> </tr> </table> Если количество цифровых позиций, обозначенных метасимволом 9 в форматной строке, превышает количество цифр в числе п, лишние позиции заполняются пробелами. Если лишние цифровые позиции обозначены метасимволом 0, лишние позиции заполняются нулями. <br> Если количество заданных цифровых позиций меньше необходимого для представления целой части числа, преобразование становится неоднозначным из-за потери значащих цифр. Поскольку функция to_char() не знает, какие именно цифры следует удалить, во всех заданных позициях выводится символ #. Следовательно, в форматную строку необходимо включить максимальное количество цифр, кото- <br> рые могут быть получены в результате форматирования. Для удаления лишних пробелов также можно воспользоваться функцией trans! ate() или функциями усечения (HrimO и т. д.). <br> Чтобы метасимвол интерпретировался в форматной строке буквально (то есть как литерал), заключите его в кавычки. Чтобы включить в форматную строку литеральный символ кавычки, его необходимо экранировать двумя обратными косыми чертами. <br> Примечание 1 <br>Примечание 1<br><br><br> В форматной строке можно свободно использовать любые символы, не являющиеся метасимволами (например, символ $ и др.) В отформатированной строке они выводятся без изменений. <br> <br><br> <h1>Метасимволы форматирования чисел</h1> <br> <br> Таблица 5.15. Метасимволы форматирования чисел <br><br> <table border=1> <tr> <td> Символ</td> <td> Описание</td> </tr> <tr> <td> НН. НН12</td> <td> Час (от 1 до 12)</td> </tr> <tr> <td> НН24</td> <td> Час (от 0 до 23)</td> </tr> <tr> <td> Ml</td> <td> Минуты (от 0 до 59)</td> </tr> <tr> <td> SS</td> <td> Секунды (от 0 до 59)</td> </tr> <tr> <td> SSSS</td> <td> Секунды, прошедшие с полуночи (от 0 до 86 399)</td> </tr> <tr> <td> AM, РМ, А.М, Р.М</td> <td> Обозначение части суток в верхнем регистре с необязательным разделением символов точками</td> </tr> <tr> <td> am, pm, a . m, p . m</td> <td> Обозначение части суток в нижнем регистре с необязательным разделением символов точками</td> </tr> <tr> <td> TZ, tz</td> <td> Часовой пояс в верхнем или нижнем регистре</td> </tr> <tr> <td> CC</td> <td> Век, представленный двумя цифрами (не равен тку, деленному на 100!)</td> </tr> <tr> <td> Y, YY, YYY, YYYY, Y.YYY</td> <td> Последняя цифра, две цифры, три или четыре цифры года (с необязательным включением запятой)</td> </tr> <tr> <td> BC, AD, B.C, A.O</td> <td> Признак эры в верхнем регистре</td> </tr> <tr> <td> be, ad, b.c, a.d</td> <td> Признак эры в нижнем регистре</td> </tr> <tr> <td> MONTH, Month, month</td> <td> Полное название месяца, дополненное справа пробелами до 9 символов и записанное либо в верхнем регистре, либо с начальной прописной буквой, либо в нижнем регистре</td> </tr> <tr> <td> MON, Mon, mon</td> <td> Сокращенное трехбуквенное обозначение месяца, записанное либо в верхнем регистре, либо с начальной прописной буквой, либо в нижнем регистре</td> </tr> <tr> <td> MM</td> <td> Номер месяца (от 1 до 12)</td> </tr> <tr> <td> RN, rn</td> <td> Номер месяца в римской записи (от I до XII), в верхнем или нижнем регистре</td> </tr> <tr> <td> DAY, Day, day</td> <td> Полное название дня недели, дополненное справа пробелами до 9 символов и записанное либо в верхнем регистре, либо с начальной прописной буквой, либо в нижнем регистре</td> </tr> <tr> <td> DY, Dy, dy</td> <td> Сокращенное двухбуквенное обозначение дня недели, записанное либо в верхнем регистре, либо с начальной прописной буквой, либо в нижнем регистре</td> </tr> <tr> <td> DDD, DD, D</td> <td> День года (от 1 до 366), день месяца (от 1 до 31) или день недели (от 1 до 7, начиная с воскресенья)</td> </tr> <tr> <td> W</td> <td> Неделя месяца (от 1 до 5, с первого дня месяца)</td> </tr> <tr> <td> WW</td> <td> Неделя года (от 1 до 53, с первого дня года)</td> </tr> <tr> <td> IW</td> <td> Неделя года в стандарте ISO (с первого четверга нового года)</td> </tr> <tr> <td> TH, th</td> <td> Суффикс для предшествующего числа в верхнем или нижнем регистре</td> </tr> <tr> <td> fm</td> <td> Из строки удаляются все лишние нули и пробелы</td> </tr> </table> Суффикс ТН и префикс FM должны непосредственно примыкать к тому значению, которое они модифицируют. Например, чтобы префикс FM применялся к компоненту Day, строка должна иметь вид FMDay (а не FM Day). Аналогично, чтобы день месяца выводился с суффиксом числительного, потребуется форматная строка DDTH (а не DD ТН). <br> <br><br> <h1>Агрегатные функции</h1> <br> <br> Таблица 5.16. Агрегатные функции <br><br> <table border=1> <tr> <td> Функция</td> <td> Описание</td> </tr> <tr> <td> avg( выражение')</td> <td> Возвращает среднее арифметическое значений выражения для всех записей в группе</td> </tr> <tr> <td> count ( выражение)</td> <td> Возвращает количество записей в группе, для которых значение выражения отлично от NULL</td> </tr> <tr> <td> ma x ( выражение}</td> <td> Возвращает максимальное значение выражения в группе</td> </tr> <tr> <td> mint выражение)</td> <td> Возвращает минимальное значение выражения в группе</td> </tr> <tr> <td> stddev ( выражение)</td> <td> Возвращает среднеквадратичное отклонение значений выражения в группе</td> </tr> <tr> <td> surrK выражение)</td> <td> Возвращает сумму значений выражения в группе</td> </tr> <tr> <td> variance( выражение)</td> <td> Возвращает дисперсию значений выражения в группе</td> </tr> </table> Ниже приведены более подробные описания всех агрегатных функций с конкретной информацией об особенностях использования, примерами и допустимыми типами входных данных. В дальнейших описаниях термин выражение означает любой идентификатор в итоговом наборе или любое действительное выражение, выполняющее операцию с этим идентификатором. <br> <br><br> <h1>Операторы регулярных выражений</h1> <br> <br> Таблица 5.2. Операторы регулярных выражений <br><br> <table border=1> <tr> <td> Оператор</td> <td> Синтаксис</td> <td> Описание</td> </tr> <tr> <td> -</td> <td> ' строка' ~ ' выражение'</td> <td> Возвращает true, если в строке существует совпадение для регулярного выражения</td> </tr> <tr> <td> i ~</td> <td> 'строка' \- 'выражение'</td> <td> Возвращает true, если в строке нет совпадения для регулярного выражения</td> </tr> <tr> <td> ~*</td> <td> ' строка' ~* ' выражение'</td> <td> Возвращает true, если в строке существует совпадение для регулярного выражения (без учета регистра символов)</td> </tr> <tr> <td> |_*</td> <td> 'строка' !-* 'выражение'</td> <td> Возвращает true, если в строке нет совпадения для регулярного выражения (без учета регистра символов)</td> </tr> </table> В табл. 5.3 перечислены метасимволы регулярных выражений. Как было указано выше, в регулярных выражениях эти символы интерпретируются особым образом. <br> <br><br> <h1>Метасимволы регулярных выражений</h1> <br> <br> Таблица 5.3. Метасимволы регулярных выражений <br><br> <table border=1> <tr> <td> Символ</td> <td> Синтаксис</td> <td> Описание</td> </tr> <tr> <td> -</td> <td> ^выражение</td> <td> Соответствует началу строки</td> </tr> <tr> <td> $</td> <td> выражение$</td> <td> Соответствует концу строки</td> </tr> <tr> <td>. </td> <td>, </td> <td> Соответствует одному символу</td> </tr> <tr> <td> [ ]</td> <td> [abc]</td> <td> Соответствует любому из символов, перечисленных в квадратных скобках</td> </tr> <tr> <td> Г]</td> <td> ГаЬс]</td> <td> Соответствует любому символу кроме символов, перечисленных в квадратных скобках</td> </tr> <tr> <td> [-]</td> <td> [a-z]</td> <td> Соответствует любому символу из интервала, заданного в квадратных скобках</td> </tr> <tr> <td> Г-]</td> <td> Га-z]</td> <td> Соответствует любому символу кроме символов из интервала, заданного в квадратных скобках</td> </tr> <tr> <td> 7</td> <td> а?</td> <td> Соответствует нулю экземпляров или одному экземпляру предшествующего символа или подвыражения</td> </tr> <tr> <td> *</td> <td> а*</td> <td> Соответствует нулю экземпляров или произвольному количеству экземпляров предшествующего символа или подвыражения</td> </tr> <tr> <td> +</td> <td> а+</td> <td> Соответствует одному и более экземпляров предшествующего символа или подвыражения</td> </tr> <tr> <td> 1</td> <td> выражение! \ выражение2</td> <td> Соответствует левому или правому подвыражению</td> </tr> <tr> <td> ( )</td> <td> (выражение!) выражение2</td> <td> Группировка подвыражений с явным определением приоритета выполняемых операций</td> </tr> </table> Примечание 3 <br>Примечание 3<br><br><br> Литералы, совпадающие с метасимволами из табл. 5.3, должны экранироваться в строке двумя символами \ (например, знак $ представляется последовательностью \\$). <br> Регулярные выражения часто применяются для поиска подстрок в строках-литералах большего размера. При поиске соответствия с учетом регистра символов используется оператор -; с оператором -* регистр игнорируется. Примеры приведены в листинге 5.6. <br> <br><br> <h1>Математические операторы</h1> <br> <br> Таблица 5.4. Математические операторы <br><br> <table border=1> <tr> <td> Оператор</td> <td> Синтаксис</td> <td> Описание</td> </tr> <tr> <td> +</td> <td> а + b</td> <td> Суммирование числовых величин а и b</td> </tr> <tr> <td> -</td> <td> а - Ь</td> <td> Вычитание числовой величины b из а</td> </tr> <tr> <td> *</td> <td> а * b</td> <td> Умножение числовых величин а и b</td> </tr> <tr> <td> /</td> <td> а / b</td> <td> Деление числовой величины а на b</td> </tr> <tr> <td> %</td> <td> а % b</td> <td> Остаток от деления а на b</td> </tr> <tr> <td> А</td> <td> а - b</td> <td> Возведение а в степень b</td> </tr> <tr> <td> |/</td> <td> !/ а</td> <td> Квадратный корень из а</td> </tr> <tr> <td> II/</td> <td> ||/ а</td> <td> Кубический корень из b</td> </tr> <tr> <td> 1</td> <td> а!</td> <td> Факториал а</td> </tr> <tr> <td> ! 1</td> <td> !! а</td> <td> Факториал а (отличается от постфиксного оператора только расположением)</td> </tr> <tr> <td> @</td> <td> @ а</td> <td> Модуль (абсолютное значение) а</td> </tr> </table> Пример использования математических операторов в целевом списке приведен в листинге 5.9. Оператор / используется для вычисления удельной прибыли по каждой книги. Частное от деления преобразуется к типу numeri с с усечением до двух цифр в дробной части. Наконец, из результата вычитается целочисленная константа 1, чтобы результат выражался в процентах свыше 100. <br> <br><br> <h1>Операторы сравнения</h1> <br> <br> Таблица 5.5. Операторы сравнения <br><br> <table border=1> <tr> <td> Оператор</td> <td> Описание</td> </tr> <tr> <td> <</td> <td> Возвращает true, если левое значение меньше правого</td> </tr> <tr> <td> ></td> <td> Возвращает true, если левое значение больше правого</td> </tr> <tr> <td> <=</td> <td> Возвращает true, если левое значение меньше правого или равно ему</td> </tr> <tr> <td> >=</td> <td> Возвращает true, если левое значение больше правого или равно ему</td> </tr> <tr> <td> =</td> <td> Возвращает true, если левое значение равно правому</td> </tr> <tr> <td> <> или ! =</td> <td> Возвращает true, если левое значение не равно правому</td> </tr> </table> Примечание 1 <br>Примечание 1<br><br><br> Оператор <> существует как синоним оператора != для обеспечения совместимости с другими реализациями СУБД на базе SQL. Работают эти операторы одинаково. <br> Пример команды, в которой используются операторы сравнения, приведен в листинге 5.10. <br> <br><br> <h1>Двоичные операторы</h1> <br> <br> Таблица 5.6. Двоичные операторы <br><br> <table border=1> <tr> <td> Оператор</td> <td> Синтаксис</td> <td> Описание</td> </tr> <tr> <td> &</td> <td> а & b</td> <td> Поразрядная конъюнкция двоичных представлений а и b (которые могут быть заданы в виде целых чисел)</td> </tr> <tr> <td> 1</td> <td> а | b</td> <td> Поразрядная дизъюнкция двоичных представлений а и b (которые могут быть заданы в виде целых чисел)</td> </tr> <tr> <td> f</td> <td> а # b</td> <td> Поразрядная операция исключающей дизъюнкции двоичных представлений а и b (которые могут быть заданы в виде целых чисел)</td> </tr> <tr> <td> -</td> <td> - b</td> <td> Поразрядное отрицание, возвращает инвертированную битовую последовательность b</td> </tr> <tr> <td> «</td> <td> b « n</td> <td> Сдвиг b влево на n разрядов</td> </tr> <tr> <td> »</td> <td> b » n</td> <td> Сдвиг b вправо на n разрядов</td> </tr> </table> В листинге 5.13 приведен пример сдвига числа и его двоичного представления на два разряда вправо оператором ». Кроме того, в нем используется функция преобразования битовой последовательности в целочисленный тип bitten nt4(), описанная в разделе «Функции». <br> <br><br> <h1>Операторы AND OR и NOT</h1> <br> <br> Таблица 5.7. Операторы AND, OR и NOT <br><br> <table border=1> <tr> <td> а</td> <td> b</td> <td> aANDb</td> <td> aORb</td> <td> NOT a</td> <td> NOTb</td> </tr> <tr> <td> true</td> <td> true</td> <td> true</td> <td> true</td> <td> false</td> <td> false</td> </tr> <tr> <td> true</td> <td> false</td> <td> false</td> <td> true</td> <td> false</td> <td> true</td> </tr> <tr> <td> true</td> <td> NULL</td> <td> NULL</td> <td> true</td> <td> false</td> <td> NULL</td> </tr> <tr> <td> false</td> <td> false</td> <td> false</td> <td> false</td> <td> true</td> <td> true</td> </tr> <tr> <td> false</td> <td> NULL</td> <td> false</td> <td> NULL</td> <td> true</td> <td> NULL</td> </tr> <tr> <td> NULL</td> <td> NULL</td> <td> NULL</td> <td> NULL</td> <td> NULL</td> <td> NULL</td> </tr> </table> В листинге 5.14 приведена пара запросов с ключевыми словами OR и AND, объединяющими условия выборки записей. Первый запрос возвращает информацию о книгах, которые стоят больше 30 долларов или отсутствуют на складе. Как видно из итогового набора, для возвращения записи должно выполняться одно или оба условия. <br> Во втором запросе те же условия объединяются ключевым словом AND. В результате записи проходят более жесткий отбор, поскольку должны выполняться сразу оба критерия. Итоговый набор состоит всего из одной записи для книги, которая стоит дороже 30 долларов и отсутствует на складе. <br> <br><br> <h1>Приоритет операторов SQL</h1> <br> <br> Таблица 5.8. Приоритет операторов SQL <br><br> <table border=1> <tr> <td> Оператор</td> <td> Синтаксис</td> <td> Описание</td> </tr> <tr> <td> </td> <td> значение: : тип</td> <td> Явное преобразование типа</td> </tr> <tr> <td> [ ]</td> <td> значение^ индекс]</td> <td> Индексация элемента массива</td> </tr> <tr> <td> </td> <td> таблица, поле</td> <td> Разделитель имен таблицы и столбца</td> </tr> <tr> <td> -</td> <td> -значение</td> <td> Унарный минус</td> </tr> <tr> <td> А</td> <td> основание * степень</td> <td> Возведение в степень</td> </tr> <tr> <td> * / %</td> <td> значение! * значение2</td> <td> Умножение, деление и остаток</td> </tr> <tr> <td> + -</td> <td> значение! + значение2</td> <td> Сложение и вычитание</td> </tr> <tr> <td> IS</td> <td> значение IS признак</td> <td> Сравнение с true или false</td> </tr> <tr> <td> IS NULL</td> <td> значение IS NULL</td> <td> Сравнение с NULL</td> </tr> <tr> <td> IS NOT NULL</td> <td> значение IS NOT NULL</td> <td> Проверка несовпадения с NULL</td> </tr> <tr> <td> Прочее</td> <td> —</td> <td> Все остальные пользовательские и встроенные операторы, не входящие ни в одну из категорий</td> </tr> <tr> <td> IN</td> <td> значение IN набор</td> <td> Проверка принадлежности к заданному набору</td> </tr> <tr> <td> BETWEEN</td> <td> значение BETWEEN a AND b</td> <td> Проверка принадлежности к интервалу [а. Ь]</td> </tr> <tr> <td> LIKE, ILIKE</td> <td> строка LIKE, шаблон</td> <td> Проверка совпадения шаблона со строкой</td> </tr> <tr> <td> <><=>=</td> <td> значение! < значение2</td> <td> Сравнения по критериям «меньше», «больше», «меньше либо равно», «больше либо равно»</td> </tr> <tr> <td> =</td> <td> значение! = значение2</td> <td> Проверка равенства</td> </tr> <tr> <td> NOT</td> <td> NOT значение</td> <td> Логическое отрицание</td> </tr> <tr> <td> AND</td> <td> значение! AND значение2</td> <td> Логическая конъюнкция</td> </tr> <tr> <td> OR</td> <td> значение! OR значение2</td> <td> Логическая дизъюнкция</td> </tr> </table> Примечание 1 <br>Примечание 1<br><br><br> Приоритет операторов, приведенных в табл. 5.8, распространяется на пользовательские операторы, обозначения которых совпадают с обозначениями встроенных операторов. Например, если вы определите собственный оператор + для своего типа данных, он будет обладать таким же приоритетом, как встроенный оператор +, независимо от своего предназначения. <br> <br><br> <h1>Математические функции PostgreSQL</h1> <br> <br> Таблица 5.9. Математические функции PostgreSQL <br><br> <table border=1> <tr> <td> Функция</td> <td> Описание</td> </tr> <tr> <td> abs(x)</td> <td> Возвращает модуль (абсолютное значение) х</td> </tr> <tr> <td> acos(x)</td> <td> Возвращает арккосинус х</td> </tr> <tr> <td> asin(x)</td> <td> Возвращает арксинус х</td> </tr> <tr> <td> atan(x)</td> <td> Возвращает арктангенс х</td> </tr> <tr> <td> atan2(x.y)</td> <td> Возвращает арктангенс х/у</td> </tr> <tr> <td> cbrt(x)</td> <td> Возвращает кубический корень х</td> </tr> <tr> <td> ceil (x)</td> <td> Возвращает минимальное целое число, не меньшее х (округление в верхнюю сторону)</td> </tr> <tr> <td> cos(x)</td> <td> Возвращает косинус х</td> </tr> <tr> <td> cot(x)</td> <td> Возвращает котангенс х</td> </tr> <tr> <td> degrees(r)</td> <td> Возвращает количество градусов в г радиан</td> </tr> <tr> <td> exp(x)</td> <td> Возвращает константу е (2,71828...) в степени х</td> </tr> <tr> <td> floor(x)</td> <td> Возвращает максимальное целое число, не большее х (округление в нижнюю сторону)</td> </tr> <tr> <td> ln(x)</td> <td> Возвращает натуральный логарифм х (функция, обратная ехр(х))</td> </tr> <tr> <td> log(b.x)</td> <td> Возвращает логарифм х по основанию b</td> </tr> <tr> <td> log(x)</td> <td> Возвращает десятичный логарифм х</td> </tr> <tr> <td> modtx.yj</td> <td> Возвращает остаток от деления х/у</td> </tr> <tr> <td> pi О</td> <td> Возвращает константу к (3,14159...)</td> </tr> <tr> <td> pow(x.y)</td> <td> Возвращает х в степени у</td> </tr> <tr> <td> radians(d)</td> <td> Возвращает количество радиан в d градусов</td> </tr> <tr> <td> ranaomO</td> <td> Возвращает псевдослучайное число в интервале от 0,0 до 1,0</td> </tr> <tr> <td> round(x)</td> <td> Возвращает число х, округленное до ближайшего целого</td> </tr> <tr> <td> sin(x)</td> <td> Возвращает синус х</td> </tr> <tr> <td> sqrt(x)</td> <td> Возвращает квадратный корень х</td> </tr> <tr> <td> tan(x)</td> <td> Возвращает тангенс х</td> </tr> <tr> <td> trunc(x)</td> <td> Возвращает целую часть х</td> </tr> <tr> <td> trunc(x.s)</td> <td> Возвращает значение х, усеченное до s цифр в дробной части</td> </tr> </table> Ниже приведены более подробные описания всех функций, перечисленных в таблице, с указанием аргументов, типов данных и выполняемых действий. Хотя функция обычно принимает аргументы лишь одного типа, PostgreSQL при необходимости пытается привести переданные аргументы к нужному типу. Если попытка автоматического преобразования типа завершается неудачей, PostgreSQL выводит сообщение об ошибке и вы можете попытаться выполнить явное преобразование. Дополнительная информация о явном преобразовании типов приведена в главе 3. <br> abs(x) <br> Синтаксис: <br> abs(x) <br> Функция abs() получает один числовой аргумент х и возвращает его модуль, то есть расстояние до нуля. Положительные числа остаются без изменений, а отрицательные числа меняют знак. <br> Аргумент функции abs() может относиться к любому из числовых типов данных (numeric, bigint, small int, real или double precision). Тип возвращаемого значения совпадает с типом аргумента. <br> <br><br> <h1>Нетривиальные возможности</h1> <h1>Автоматизация стандартных процедур</h1> <br> <br>Автоматизация стандартных процедур <br><br> PostgreSQL является объектно-реляционной СУБД, что позволило включить в нее ряд нестандартных расширений SQL. Часть этих расширений связана с автоматизацией часто выполняемых операций с базами данных. <br> В этом разделе описаны две категории расширений: последовательности и триггеры. <br> <br><br> <h1>Добавление ограничений в существующую таблицу</h1> <br> <br> Добавление ограничений в существующую таблицу <br><br> Команда ALTER TABLE позволяет включать ограничения в существующую таблицу. Впрочем, в PostgreSQL 7.1.x поддерживается только возможность добавления ограничений CHECK и FOREIGN KEY. <br> Установка ограничений в команде ALTER TABLE имеет следующий синтаксис: <br> ALTER TABLE таблица <br> ADD [ CONSTRAINT ограничение ] { CHECK ( условие ) | FOREIGN KEY ( поле [. ... ] ) <br> REFERENCES таблица [ ( поле [....])] <br> [ MATCH FULL | MATCH PARTIAL ] <br> [ ON DELETE операция ] <br> [ ON UPDATE операция ] <br> [ DEFERRABLE | NOT DEFERRABLE ] <br> [ INITIALLY DEFERRED INITIALLY IMMEDIATE ] } <br> В листинге 7.9 устанавливается новое ограничение FOREIGN KEY для поля subjected, которое связывается с полем id таблицы subjects. Ограничение гарантирует, что в результате вставки или обновления данных в поле subjected таблицы books не появятся значения, отсутствующие в поле id таблицы subjects. <br> <br><br> <h1>Функциональные индексы</h1> <br> <br> Функциональные индексы <br><br> В слегка измененном виде команда CREATE INDEX позволяет индексировать данные не по значениям поля, а по некоторой функции этих значений. Такая форма индекса называется функциональной. <br> Команда создания функционального индекса имеет следующий синтаксис: <br> CREATE [ UNIQUE ] INDEX индекс ON таблица <br> [ USING тип ] ( функция ( поле [. ...])[ класс ] ) <br> Единственное отличие этой команды от описанной выше заключается в том, что индекс строится по результатам применения функции к каждому значению поля. Остальные элементы те же. <br> Функциональные индексы часто строятся для полей, значения которых проходят предварительную обработку перед сравнением в команде SQL. Например, при сравнении строковых данных без учета регистра символов часто используется функция иррегО. Создание функционального индекса с функцией иррегО улучшает эффективность таких сравнений. <br> В листинге 7.5 приведен пример построения индекса upper_title для таблицы books. Данные индексируются по результатам применения функции upper () к полю title. Затем выполняется запрос SQL, который благодаря наличию функционального индекса выполняется более эффективно. <br> <br><br> <h1>Индексы элементов</h1> <br> <br> Индексы элементов <br><br> Популярность массивов в значительной степени обусловлена тем фактом, что к отдельным элементам можно обращаться при помощи индексов — целых чисел, заключенных в скобки и описывающих позицию искомого элемента в массиве. <br> В отличие от таких языков программирования, как С, в PostgreSQL индексация в массивах начинается с 1, а не с 0. Так, в листинге 7.21 индекс [1] для поля books таблицы favorite_books описывает первый элемент массива. Обратите внимание: данные, возвращаемые запросом, не заключаются в кавычки или фигурные скобки. Это связано с тем, что отдельное текстовое значение должно возвращаться в виде одной текстовой константы, а не массива. <br> <br><br> <h1>Индексы</h1> <br> <br>Индексы <br><br> Индексом называется объект базы данных, позволяющий значительно повысить скорость обращения к базе за счет ускоренной обработки команд, содержащих сравнительные критерии. Хранимая в индексах информация о размещении данных по одному или нескольким полям таблицы повышает эффективность поиска записей при условной выборке (например, с использованием секции WHERE). <br> Существует несколько разновидностей внутреннего устройства индексов. В этом разделе описаны разные типы индексов, а также объясняется, в каких ситуациях следует использовать тот или иной тин. <br> Индексы ускоряют доступ к базе, но они также сопряжены с дополнительными затратами ресурсов. При изменении данных в поле индекс приходится обновлять, поэтому поддержание редко используемых индексов отрицательно сказывается на быстродействии системы (затраты времени на поддержание индексов превышают экономию от их использования). Как правило, индексы определяются только для полей, часто указываемых в условиях поиска. <br> <br><br> <h1>Использование курсоров</h1> <br> <br> Использование курсоров <br><br> Курсор SQL в PostgreSQL представляет собой доступный только для чтения указатель на итоговый набор выполненной команды SELECT. Курсоры часто используются в приложениях, хранящих информацию о состоянии подключения к серверу PostgreSQL. Создание курсора и работа со ссылкой на полученный итоговый набор позволяет приложению организовать более эффективную выборку разных записей итогового набора без повторного выполнения запроса с другими значениями LIMIT и OFFSET. <br> В прикладных интерфейсах (API) курсоры часто используются для объединения нескольких запросов с последующим их отслеживанием и управлением ими через ссылку на курсор на уровне приложения. Тем самым предотвращается необходимость хранения всех результатов в памяти приложения. <br> Курсоры часто обладают абстрактным представлением в прикладных интерфейсах (пример — класс PgCursor в libpq++), хотя приложение может напрямую создавать курсоры и работать с ними при помощи стандартных команд SQL. В этом подразделе описаны обобщенные принципы работы с курсорами в SQL, продемонстрированные на примере клиента psql. В PostgreSQL существуют четыре команды, предназначенные для работы с курсорами: DECLARE, FETCH, MOVE и CLOSE. <br> Команда DECLARE определяет и одновременно открывает курсор, после чего заполняет его информацией по результатам итогового набора выполненного запроса. Команда FETCH позволяет получить записи из открытого курсора. Команда MOVE перемещает «текущую» позицию курсора в итоговом наборе, а команда CLOSE закрывает курсор. <br> Примечание 1 <br>Примечание 1<br><br><br> Если вас интересует тема использования курсоров в конкретном интерфейсе API, обращайтесь к документации на API. <br> <br><br> <h1>Использование производных таблиц</h1> <br> <br> Использование производных таблиц <br><br> Связь общих полей базовой и производной таблиц не ограничивается чисто косметическими удобствами. Данные, занесенные в таблицу distinguished_authors, присутствуют и в родительской таблице authors. Впрочем, в таблице authors видны только три унаследованных поля. В запрос к базовой таблице можно включить ключевое слово ONLY, которое указывает, что данные производных таблиц исключаются из результатов запроса. <br> Примечание 2 <br>Примечание 2<br><br> Вставка данных в производную таблицу <br> booktown=# INSERT INTO distinguished_authors <br> booktown-# VALUES (nextvaK 'authorjds'), <br> booktown(# 'Simon'. 'Neil', 'Pulitzer Prize'); <br> INSERT 3629421 1 <br> Поскольку первые три поля таблицы di sti ngui shed_authors были унаследованы от таблицы authors, данные этой записи косвенно включаются в таблицу authors (хотя непосредственная вставка в таблицу authors не выполнялась). Тем не менее поле award будет присутствовать только в таблице di sti ngui shed_authors, поскольку наследование действует только в одну сторону (от родителя к потомку). <br> В листинге 7.13 выполняются три команды SELECT. В секциях FROM указываются разные цели, тогда как условия в секциях WHERE всех трех команд одинаковы. <br> <br><br> <h1>Построение индекса</h1> <br> <br>Листинг 7.1. Построение индекса <br><br> booktown=# CREATE INDEX books_title_idx <br> booktown-# ON books (title);<br> <br> CREATE <br> booktown=# \d books <br> Table "books" Attribute | Type | Modifier <br> id | integer | not null <br> title | text | not null <br> authorjd |integer | <br> subjectjd I integer <br> Indices: books_id_pkey. books_titlejdx <br> Установка некоторых типов ограничений (прежде всего, ограничения PRIMARY KEY и UNIQUE) также приводит к автоматическому построению индекса. В листинге 7.2 при создании таблицы authors для поля id устанавливается ограничение первичного ключа (PRIMARY KEY). В результате автоматически строится индекс authors_pkey. <br> <br><br> <h1>Удаление ограничений</h1> <br> <br>Листинг 7.10. Удаление ограничений <br><br> booktown=*# DROP INDEX books_id_pkey; <br> DROP <br> booktown=# CREATE TABLE new_books <br> booktown-# (id integer CONSTRAINT books_id_pkey PRIMARY KEY. <br> booktown(# title text NOT NULL. <br> booktown(# author_id integer. <br> booktown(# subjected integer): <br> NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index 'books_id_pkey' <br> for table 'new_books' <br> CREATE <br> booktown=# INSERT INTO new_books SELECT * FROM books: <br> INSERT 0 15 <br> booktown=f ALTER TABLE books RENAME TO old_books: <br> ALTER <br> booktown=# ALTER TABLE new_books RENAME TO books; <br> ALTER <br> <br><br> <h1>Создание производной таблицы</h1> <br> <br>Листинг 7.11. Создание производной таблицы <br><br> booktown=# CREATE TABLE distinguished_authors (award text) <br> booktown-# INHERITS (authors): CREATE <br> booktown=# \d distinguished_authors Table "distinguished_authors" <br> Attribute | Type Modifier <br> id | integer | not null <br> lastjiame text | <br> firstjiame | text <br> award text <br> Как видите, несмотря на то что в листинге 7.11 определено всего одно поле, таблица distinguished_authors унаследовала все поля исходной таблицы authors. <br> <br><br> <h1>Выборка с наследованием</h1> <br> <br>Листинг 7.13. Выборка с наследованием <br><br> booktown=# SELECT * FROM distinguished_authors <br> booktown-# WHERE lastjiame - 'Simon'; <br> id | last_name firstjname award <br> 25043 | Simon | Neil | Pulitzer Prize <br> (1 row) <br> booktown=# SELECT * FROM authors WHERE last_name - 'Simon'; <br> Id last_name first_name <br> 25043 | Simon | Neil (1 row) <br> booktown=# SELECT * FROM ONLY authors WHERE <br> lastjname = 'Sinon': id i last_name | first_name <br> (0 rows) <br> Все три запроса в листинге 7.13 производят выборку записей, у которых поле 1 astjname совпадает со строковой константой Simon. Первый запрос извлекает данные из таблицы distinguished_authors, в которую они были первоначально занесены (см. листинг 7.12). <br> Второй запрос в листинге 7.13 производит выборку из таблицы authors, базовой по отношению к distinguished_authors. В этом случае запись также возвращается, но в нее включаются только поля, унаследованные таблицей di st i ngui shed_authors. <br> Следует хорошо понимать, что данные в действительности не заносятся в базовую таблицу, а лишь становятся видимыми в ней благодаря отношению наследования. Это доказывает третий и последний запрос в листинге 7.13, в котором перед именем таблицы authors находится ключевое слово ONLY. Оно означает, что выборка производится только из базовой таблицы, а производные таблицы игнорируются; в результате запрос не возвращает ни одной записи. <br> Наследование может приводить к видимому нарушению ограничений. Например, значение поля, для которого установлено ограничение уникальности, может повторяться в данных производных таблиц. Применение наследования требует осторожности, поскольку производная таблица формально не нарушает ограничений, хотя при выборке из базовой таблицы без ключевого слова ONLY может показаться обратное. <br> <br><br> <h1>Модификация базовых и производных таблиц</h1> <br> <br>Листинг 7.14. Модификация базовых и производных таблиц <br><br> booktown=# UPDATE authors SET firstjiame - 'Paul' <br> booktown-# WHERE last_name = 'Simon'; <br> UPDATE 1 <br> booktown=# SELECT * FROM distinguished_authors; <br> id | lastjiame first_name award ---25043 <br> Simon | Paul Pulitzer Prize <br> (1 row) <br> Ключевое слово ONLY выполняет в командах UPDATE и DELETE те же функции, что и в команде SELECT — оно предотвращает каскадные модификации, продемонстрированные в листинге 7.14. Согласно правилам синтаксиса SQL ключевое слово ONLY всегда предшествует имени производной таблицы. <br> Пример использования ключевого слова ONLY приведен в листинге 7.15. Сначала в таблице distinginshed_authors создается запись, в которой заполняется поле award. В результате в таблице authors появляются две разные записи для одного автора. Затем старая запись (физически находящаяся в таблице authors) удаляется командой SQL DELETE с ключевым словом ONLY. <br> <br><br> <h1>Модификация базовых</h1> <br> <br>Листинг 7.15. Модификация базовых таблиц с ключевым словом ONLY <br><br> booktown=# INSERT INTO distinguished_authors<br> booktown-* VALUES (1809. 'Geisel'. <br> booktown(# 'Theodor Seuss', 'Pulitzer Prize');<br> <br> INSERT 3629488 1 <br> booktown=# SELECT * FROM authors <br> booktown-# WHERE lastjname = 'Geisel': <br> id | lastjname | firstjiame <br> 1809 | Geisel | Theodor Seuss 1809 | Geisel | <br> Theodor Seuss <br> (2 rows) <br> booktown=# DELETE FROM ONLY authors <br> booktown-# WHERE lastjiame = 'Geisel'; <br> DELETE 1 <br> В итоге после выполнения листинга 7.15 запись появляется в таблице distinguished_authors и удаляется из таблицы authors: <br> booktown=# SELECT * FROM authors <br> booktown-# WHERE lastjiame = 'Geisel': <br> id | lastjiame | firstjiame <br> 1809 Geisel | Theodor Seuss <br> (1 row) <br> booktown=# SELECT * FROM distinguishedjauthors <br> booktown-# WHERE lastjiame = 'Geisel1; <br> id | lastjiame | firstjiame | award <br> 1809 | Geisel | Theodor Seuss | Pulitzer Prize <br> (1 row) <br> <br><br> <h1>Создание таблицы с полеммассивом</h1> <br> <br>Листинг 7.16. Создание таблицы с полем-массивом <br><br> booktown=# CREATE TABLE favorite_books <br> booktown-# (employeejid integer, books text[]);<br> <br> CREATE <br> Таблица, созданная в листинге 7.16, позволяет хранить в одном поле неограниченное количество названий книг. Преимущество массива перед объединением названий в одну строку (которая, конечно, тоже может содержать несколько названий) заключается в их физической изоляции. Система знает, где начинается и где кончается каждое название, поэтому выборка может производиться по индексу элемента вместо ручного разбора длинной строки на составляющие. <br> Многомерные массивы создаются аналогичным образом, просто за первой парой квадратных скобок добавляются дополнительные пары. В листинге 7.17 создается таблица favorite_authors с целочисленным полем employee_id и многомерным массивом author_and_titles. Фактически мы создаем массив текстовых массивов. <br> <br><br> <h1>Создание таблицы</h1> <br> <br>Листинг 7.17. Создание таблицы с полем, содержащим многомерный массив <br><br> booktown=# CREATE TABLE favorite_authors (employee_id Integer, <br> booktowntf authors_and_titles text[][]);<br> <br> CREATE <br> <br><br> <h1>Вставка с использованием массивовконстант</h1> <br> <br>Листинг 7.18. Вставка с использованием массивов-констант <br><br> booktown=# INSERT INTO favorite_books VALUES <br> booktown-# (102, '{"The HitchhikerVs Guide to the Galaxy"}');<br> <br> INSERT 3628399 1 <br> booktown=# INSERT INTO favorite_books VALUES <br> booktown-# (103, '{"The Hobbit". "Kitten, Squared"}');<br> <br> INSERT 3628400 1 <br> Как видно из листинга, даже при вставке одного элемента массив заключается в фигурные скобки. Кроме того, обратите внимание, что апостроф в названии книги (первая команда INSERT) экранируется символом \, хотя и находится внутри кавычек. Это связано с тем, что массив-константа сначала обрабатывается как одна длинная строка, а затем интерпретируется как массив по контексту целевого поля. <br> При вставке значений в многомерный массив все подмассивы заключаются в отдельные фигурные скобки и разделяются запятыми. В листинге 7.19 приведен пример вставки одной записи с многомерным массивом-константой в таблицу favorite_authors, созданную в листинге 7.17. <br> <br><br> <h1>Вставка данных в многомерный массив</h1> <br> <br>Листинг 7.19. Вставка данных в многомерный массив <br><br> booktown=# INSERT INTO favorite_authors <br> bOOktown-# VALUES (102, <br> booktown(# '{{"J.R.R. Tolkien". "The Silmarillion"}, <br> booktown'# {"Charles Dickens", "Great Expectations"}, <br> booktown'l {"Ariel Denham", "Attic Lives"}}');<br> <br> INSERT 3727961 1 <br> Многомерный массив в листинге 7.19 содержит три текстовых массива, каждый из которых состоит из двух элементов. Между массивами не существует никаких систематических связей, хотя из контекста следует, что первые элементы каждого массива обозначают авторов, а вторые элементы обозначают названия книг, написанных этими авторами. <br> <br><br> <h1>Автоматическое построение индекса</h1> <br> <br>Листинг 7.2. Автоматическое построение индекса <br><br> booktown=# CREATE TABLE authors (id integer PRIMARY KEY, <br> booktown(# last_name text, <br> booktown(# first_name text);<br> <br> NOTICE: CREATE TABtE/PRIMARY KEY will create implicit index 'authors_pkey' for <br> table 'authors' <br> CREATE <br> example=# \d authors <br> Table "authors" <br> Attribute | Type Modifier <br> id integer | not null <br> lastjiame | text <br> firstjiame text | <br> Index: authors_pkey <br> Индекс, построенный командой из листинга 7.2, позволяет PostgreSQL быстро проверять уникальность первичного ключа для всех новых записей, заносимых в таблицу. Кроме того, индекс повышает скорость выполнения запросов, у которых поле i d указано в условии поиска. <br> <br><br> <h1>Выборка из полеймассивов</h1> <br> <br>Листинг 7.20. Выборка из полей-массивов <br><br> booktown=# SELECT books FROM favorite_books; <br> books <br> {"The Hitchhiker's Guide to the Galaxy"} <br> {"The Hobbit"."Kitten. Squared") <br> (2 rows) <br> Хотя возможность выборки всего массива приносит несомненную пользу, на практике чаще требуется получить некоторое подмножество элементов. Для решения этой задачи необходимо познакомиться с такими новыми понятиями, как индексы элементов и срезы массивов. <br> <br><br> <h1>Выборка отдельного элемента массива</h1> <br> <br>Листинг 7.21. Выборка отдельного элемента массива <br><br> booktown=# SELECT books[l] FROM favorite_books: <br> books <br> The Hitchhiker's Guide to the Galaxy The Hobbit <br> (2 rows) <br> При указании индекса несуществующего элемента массива выборка возвращает NULL. Обычно для обработки таких ситуаций используется конструкция IS NOT NULL. В листинге 7.22 приведены два запроса; первый возвращает две записи — для NULL и для названия книги. Второй запрос возвращает только название, а запись с NULL исключается из выборки в результате использования секции WHERE с проверкой условия NOT NULL. <br> <br><br> <h1>Предотвращение выборки NULL в массивах</h1> <br> <br>Листинг 7.22. Предотвращение выборки NULL в массивах <br><br> booktown=# SELECT books[2] FROM favorite_books; <br> books <br> Kitten. Squared (2 rows) <br> booktown=# SELECT books[2] FROM favorite_books <br> booktown-# WHERE books[2] IS NOT NULL; <br> books <br> Kitten. Squared <br> (1 row) <br> При выборке из многомерного массива за исходным индексом перечисляются дополнительные индексы. В листинге 7.23 из таблицы favorite_authors, созданной в листинге 7.19, выбираются два элемента — имя автора и название книги. <br> <br><br> <h1>Выборка из многомерного массива</h1> <br> <br>Листинг 7.23. Выборка из многомерного массива <br><br> booktown=# SELECT authors_and_titles[l][l] AS author, <br> booktown-# authors_and_titles[l][2] AS title <br> booktown-# FROM favorite authors; <br> author I title <br> J.R.R. Tolkien | The Silmarillion <br> (1 row) <br> <br><br> <h1>Выборка с использованием среза</h1> <br> <br>Листинг 7.24. Выборка с использованием среза <br><br> booktown=# SELECT books[l:2] FROM favorite_books; <br> books <br> {"The Hitchhiker's Guide to the Galaxy"} <br> {"The Hobbit"."Kitten, Squared"} <br> (2 rows) <br> В PostgreSQL 7.1.x использование срезов в многомерных массивах иногда приводит к непредсказуемым последствиям. По этой причине, пока не будут внесены исправления, при работе с многомерными массивами рекомендуется обращаться к элементам по конкретным значениям индексов. <br> <br><br> <h1>Функция array_dims()</h1> <br> <br>Листинг 7.25. Функция array_dims() <br><br> booktown=# SELECT array_dims(books) FROM favorite_books; <br> array_dims <br> [1:1] <br> [1:2] <br> (2 rows) <br> Обновление данных в полях-массивах <br> Существует три варианта модификации данных в полях-массивах. <br> <ul> <li> Полная модификация. Все содержимое массива заменяется новыми данными, заданными в виде массива-константы. </li> <li> Модификация среза. Срез (то есть интервальное подмножество элементов) заменяется новыми данными, заданными в виде массива-константы. Количествоэлементов в константе должно соответствовать количеству элементов в обновляемом срезе. </li> <li> Модификация элемента. Отдельный элемент массива заменяется новой константой, относящейся к базовому типу данных массива. Элемент задается индексом. В первом случае количество элементов в новом массиве может не совпадать с количеством элементов в существующем массиве. Допустим, работник с кодом 1d=102 хочет добавить данные о новой книге в список, хранящийся в таблице favorite_books. Команда UPDATE, приведенная в листинге 7.26, заменяет все текущее содержимое массива. </li> </ul> <br><br> <h1>Полная модификация массива</h1> <br> <br>Листинг 7.26. Полная модификация массива <br><br> booktown=# UPDATE favorite_books <br> booktown-# SET books='{"The HitchhikerVs Guide to the Galaxy", <br> booktown'# "The Restaurant at the End of the Universe"}' <br> booktown-# WHERE employeejd = 102; <br> UPDATE 1 <br> Способ, продемонстрированный в листинге 7.26, подходит и для модификации среза массива. Для этого в конец идентификатора поля добавляется определение среза, например, books[l:3] означает первый, второй и третий элементы массива. Впрочем, на практике чаще возникает задача замены не всего массива и не среза, а отдельных элементов. <br> При обновлении отдельного элемента к идентификатору поля присоединяется индекс, определяющий конкретный обновляемый элемент*. В листинге 7.27 приведен пример обновления первого элемента в массиве books таблицы favorite_books. <br> <br><br> <h1>Модификация отдельного элемента</h1> <br> <br>Листинг 7.27. Модификация отдельного элемента <br><br> booktown=# SELECT books[l] FROM favorite_books; <br> books <br> The Hitchhiker's Guide to the Galaxy The Hobbit <br> (2 rows) <br> booktown=# UPDATE favorite_books <br> booktown-# SET books[l] = 'There and Back Again: A HobbitVs Holiday' <br> booktown-# WHERE books[l] = 'The Hobbit'; <br> UPDATE 1 <br> booktown=# SELECT books[l] FROM favorite_books; <br> books <br> The Hitchhiker's Guide to the Galaxy <br> There and Back Again: A Hobbit's Holiday <br> (2 rows)<br> <br><br> <h1>Создание последовательности</h1> <br> <br>Листинг 7.28. Создание последовательности <br><br> booktown-# CREATE SEQUENCE shipments_ship_id_seq <br> booktown-# MINVALUE 0; <br> CREATE <br> <br><br> <h1>Вывод атрибутов последовательности</h1> <br> <br>Листинг 7.29. Вывод атрибутов последовательности <br><br> booktown=# SELECT 1ast_value, increment_by <br> booktown-# FROM shipments_ship_id_seq; <br> last_value increment_by <br> 0 | 1 <br> (1 row) <br> Запрос обращен к только что созданной последовательности, поэтому атрибут 1 ast_val ue остался равным нулю. <br> <br><br> <h1>Создание уникального индекса</h1> <br> <br>Листинг 7.3. Создание уникального индекса <br><br> booktown-* CREATE UNIQUE INDEX unique_publisherjdx <br> booktown-# ON publishers (name): <br> CREATE <br> booktown=# \d publishers <br> Table "publishers" Attribute | Type | Modifier <br> id integer | not null <br> name | text <br> address j text j Indices: publishers_pkey. <br> urn que_publ i sher_i dx <br> Поскольку псевдозначение NULL формально не совпадает ни с одним реальным значением, в поле с уникальным индексом допускаются многократные вхождения NULL. В этом и заключается главное практическое различие между уникальным индексом и индексом, автоматически создаваемым при установке ограничения PRIMARY KEY, которое вообще запрещает присутствие значений NULL. <br> ВНИМАНИЕ<br> Ключевое слово UNIQUE в сочетании с секцией USING может использоваться только для индексов, реализованных в виде В-дерева. <br> <br><br> <h1>Изменение текущего значения последовательности</h1> <br> <br>Листинг 7.30. Изменение текущего значения последовательности <br><br> booktown=# SELECT nextvaH 'shipments_shipjd_seq');<br> <br> nextval <br> 1 (1 row) <br> booKtown=# SELECT nextval ('shipments_ship_id_seq'): <br> nextval <br> 2 <br> (1 row) <br> Примечание 1 <br>Примечание 1<br><br><br> При первом вызове функция nextval О возвращает начальное значение последовательности (заданное с ключевым словом START). Причина — функция не вызывалась, поэтому приращение еще не произошло. При всех последующих вызовах nextval () атрибут last_value изменяется. <br> Последовательности часто используются при определении значений по умолчанию для таблиц, в которых должны храниться уникальные целочисленные идентификаторы. Пример приведен в табл. 7.2. <br> <br><br> <h1>Функция currval()</h1> <br> <br>Листинг 7.31. Функция currval()<br><br> booktown=# INSERT INTO shipments (customer_id, isbn, ship_date) <br> booktown-# VALUES (221. '0394800753', 'now');<br> INSERT 3628625 1 <br> booktown=# SELECT * FROM shipments <br> booktown-# WHERE Id = currval('shipments_ship_id_seq'): <br> id | customerjd | Isbn | ship_date <br> 1002 ! 107 | 0394800753 | 2001-09-22 11:23:28-07 <br> (1 row) <br> Наконец, функция setval () присваивает атрибуту 1 ast_val lie последовательности произвольное число из интервала допустимых значений. Первый аргумент функции содержит имя последовательности, заключенное в апострофы, а второй аргумент содержит целочисленную константу, представляющую новое значение last_value. <br> Существует два варианта вызова функции setval О. По умолчанию предполагается, что новое значение относится к инициализированной последовательности; это означает, что следующее значение, возвращенное nextval О, уже будет увеличено по отношению к величине, переданной при вызове setval О. <br> Кроме того, последовательность можно деинициализировать, для чего в необязательном последнем аргументе передается логическая величина false. Последовательность изменяется так, что следующий вызов nextval О вернет то же число, которое было передано при вызове setval () (хотя при следующем вызове nextval () последовательность увеличится). <br> В листинге 7.32 приведены оба варианта замены текущего значения последовательности shipments_ship_id_seq с последующими вызовами nextval О, демонстрирующими полученный результат. <br> <br><br> <h1>Изменение текущего значения последовательности</h1> <br> <br>Листинг 7.32. Изменение текущего значения последовательности <br><br> booktown=# SELECT setval('shipments_ship_1d_seq'. 1010);<br> <br> setval <br> 1010 <br> (1 row) <br> booktown=# SELECT nextval('shipments_ship_id_seq');<br> <br> nextval <br> 1011 <br> (1row) <br> booktown=# SELECT setvalСshipments_ship_id_seq', 1010. false);<br> <br> setval <br> 1010 <br> (1 row) <br> booktown=# SELECT nextval ('shipnients_ship_id_seq');<br> <br> nextval <br> 1010 <br> (1 row) <br> ВНИМАНИЕ <br> Последовательности обычно применяются для обеспечения уникальности значений полей. Прежде чем изменять атрибут 1ast_value, убедитесь в том, что вы хорошо понимаете все возможные последствия. <br> <br><br> <h1>Удаление последовательности</h1> <br> <br>Листинг 7.33. Удаление последовательности <br><br> booktown=# DROP SEQUENCE shipments_ship_id_seq; <br> DROP <br> Прежде чем уничтожать последовательность, убедитесь в том, что она не используется другой таблицей, функцией или другим объектом базы данных. Если забыть об этой проверке, это нарушит работу других операций, зависящих от данной последовательности. Следующий запрос возвращает имена всех отношений, в которых заданная последовательность используется при вычислении значений по умолчанию: <br> SELECT p.relname. a.adsrc FROM pg_class p <br> JOIN pg_attrdef a ON (p.relfilenode = a.adrelid) <br> WHERE a.adsrc - '"последовательность"'; <br> В листинге 7.34 с помощью этого запроса выполняется поиск имен таблиц, у которых последовательность shipments_ship_id_seq используется для вычислений значений по умолчанию. <br> <br><br> <h1>Проверка зависимостей</h1> <br> <br>Листинг 7.34. Проверка зависимостей <br><br> Dooktown=# SELECT p.relname. a.adsrc FROM pg_class p JOIN pg_attrdef a <br> booktown-# ON (p.relfilenode = a.adrelid) <br> booktown-# WHERE a.adsrc - '"shipments_ship_id_seq"'; <br> relname | adsrc <br> shipments | nextvaK'"sh1pments_ship_id_seq"'::text) <br> (1 row) <br> <br><br> <h1>Создание триггера check_shipment</h1> <br> <br>Листинг 7.35. Создание триггера check_shipment <br><br> booktown=# CREATE TRIGGER check_shipment <br> booktown-# BEFORE INSERT OR UPDATE <br> booktown-# ON shipments FOR EACH ROW <br> booktown-# EXECUTE PROCEDURE check_shipment_addition();<br> <br> CREATE <br> Триггер check_shipment настроен на выполнение функции check_shipment_addition() для команд INSERT и UPDATE, поэтому он достаточно надежно обеспечивает логическую целостность данных в полях customerjd и i sbn. Ключевое слово ROW гарантирует, что каждая добавляемая или модифицируемая запись будет обработана функцией проверки check_argument_addition(). <br> Функция check_shipment_addition() вызывается без аргументов, поскольку для проверки записей в ней используются внутренние переменные PL/pgSQL. Реализация функции check_shipments_addition() на языке PL/pgSQL приведена в главе 11. <br> <br><br> <h1>Удаление триггера</h1> <br> <br>Листинг 7.36. Удаление триггера <br><br> booktown=# DROP TRIGGER check_shipment ON shipments: <br> DROP <br> Сообщение DROP означает, что триггер успешно удален. Обратите внимание: при удалении указывается не только имя удаляемого триггера, но и имя таблицы. <br> Если вы не помните, в какой таблице был установлен удаляемый триггер, необходимую информацию можно получить из системных таблиц PostgreSQL. Например, можно провести объединение полей tgrelid системной таблицы pg_trigger и поля rel f i I enode системной таблицы pg_cl ass и сравнить имя триггера с полем tgname. Запрос, приведенный в листинге 7.37, возвращает имя отношения (rel name), связанного с триггером check_shipment. <br> <br><br> <h1>Получение имени таблицы связанной с триггером</h1> <br> <br>Листинг 7.37. Получение имени таблицы, связанной с триггером <br><br> booktown=# SELECT relname FROM pg_class <br> booktown-# INNER JOIN pg_trigger <br> booktown-# ON (tgrelid = relfilenode) <br> booktown-# WHERE tgname = 'check_shipment': . <br> relname <br> shipments <br> (1 row) <br> ВНИМАНИЕ<br> При удалении функции, вызываемой по срабатыванию триггера, триггер перестает работать, причем повторное определение функции с тем же именем не исправит проблему. После повторного создания функции триггер также приходится создавать заново.<br> <br><br> <h1>Создание транзакции</h1> <br> <br>Листинг 7.38. Создание транзакции <br><br> bOOktown=# BEGIN; <br> BEGIN <br> С точки зрения пользователя, вносящего изменения в базу данных, все команды SQL после команды BEGIN выполняются немедленно. Но как упоминалось выше, для других пользователей эти изменения остаются невидимыми вплоть до момента фиксации транзакционного блока. <br> Транзакционный блок завершается командой SQL COMMIT, за которой также могут следовать необязательные ключевые слова WORK или TRANSACTION. В листинге 7.39 команда SQL COMMIT синхронизирует состояние базы данных с результатами команды UPDATE. <br> <br><br> <h1>Фиксация транзакции</h1> <br> <br>Листинг 7.39. Фиксация транзакции <br><br> booktown-# BEGIN; BEGIN <br> booktown=# UPDATE subjects SET location = NULL <br> booktown-f WHERE id = 12; <br> UPDATE 1 <br> booktown=# SELECT location FROM subjects WHERE id - 12: <br> location <br> (1 row) <br> booktown=# COMMIT; <br> COMMIT <br> Как видно из листинга, хотя результаты команды UPDATE немедленно отражаются на выборке, выполняемой командой SELECT, другие пользователи, подключенные к той же базе данных, ничего не будут знать о них вплоть до выполнения команды COMMIT. <br> Транзакции откатываются командой SQL ROLLBACK, за которой также могут следовать необязательные ключевые слова WORK или TRANSACTION. <br> В листинге 7.40 мы создаем транзакцию, вносим изменения в таблицу subjects и убеждаемся в их присутствии. Затем транзакция откатывается, и таблица возвращается к состоянию, в котором она находилась до начала транзакции. <br> <br><br> <h1>Выбор типа индекса</h1> <br> <br>Листинг 7.4. Выбор типа индекса <br><br> booktown=# CREATE TABLE polygons (shape polygon): <br> CREATE <br> booktown=f CREATE INDEX spadaljdx ON polygons USING RTREE (shape);<br> <br> CREATE <br> ВНИМАНИЕ <br> Если у вас нет твердой, обоснованной уверенности в том, что для конкретной ситуации лучше подойдет другой тип индекса, мы рекомендуем использовать стандартный тип BTREE. <br> <br><br> <h1>Откат транзакции</h1> <br> <br>Листинг 7.40. Откат транзакции <br><br> booktown=# и <br> BEGIN <br> booktown=# SELECT * FROM subjects WHERE id = 12; <br> id | subject | location <br> 12 | Religion | (1 row) <br> booktown=# UPDATE subjects SET location = 'Sunset Dr' <br> booktown-# WHERE id = 12; <br> UPDATE 1 <br> booktown=# SELECT * FROM subjects WHERE id = 12; <br> id | subject | location <br> 12 | Religion | Sunset Dr<br> (1 row) <br> booktown=# ROLLBACK; <br> ROLLBACK <br> booktown=# SELECT * FROM subjects WHERE id = 12; <br> id | subject I location <br> 12 ] Religion | <br> (1 row) <br> PostgreSQL предельно строго относится к ошибкам, возникающим при выполнении команд в транзакциях. Даже простейшие ошибки, вроде приведенной в листинге 7.41, переводят транзакцию в аварийное состояние. В этом состоянии запрещается выполнение любых команд, кроме команд завершения транзакции <br> (COMMIT или ROLLBACK). <br> <br><br> <h1>Выход из аварийного состояния</h1> <br> <br>Листинг 7.41. Выход из аварийного состояния <br><br> booktown=# BEGIN: <br> BEGIN <br> booktown=# SELECT * FROM; <br> ERROR: parser: parse error at or near ";" <br> booktown=# SELECT * FROM books; <br> NOTICE: current transaction is aborted, queries ignored until end of transaction <br> *ABORT STATE* <br> booktown=# COMMIT; <br> <br><br> <h1>Объявление курсора</h1> <br> <br>Листинг 7.42. Объявление курсора <br><br> booktown=# BEGIN; <br> BEGIN <br> booktown=# DECLARE all_books CURSOR <br> booktown-# FOR SELECT * FROM books; <br> SELECT <br> Сообщение SELECT в конце листинга 7.42 говорит о том, что команда была выполнена успешно, а записи, полученные в результате запроса, стали доступными для курсора a! l_books. <br> <br><br> <h1>Выборка записей из курсора</h1> <br> <br>Листинг 7.43. Выборка записей из курсора <br><br> booktown=# FETCH 4 FROM all_books; <br> Id | title | authored | suojectjd <br> 7808 | The Shining | 4156 | 9 <br> 4513 | Dune 1 1866 | 15 <br> 4267 I 2001: A Space Odyssey | 2001 | 15 <br> 1608 I The Cat in the Hat j 1809 2 <br> (4 rows) <br> booktown=# FETCH NEXT FROM all_books; <br> id | title | authorjd | subjectjd <br> 1590 Bartholomew and the Oobleck 1809 2 <br> (1 row) <br> booktown=# FETCH PRIOR FROM all_books: <br> id | title | authorjd subjectjd <br> 1608 | The Cat in the Hat | 1809 | 2 <br> (1 row) <br> <br><br> <h1>Перемещение текущей позиции курсора</h1> <br> <br>Листинг 7.44. Перемещение текущей позиции курсора <br><br> booktown=# MOVE FORWARD 10 <br> booktown-# IN all_books; <br> MOVE <br> <br><br> <h1>Закрытие курсора</h1> <br> <br>Листинг 7.45. Закрытие курсора <br><br> booktown=# CLOSE al1_books; <br> CLOSE <br> booktown=# COMMIT: <br> COMMIT <br> <br><br> <h1>Создание функции SQL</h1> <br> <br>Листинг 7.46. Создание функции SQL <br><br> booktown=# CREATE FUNCTION isbn_to_title(text) RETURNS text <br> booktown-l AS 'SELECT title FROM books <br> booktown'f JOIN editions AS e (isbn. id) <br> booktown'# USING (id) <br> booktown'# WHERE isbn = $1' <br> booktown-# LANGUAGE 'SQL'; <br> CREATE <br> Позиционный параметр $1 при выборке заменяется значением первого аргумента в списке, переданном при вызове функции 1sbn_to_title. Позиционный параметр не заключается в отдельные апострофы, поскольку апострофы являются частью переданного аргумента. Остальные составляющие определения функции являются либо идентификаторами, либо стандартными ключевыми словами SQL <br> Сообщение CREATE означает, что создание функции прошло успешно. В листинге 7.47 функция i sbn_to_ti tl e вызывается с одним текстовым аргументом 0929605942. Функция возвращает название книги, связанное с этим кодом ISBN. При этом используется код SQL, содержащийся в листинге 7.46. <br> <br><br> <h1>Использование функции SQL</h1> <br> <br>Листинг 7.47. Использование функции SQL <br><br> booktown=# SELECT isbn_to_title('0929605942');<br> <br> isbn to title <br> The Tell-Tale Heart <br> (1 row) <br> Созданная функция доступна для всех пользователей, обладающих соответствующими правами. Например, для выполнения функции 1sbn_to_title необходим доступ для чтения к таблицам editions и books (права пользователей описаны в главе 10). <br> <br><br> <h1>Функции на языке С</h1> <br> <br>Листинг 7.48. Функции на языке С <br><br> /* 1s_zero.c <br> * Простейшие проверочные функции */ <br> int is_zero(int);<br> <br> int is_zero_two(int. int): <br> int is_zero(int incoming) { <br> /* Вернуть true, если аргумент равен 0. */ <br> if (incoming == 0) return 1; <br> else return 0: } <br> int is_zero_two(int left, int right) { <br> /* Вернуть true, если хотя бы один из аргументов равен 0. */ <br> if (left —0 || right == 0) return 1: <br> else return 0; } <br> ВНИМАНИЕ <br> В этот простейший пример не были включены заголовочные файлы PostgreSQL. В данном случае они не нужны из-за очевидного соответствия между типами данных С и SQL. Более реальные примеры с использованием внутреннего интерфейса API PostgreSQL и структур данных находятся во вложенном каталоге contrib исходного каталога PostgreSQL. <br> В листинге 7.49 файл is_zero.c компилируется с ключом -shared, а полученный общий модуль создается в файле is_zero.so. Путь к файлу передается в определении функции в команде CREATE FUNCTION; атрибут LANGUAGE сообщает, что функция написана на языке С. <br> <br><br> <h1>Создание функции на языке С</h1> <br> <br>Листинг 7.49. Создание функции на языке С <br><br> [jworsley@cmd ~]$ gcc -shared is_zero.c -о is_zero.so <br> [jworsley@cmd -]$ psql -U manager booktown <br> Welcome to psql. the PostgreSQL interactive terminal. <br> Type: \copyright for distribution terms <br> \h for help with SQL commands <br> \? for help on internal slash commands <br> \g or terminate with semicolon to execute query <br> \q to quit <br> booktown-* CREATE FUNCTION is_zero(int4) RETURNS Boolean <br> booktown-l AS '/home/jworsley/is_zero.so' LANGUAGE 'C'; <br> CREATE <br> Команда CREATE FUNCTION в листинге 7.49 создает функцию с именем is_zero(), которая получает один аргумент типа int4 и возвращает значение типа boolean. В объявление включена ссылка на функцию С с именем i s_zero( i nt), реализованную в объектном модуле /home/jworsley/is_zero.so (поскольку в языке С нет типа boo! ean, PostgreSQL приходится преобразовывать целочисленное значение, возвращаемое функцией, к логическому типу). При этом число 0 преобразуется в fal se, a 1 — в true. <br> По умолчанию PostgreSQL ищет в общем модуле функцию с тем же именем, с которым она создается в PostgreSQL. Такой способ подходит для функции i s_zero(i nteger), имя которой соответствует откомпилированному символическому имени функции is_zero(int) в файле is_zero.so. Для предотвращения конфликтов имен вторая функция в общем объектном модуле определяется с сигнатурой is_zero_two(int.int). Чтобы ассоциировать ее с перегруженной функцией PostgreSQL, получающей два аргумента вместо одного, имя функции С в виде строковой константы передастся после пути к файлу общего модуля. <br> Имя указывается без круглых скобок и без перечисления аргументов, а от пути к файлу оно отделяется запятой: <br> CREATE FUNCTION имя ( [ тип_аргумента [. ...] ] ) <br> RETURNS тип_возвращаемого_значения<br> AS 'определение'. 'имя_в_объектном_файле' <br> LANGUAGE 'С' [ WITH ( атрибут [. ...] ) ] <br> В листинге 7.50 подгружается тот же общий модуль, но на этот раз перегруженная функция PostgreSQL ассоциируется с функций С is_zero_two. <br> <br><br> <h1>Построение функционального индекса</h1> <br> <br>Листинг 7.5. Построение функционального индекса <br><br> booktown=# CREATE INDEX upperjtitlejdx ON books <br> booktown-f (upper(title));<br> <br> CREATE <br> booktown=# SELECT title FROM books WHERE upper(title) = 'DUNE'; <br> title <br> Dune <br> (1 row) <br> <br><br> <h1>Перегрузка функции С</h1> <br> <br>Листинг 7.50. Перегрузка функции С <br><br> booktown=# CREATE FUNCTION is_zero(int4. int4) RETURNS Boolean <br> booktown-# AS '/home/jworsley/is_zero.so'. 'is_zero_two' <br> booktown-* LANGUAGE 'C': <br> CREATE <br> Функции С, как и функции SQL, могут вызываться любым пользователем. Функции С могут вносить прямые изменения в файловую систему (если позволяют права) и производить операции системного уровня, поэтому к их проектированию следует подойти особенно тщательно, чтобы избежать потенциальных злоупотреблений. В листинге 7.51 приведены примеры нескольких вызовов функции i s_zero, определенной в листинге 7.49, и ее перегруженной версии из листинга 7.51. <br> <br><br> <h1>Использование функций С</h1> <br> <br>Листинг 7.51. Использование функций С <br><br> booktown=# SELECT is_zero(0) AS zero. is_zero(l) AS one, <br> booktown-# 1s_zero(6. 0) AS one_zero, is_zero(11.12) AS neither: <br> zero | one | one_zero | neither <br> t [ f | t | f <br> (1 row) <br> <br><br> <h1>Удаление функции</h1> <br> <br>Листинг 7.52. Удаление функции <br><br> booktown=# DROP FUNCTION isbn_to_title(text);<br> <br> DROP <br> Сообщение сервера DROP означает, что функция была успешно удалена. Команда DROP FUNCTION, как и большинство команд DROP, необратима, поэтому перед ее выполнением убедитесь в том, что функцию действительно требуется удалить. <br> <br><br> <h1>Создание пользовательского оператора</h1> <br> <br>Листинг 7.53. Создание пользовательского оператора <br><br> booktown=# CREATE OPERATOR !# (PROCEDURE = is_zero, <br> booktown(# LEFTARG = integer);<br> <br> CREATE <br> Сообщение CREATE означает, что создание оператора прошло успешно. Новый оператор становится доступным для любого пользователя, подключенного к базе данных (по аналогии с функциями). Оператор принадлежит пользователю, создавшему его, и поэтому не может быть удален другим пользователем, не обладающим правами суперпользователя. В листинге 7.54 новый оператор !# возвращает из таблицы stock список книг, отсутствующих на складе. <br> <br><br> <h1>Применение пользовательского оператора</h1> <br> <br>Листинг 7.54. Применение пользовательского оператора <br><br> booktown=# SELECT * FROM stock WHERE stock !#; <br> isbn | cost | retail | stock <br> 0394900014 | 23.00 | 23.95 | 0 <br> 0451198492 | 36.00 | 46.95 | 0 <br> 0451457994 | 17.00 j 22.95 | 0 <br> (3 rows) <br> <br><br> <h1>Перегрузка пользовательского оператора</h1> <br> <br>Листинг 7.55. Перегрузка пользовательского оператора <br><br> booktown=# CREATE OPERATOR !# (PROCEDURE = is_zero. <br> booktown(# RIGHTARG = integer);<br> <br> CREATE <br> booktown=# CREATE OPERATOR !# (PROCEDURE = is_zero, <br> booktown(# LEFTARG = integer, <br> booktown(# RIGHTARG = integer);<br> <br> CREATE <br> В листинге 7.55 оператор !# перегружается с тем же именем функции is_zero(), поскольку сама функция была перегружена в листинге 7.50 (см. пункт «Создание функций на языке С» в подразделе «Создание новых функций» данного раздела). Наличие двух версий функции is_zero() (с одним и с двумя аргументами) позволяет перегрузить оператор !# в двух вариантах, с одним операндом (левым или правым) и с двумя операндами. <br> Лексический анализатор PostgreSQL правильно интерпретирует все перегруженные операторы в командах SQL. В листинге 7.56 продемонстрированы три варианта использования оператора !# с разными операндами. Все три варианта допустимы, так как оператор был перегружен в листинге 7.55. <br> <br><br> <h1>Использование перегруженного оператора</h1> <br> <br>Листинг 7.56. Использование перегруженного оператора <br><br> booktownHf SELECT isbn, stock FROM stock booktown-# WHERE stock !# <br> booktown-# AND !# stock <br> booktown-# AND stock !# stock; <br> isbn | stock <br> 0394900014 0 <br> 0451198492 | 0 <br> 0451457994 | 0 <br> (3 rows) <br> <br><br> <h1>Удаление оператора</h1> <br> <br>Листинг 7.57. Удаление оператора <br><br> booktown=# DROP OPERATOR !# (integer, integer);<br> <br> DROP <br> Команда в листинге 7.58 выглядит почти так же, но она удаляет перегруженную версию с правым операндом. <br> <br><br> <h1>Удаление перегруженного оператора</h1> <br> <br>Листинг 7.58. Удаление перегруженного оператора <br><br> booktown=# DROP OPERATOR !# (NONE, integer);<br> <br> DROP<br> <br><br> <h1>Удаление индекса</h1> <br> <br>Листинг 7.6. Удаление индекса <br><br> booktown=# DROP INDEX upper_title_idx: <br> DROP<br> <br><br> <h1>Создание таблицы с ограничениями полей</h1> <br> <br>Листинг 7.7. Создание таблицы с ограничениями полей <br><br> booktown=# CREATE TABLE employees <br> booktown-f (id integer PRIMARY KEY CHECK (id > <br> 100). <br> booktown(# lastjiame text NOT NULL. <br> booktown(# first_name text);<br> <br> NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index 'employeesjjkey' <br> for table 'employees' <br> CREATE <br> В листинге 7.7 создается поле id типа integer, для которого устанавливаются ограничения PRIMARY KEY и CHECK. Ограничение PRIMARY KEY также подразумевает ограничения NOT NULL и UNIQUE и приводит к автоматическому созданию индекса empl oyees_pkey для ограничиваемого поля. Ограничение CHECK гарантирует, что значение поля id всегда больше 100. Это означает, что любые попытки вставки или обновления в таблице empl oyees записей, у которых поле id меньше либо равно 100, завершаются неудачей. <br> Таблица employees, созданная в листинге 7.7, также содержит текстовое поле 1 astjiame, для которого установлено ограничение NOT NULL. Это более простое ограничение запрещает появление в таблице записей, у которых поле lastjiame содержит NULL. Иначе говоря, это поле обязательно для заполнения. <br> Примечание 1 <br>Примечание 1<br><br><br> Условия в секциях CHECK должны оперировать со значениями сравнимых типов данных. <br> <br><br> <h1>Использование ограничений таблицы</h1> <br> <br>Листинг 7.8. Использование ограничений таблицы <br><br> booktown=# CREATE TABLE editions <br> booktown-# (isbn text, <br> booktown(# bookjid integer, <br> booktown(# edition integer, <br> booktown(# publisherjd integer, <br> booktownCl publication date. <br> booktown(# type char, <br> booktown(# CONSTRAINT pkey PRIMARY KEY (isbn), <br> booktown(# CONSTRAINT integrity CHECK (bookjd IS NOT NULL <br> booktown(# AND edition IS NOT NULL). <br> booktown(# CONSTRAINT book_exists FOREIGN KEY (bookjd) <br> booktown(# REFERENCES books (id) <br> booktown(# ON DELETE CASCADE <br> booktown(# ON UPDATE CASCADE);<br> <br> NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index 'pkey1 for table <br> 'editions' <br> NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s) <br> CREATE <br> Первое ограничение, pkey, относится к типу PRIMARY KEY и устанавливается для таблицы по полю isbn. Оно практически не отличается от ограничения PRIMARY KEY для поля, поскольку список в данном примере состоит всего из одного поля. <br> Ограничение i ntegri ty гарантирует, что поля book i d и edi ti on не содержат псевдозначения NULL. <br> Наконец, ограничение book_exists при помощи конструкций FOREIGN KEY и REFERENCES гарантирует, что значение поля book_id встречается в поле id таблицы books. Более того, поскольку в секциях ON DELETE и ON ACTION встречается ключевое слово CASCADE, любые модификации поля ids таблице books приведут к каскадным изменениям записей в таблице editions, а при удалении записей из таблицы books будут удалены соответствующие записи таблицы editions. <br> Для этих ограничений в базе данных автоматически строится индекс editions_pkey по полю isbn, а также создается триггер. Индекс обеспечивает выполнение ограничения PRIMARY KEY, а триггер относится к ограничению FOREIGN KEY. <br> <br><br> <h1>Добавление ограничений в существующую таблицу</h1> <br> <br>Листинг 7.9. Добавление ограничений в существующую таблицу <br><br> booktown=# ALTER TABLE books <br> booktown-# ADD CONSTRAINT legal_subjects <br> booktown-# FOREIGN KEY (subjectjd) <br> booktown-# REFERENCES subjects (id);<br> <br> NOTICE: ALTER TABLE ... ADD CONSTRAINT will create implicit trigger(s) for <br> FOREIGN KEY check(s) <br> CREATE <br> <br><br> <h1>Массивы</h1> <br> <br>Массивы <br><br> Как упоминалось в главе 3, поля данных PostgreSQL вместо отдельных величин могут содержать конструкции, называемые массивами. Массив сам по себе не является самостоятельным типом данных, а лишь расширяет любой другой тип данных PostgreSQL. <br> <br><br> <h1>Модификация производных таблиц</h1> <br> <br> Модификация производных таблиц <br><br> Как упоминалось в предыдущем разделе, процесс включения данных в базовые и производные таблицы весьма прямолинеен. Вставка в производную таблицу приводит к кажущемуся появлению данных в базовой таблице, хотя сами данные по-прежнему находятся в производной таблице. Вставка данных в базовую таблицу никак не отражается на производной таблице. <br> Процесс модификации данных в производной таблице достаточно прост и очевиден — изменяется только содержимое производной таблицы, а все данные из базовой таблицы остаются без изменений. Как говорилось выше, данные не являются общими в обычном смысле слова, а лишь видны в других таблицах. Выборка из базовой таблицы без ключевого слова ONLY выведет как записи базовой таблицы, так и модифицированные записи производной таблицы. <br> С модификацией записей в базовых таблицах дело обстоит сложнее. Команды UPDATE и DELETE по умолчанию работают не только с записями базовой таблицы, но и с записями всех производных таблиц, подходящих по заданному критерию. В листинге 7.14 выполняется команда UPDATE для таблицы authors. Как видно из листинга, команда также изменяет записи таблицы di stinguished_authors. <br> <br><br> <h1>Наследование</h1> <br> <br> Наследование <br><br> В PostgreSQL поддерживается механизм создания объектно-реляционных связей, называемый наследованием. Таблица может наследовать некоторые атрибуты своих полей от одной или нескольких других таблиц, что приводит к созданию отношений типа «предок—потомок». В результате производные таблицы («потомки») обладают теми же полями и ограничениями, что и их базовые таблицы («предки»), а также дополняются собственными полями. <br> При составлении запроса к базовой таблице можно потребовать, чтобы запрос произвел выборку только из самой таблицы или же просмотрел как таблицу, так и ее производные таблицы. С другой стороны, в результаты запроса к производной таблице никогда не включаются записи из базовой таблицы. <br> <br><br> <h1>Нетривиальное использование таблиц</h1> <br> <br>Нетривиальное использование таблиц <br><br> В PostgreSQL предусмотрено несколько вариантов ограничения данных, участвующих в операциях вставки и обновления. Один из них заключается в установке ограничений для таблиц и полей. <br> Кроме того, в PostgreSQL поддерживается механизм наследования, характерный для объектно-реляционных СУБД. Наследование позволяет установить между таблицами связи типа «предок—потомок» и создать иерархию полей. <br> В этом разделе будут рассмотрены обе темы. Кроме того, речь пойдет о создании и практическом применении производных таблиц. <br> <br><br> <h1>Нетривиальные возможности</h1> <br> <br>Нетривиальные возможности <br><br> В данной главе рассматриваются нетривиальные возможности PostgreSQL, в том числе оптимизация доступа к таблицам с использованием индексов, наследование и установка ограничений для таблиц, практическое применение массивов в значениях полей, работа с транзакциями и курсорами. Все перечисленные возможности выгодно отличают PostgreSQL от других реляционных СУБД. <br> Кроме того, в этой главе описаны такие концепции из области программирования, как триггеры и последовательности. Наконец, для программистов, занимающихся разработкой специализированных процедур для работы с базой данных, описано, как расширить возможности PostgreSQL путем определения пользовательских функций и операторов. <br> <br><br><br> <h1>Объявление курсора</h1> <br> <br> Объявление курсора <br><br> Команда SQL DECLARE создает курсор и выполняет его. Этот процесс также называется открытием курсора. Курсор может быть объявлен только в существующем транзакционном блоке, поэтому перед объявлением курсора должна быть выполнена команда BEGIN. Синтаксис команды DECLARE: <br> DECLARE курсор [ BINARY ] [ INSENSITIVE ] [ SCROLL ] <br> CURSOR FOR запрос <br> [ FOR { READ ONLY | UPDATE [ OF none [. ...]]}] <br> <ul> <li> DECLARE курсор. Имя создаваемого курсора. </li> <li> [ BINARY ]. Ключевое слово BINARY означает, что выходные данные должны возвращаться в двоичном формате вместо стандартного ASCII-кода. Иногда переключение на двоичный формат повышает эффективность курсора, но это относится лишь к пользовательским приложениям, поскольку стандартные клиенты (такие, как psql) работают только с текстовым выводом. </li> <li> [ INSENSITIVE ] [ SCROLL ]. Ключевые слова INSENSITIVE и SCROLL существуют для совместимости со стандартом SQL, но они описывают поведение PostgreSQL по умолчанию, поэтому их присутствие не обязательно. Ключевое слово SQL INSENSITIVE обеспечивает независимость данных, возвращенных курсором, от других курсоров или подключении. Поскольку PostgreSQL требует, чтобы курсоры определялись в транзакционных блоках, это требование заведомо выполняется. Ключевое слово SQL SCROLL указывает, что курсор поддерживает одновременную выборку нескольких записей. Этот режим поддерживается в PostgreSQL по умолчанию, даже если ключевое слово SCROLL не указано. </li> <li> CURSOR FOR запрос. Запрос, после выполнения которого итоговый набор становится доступным через курсор. </li> <li> FOR { READ ONLY | UPDATE [ OF поле [. ...] ] }. В PostgreSQL 7.1.x поддерживаются курсоры, доступные только для чтения (READ ONLY), поэтому секция FOR оказывается лишней. </li> </ul> В листинге 7.42 мы создаем транзакцию командой BEGIN и открываем курсор с именем all_books, ассоциированный с командой SELECT * FROM books. <br> <br><br> <h1>Ограничения полей</h1> <br> <br> Ограничения полей <br><br> При выполнении команды \h CREATE TABLE клиент psql выводит несколько подробных синтаксических диаграмм для ограничений, которые могут устанавливаться для таблиц. Синтаксис ограничения поля выглядит так: <br> [ CONSTRAINT ограничение ] <br> { NOT NULL UNIQUE | PRIMARY KEY | DEFAULT значение | CHECK ( условие ) | REFERENCES таблица [ ( поле ) ] <br> [ MATCH FULL | MATCH PARTIAL ] <br> [ ON DELETE операция ] <br> [ ON UPDATE операция ] <br> [ DEFERRABLE | NOT DEFERRABLE ] <br> [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] } <br> Определение следует в команде CREATE TABLE сразу же за типом ограничиваемого поля и предшествует запятой, отделяющей его от следующего поля. Ограничения могут устанавливаться для любого количества полей, а ключевое слово CONSTRAINT и идентификатор ограничение не обязательны. <br> Существует шесть типов ограничений полей, задаваемых при помощи специальных ключевых слов. Некоторые из них косвенно устанавливаются при создании ограничений другого типа. Типы ограничений полей перечислены ниже. <br> <ul> <li> NOT NULL. Поле не может содержать псевдозначение NULL. Ограничение NOT NULL эквивалентно ограничению CHECK (поле NOT NULL). </li> <li> UNIQUE. Поле не может содержать повторяющиеся значения. Следует учитывать, что ограничение UNIQUE допускает многократное вхождение псевдозначений NULL, поскольку формально NULL не совпадает ни с каким другим значением. </li> <li> PRIMARY KEY. Автоматически устанавливает ограничения UNIQUE и NOT NULL, а для заданного поля создается индекс. В таблице может устанавливаться только одно ограничение первичного ключа. </li> <li> DEFAULT значение. Пропущенные значения поля заменяются заданной величиной. Значение по умолчанию должно относиться к типу данных, соответствующему типу поля. В PostgreSQL 7.1.x значение по умолчанию не может задаваться при помощи подзапроса. </li> <li> CHECK условие. Команда INSERT или UPDATE для записи завершается успешно лишь при выполнении заданного условия (выражения, возвращающего логический результат). При установке ограничения поля в секции CHECK может использоваться только поле, для которого устанавливается ограничение. </li> <li> REFERENCES. Это ограничение состоит из нескольких секций, которые перечислены ниже.</li></ul> <ul> <li> REFERENCES таблица [ ( поле ) ]. Входные значения ограничиваемого поля сравниваются со значениями другого поля в заданной таблице. Если совпадения отсутствуют, команда INSERT или UPDATE завершается неудачей. Если параметр поле не указан, проверка выполняется по первичному ключу. Ограничение REFERENCES похоже на ограничение таблицы FOREIGN KEY, описанное в следующем пункте этого подраздела. Действительно, между этими ограничениями есть много общего. Пример таблицы, созданной с ограничением FOREIGN KEY, приведен в листинге 7.8. </li> <li> MATCH FULL | MATCH PARTIAL. Секция MATCH указывает, разрешается ли смешивание значений NULL и обычных значений при вставке в таблицу, у которой внешний ключ ссылается на несколько полей. Таким образом, на практике секция MATCH приносит пользу лишь в ограничениях таблиц, хотя формально она может использоваться и при ограничении полей. Конструкция MATCH FULL запрещает вставку данных, у которых часть полей внешнего ключа содержит псевдозначение NULL (кроме случая, когда NULL содержится во всех полях). В PostgreSQLV.l.x конструкция MATCH PARTIAL не поддерживается. Если секция MATCH отсутствует, считается, что поля с псевдозначениями NULL удовлетворяют ограничению. Также будет уместно напомнить, что ограничения полей относятся лишь к одному полю, поэтому секция MATCH используется лишь в ограничениях таблиц. </li> <li> ON DELETE операция. При выполнении команды DELETE для заданной таблицы с ограничиваемым полем выполняется одна из следующих операций: N0 ACTION (если удаление приводит к нарушению целостности ссылок, происходит ошибка; используется по умолчанию, если операция не указана), RESTRICT (аналогично NO ACTION), CASCADE (удаление всех записей, содержащих ссылки на удаляемую запись), SET NULL (поля, содержащие ссылки на удаляемую запись, заменяются псевдозначениями NULL), SET DEFAULT (полям, содержащим ссылки на удаляемую запись, присваивается значение по умолчанию). </li> <li> ON UPDATE операция. При выполнении команды UPDATE для заданной таблицы выполняется одна из операций, описанных выше. По умолчанию используется значение NO ACTION. Если выбрана операция CASCADE, все записи, содержащие ссылки на обновляемую запись, обновляются новым значением (вместо удаления, как в случае с ON DELETE CASCADE). </li> <li> DEFERRABLE | NOT DEFERRABLE. Значение DEFERRABLE позволяет отложить выполнение ограничения до конца транзакции (вместо немедленного выполнения после завершения команды). Значение NOT DEFERRABLE означает, что ограничение всегда проверяется сразу же после завершения очередной команды. В этом случае пользователь не может отложить проверку ограничения до конца транзакции. По умолчанию выбирается именно этот вариант. </li> <li> INITIALLY DEFERRED | INITIALLY IMMEDIATE. Секция INITIALLY задается только для ограничений, определенных с ключевым словом DEFERRED. Значение INITIALLY DEFERRED откладывает проверку ограничения до конца транзакции, а при установке значения INITIALLY IMMEDIATE проверка производится после каждой команды. При отсутствии секции INITIALLY по умолчанию используется значение INITIALLY IMMEDIATE. </li> </ul> В листинге 7.7 приведен пример создания таблицы employees с несколькими ограничениями. <br> <br><br> <h1>Ограничения таблиц</h1> <br> <br> Ограничения таблиц <br><br> В ограничениях таблиц, в отличие от ограничений полей, могут участвовать сразу несколько полей таблицы. Синтаксис ограничения таблицы: <br> [ CONSTRAINT ограничение ] { UNIQUE ( поле [. ...] ) | PRIMARY KEY ( поле [. ...] ) | CHECK ( условие ) ] FOREIGN KEY ( поле [. ... ] ) <br> REFERENCES таблица [ ( поле [....])] <br> [ MATCH FULL | MATCH PARTIAL ] <br> [ ON DELETE операция ] <br> [ ON UPDATE операция ] <br> [ DEFERRABLE | NOT DEFERRABLE ] <br> [ INITIALLY DEFERRED INITIALLY IMMEDIATE ] <br> Секция CONSTRAINT ограничение определяет необязательное имя. Ограничениям рекомендуется присваивать содержательные имена вместо автоматически сгенерированных имен, не несущих никакой полезной информации. В будущем имя также может пригодиться и для удаления ограничения (например, в секции DROP CONSTRAINT команды ALTER TABLE). Другие секции относятся к четырем разновидностям ограничений таблиц. <br> <ul> <li> PRIMARY KEY ( поле [. ...] ). Ограничение таблицы PRIMARY KEY имеет много общего с аналогичным ограничением поля. В ограничении таблицы PRIMARY KEY могут перечисляться несколько полей, разделенных запятыми. Для перечисленных полей автоматически строится индекс. Как и в случае с ограничением поля, комбинация значений всех полей должна быть уникальной и не может содержать NULL. </li> <li> UNIQUE ( поле [. ...] ). Ограничение означает, что комбинация значений полей, перечисленных за ключевым словом UNIQUE, принимает только уникальные значения. Допускается многократное вхождение псевдозначения NULL, поскольку оно формально не совпадает ни с одним значением. </li> <li> CHECK ( условие ). Команда INSERT или UPDATE для записи завершается успешно лишь при выполнении заданного условия (выражения, возвращающего логический результат). Используется по аналогии с ограничениями полей, но в секции CHECK может содержать ссылки на несколько полей. </li> <li> FOREIGN KEY ( поле [. ... ] ) REFERENCES таблица [ ( поле [. ... ] ) ]. В качестве прототипа для секции REFERENCES можно перечислить несколько полей. Синтаксис части, следующей за секцией FOREIGN KEY, идентичен синтаксису ограничения REFERENCES для полей. </li> </ul> В листинге 7.8 в базе данных booktown создается таблица editions с тремя ограничениями. Развернутое описание приводится ниже. <br> <br><br> <h1>Ограничения в таблицах</h1> <br> <br> Ограничения в таблицах <br><br> Ограничение (constraint) представляет собой особый атрибут таблицы, который устанавливает критерии допустимости для содержимого ее полей. Соблюдение этих правил помогает предотвратить заполнение базы ошибочными или неподходящими данными. <br> Ограничения задаются в секции CONSTRAINT при создании таблицы командой CREATE TABLE. Они делятся на два типа — ограничения полей и ограничения таблиц. <br> Ограничения полей всегда относятся только к одному полю, тогда как ограничения таблиц могут устанавливаться как для одного, так и для нескольких полей. В команде CREATE TABLE ограничения полей задаются сразу же после определения поля, тогда как ограничение таблицы устанавливается в специальном блоке, отделенном запятой от всех определений полей. Поля, на которые распространяется ограничение таблицы, задаются самим определением, а не его расположением в команде. <br> Ниже описаны различные правила, устанавливаемые при помощи ограничений. <br> <br><br> <h1>Операции с последовательностями</h1> <br> <br> Операции с последовательностями <br><br> Выборка атрибутов последовательности требуется относительно редко. Как правило, все операции с последовательностями выполняются при помощи трех специальных функций PostgreSQL. <br> <ul> <li> nextval ('последовательность'). Увеличивает текущее значение заданной последовательности и возвращает новое значение в виде величины типа 1 nteger. </li> <li> currval ('последовательность'). Возвращает значение, полученное при последнем вызове nextval О. Значение ассоциируется с определенным сеансом PostgreSQL, поэтому если функция nextval () еще не вызывалась для заданного подключения в текущем сеансе, функция не сможет вернуть значение. </li> <li> setval ('последовательность'. п). Присваивает число п текущему значению заданной последовательности. Следующий вызов nextval О возвращает значение п+приращение, где приращение — изменение текущего значения последовательности при каждой итерации. </li> <li> setval ('последовательность'. п. Ь). Также присваивает число п текущему значению заданной последовательности. Если параметр b (тип boo! ean) равен f al se, то следующий вызов nextval () вернет значение п, а если параметр равен true, то будет возвращено значение п+приращение, как при вызове функции setval О без дополнительного аргумента. </li> </ul> Чаще всего при работе с последовательностями используется функция nextval О, при вызове которой и происходит увеличение текущего значения. В качестве аргумента функция получает имя последовательности, заключенное в апострофы, а возвращает значение типа Integer. <br> В листинге 7.30 выводится пара очередных значений последовательности с именем shipments_ship_id_seq. <br> <br><br> <h1>Определение количества элементов</h1> <br> <br> Определение количества элементов <br><br> Чтобы узнать количество значении, хранящихся в массиве, следует воспользоваться функцией array_dims(). В качестве параметра функции передается идентификатор — имя поля-массива, для которого вызывается функция. Результат возвращается в виде строки, содержащей описание массива в синтаксисе среза. В листинге 7.25 приведен пример вызова функции array_dims() для поля books таблицы favorite_books. <br> <br><br> <h1>Перегрузка операторов</h1> <br> <br> Перегрузка операторов <br><br> Операторы, как и функции, поддерживают возможность перегрузки. Иначе говоря, в программе можно создать оператор с таким же именем, как у существующего <br> оператора, но работающего с другими типами операндов. При этом в программе должна существовать функция, количество и тины аргументов которой соответствуют количеству и типам операндов. <br> Пример перегрузки оператора !# приведен в листинге 7.55. Первая команда CREATE OPERATOR создает оператор, аналогичный оператору из листинга 7.53. Тем не менее в новой версии оператора вместо LEFTARG указано ключевое слово RIGHTARG, поэтому новый оператор работает с операндом типа integer, находящимся не слева, а справа. Вторая команда создает третью версию оператора !#, работающую с обоими операндами. <br> <br><br> <h1>Перемещение курсора</h1> <br> <br> Перемещение курсора <br><br> Курсор поддерживает информацию о текущей позиции в итоговом наборе команды SELECT. Перемещение курсора к заданной записи выполняется командой MOVE. Синтаксис команды MOVE: <br> MOVE [ FORWARD | BACKWARD | RELATIVE ] <br> [ число ALL | NEXT | PRIOR ] <br> { IN | FROM } курсор <br> Как видно из приведенного объявления, синтаксис команды MOVE очень близок к синтаксису команды FETCH. Впрочем, команда MOVE никаких записей не возвращает и лишь перемещает текущую позицию курсора. Смещение задается целочисленной константой или ключевым словом ALL (перемещение в заданном направлении на максимально возможное расстояние), NEXT или PRIOR. В листинге 7.44 текущая позиция курсора перемещается на 10 записей вперед. <br> <br><br> <h1>Получение информации о триггерах</h1> <br> <br> Получение информации о триггерах <br><br> В PostgreSQL триггеры хранятся в системной таблице pg_trigger, что позволяет получить информацию о существующих триггерах на программном уровне. Структуру таблицы pg_trigger иллюстрирует табл. 7.3. <br> <br><br> <h1>Последовательности</h1> <br> <br> Последовательности <br><br> Последовательностью (sequence) в PostgreSQL называется объект базы данных, который фактически представляет собой автоматически увеличивающееся число. В других СУБД последовательности часто называются счетчиками. Последовательности очень часто используются для присваивания уникальных значении идентификаторов в таблицах. Последовательность определяется текущим числовым значением и набором характеристик, определяющих алгоритм автоматического увеличения (или уменьшения) используемых данных. <br> Наряду с текущим значением в определение последовательности также включается минимальное значение, максимальное значение и приращение. Обычно приращение равно 1, но оно также может быть любым целым числом. <br> На практике последовательности не рассчитаны на прямой доступ из программы. Работа с ними осуществляется через специальные функции PostgreSQL, предназначенные для увеличения, присваивания или получения текущего значения последовательности. <br> <br><br> <h1>Просмотр последовательностей в базе данных</h1> <br> <br> Просмотр последовательностей в базе данных <br><br> Команда \d клиента psql показывает, к какому типу относится тот или иной объект базы данных — последовательность, таблица, представление или индекс. Для получения более конкретной информации можно воспользоваться командой \ds, выводящей список всех последовательностей в текущей базе данных. Пример: <br> booktown=# \ds <br> List of relations Name Type | Owner <br> book_ids | sequence | manager <br> shipments_ship_id_seq j sequence | manager <br> subject_ids j sequence | manager <br> (3 rows) <br> К последовательности также можно обратиться командой SELECT, как к таблице или представлению (хотя такая возможность используется относительно редко). При составлении запроса к последовательности в списке выборки вместо полей указываются атрибуты последовательности, перечисленные в табл. 7.1. <br> <br><br> <h1>Расширение PostgreSQL</h1> <br> <br>Расширение PostgreSQL <br><br> PostgreSQL не ограничивает пользователя встроенными функциями и операторами, позволяя ему создавать собственные расширения. Если вам приходится часто выполнять некоторую стандартную последовательность команд SQL или программных операций, пользовательские функции помогут решить эту задачу более надежно и эффективно. Также в PostgreSQL предусмотрена возможность определения операторов для вызова пользовательских (или встроенных) функций, что делает команды SQL понятнее и эффективнее. <br> Функции и операторы тоже существуют как объекты базы данных и поэтому связываются с конкретной базой. Например, функция, созданная при подключении к базе данных booktown, доступна только для пользователей, также подключившихся к этой базе. <br> Если некоторые общие функции или операторы должны использоваться в разных базах данных, создайте их в базе данных template 1. В этом случае объекты функций и операторов будут автоматически копироваться из шаблона template 1 при создании новой базы данных. <br> В следующих подразделах рассматриваются операции создания, использования и удаления нестандартных функций и операторов. <br> <br><br> <h1>Создание функций на языке С</h1> <br> <br> Создание функций на языке С <br><br> СУБД PostgreSQL, написанная на языке С, может динамически подгружать откомпилированный код С без перекомпиляции пакета. Использование команды <br> CREATE FUNCTION для компоновки с функциями С разрешено только суперпользователям, поскольку эти функции могут содержать системные вызовы, представляющие потенциальную угрозу для безопасности системы. <br> Документирование всего интерфейса API системы PostgreSQL выходит за рамки книги. Впрочем, опытный программист сможет очень легко написать, откомпилировать и скомпоновать простейшие функции С с использованием загружаемых общих модулей. <br> У компилятора gcc (GNU С Compiler) имеется ключ -shared, предназначенный для создания динамически загружаемых модулей. В простейшем случае загружаемый модуль создается командой следующего вида: <br> $ gcc -shared input.с -о output.so <br> Здесь input.с — имя файла, содержащего компилируемый код С, a output.so — файл общего загружаемого модуля. <br> В листинге 7.48 приведена пара очень простых функций, написанных на языке С. Первая функция, is_zero(int), возвращает true (1), если при вызове ей был передан аргумент 0; в противном случае возвращается false (0). Вторая функция, is_zero_two(int. int), возвращает true, если хотя бы один из переданных аргументов равен нулю. <br> <br><br> <h1>Создание функций SQL</h1> <br> <br>Создание функций SQL <br><br> Из всех разновидностей функций в PostgreSQL проще всего создаются «чистые» функции SQL, поскольку их создание не требует ни знания других языков, ни серьезного опыта программирования. Функция SQL определяется как обычная команда с позиционными параметрами. <br> Позиционный параметр представляет собой ссылку на один из аргументов, переданных при вызове функции SQL. Он называется позиционным, поскольку в ссылке указывается его позиция в списке переданных аргументов. Позиционный параметр состоит из знака $, за которым следует номер (нумерация начинается с 1). Например, $1 означает первый аргумент в переданном списке. <br> В листинге 7.46 создается функция i sbn_to_ti tl e, которая возвращает название книги по заданному коду ISBN. Функция получает один аргумент типа text и возвращает результат того же типа. <br> <br><br> <h1>Создание индекса</h1> <br> <br> Создание индекса <br><br> Индексы создаются командой SQL CREATE INDEX. Синтаксис команды: <br> CREATE [ UNIQUE ] INDEX индекс ON таблица <br> [ USING тип ] ( поле [ класс ] [. ...] ) <br> Здесь индекс — имя создаваемого индекса, таблица — имя таблицы, для которой строится индекс, а поле — имя индексируемого поля. Необязательный параметр тип позволяет выбрать нужную реализацию индекса, а параметр класс описывает операторный класс, используемый для сортировки входных данных. <br> ВНИМАНИЕ <br> В PostgreSQL операторные классы хранятся в поле pg_opclass. Используйте этот параметр лишь в том случае, если вы досконально разбираетесь во всех тонкостях операторных классов PostgreSQL. <br> Команда может содержать список из нескольких индексируемых полей, разделенных запятыми; в этом случае индекс строится для всех перечисленных полей. Составные индексы используются в PostgreSQL только при выполнении команд SQL, осуществляющих поиск по всем индексированным полям с объединением условий ключевым словом AND. В стандартной установке PostgreSQL составной индекс содержит не более 16 полей и реализуется только в виде В-дерева. <br> Перед построением индекса следует решить, какие поля чаще всего требуются при поиске. Например, хотя таблица books проиндексирована по полю id (первичный ключ), поле title также часто проверяется в условиях WHERE. Включение вторичного индекса по полю title заметно ускорит работу команд SQL, в которых значение этого поля сравнивается с некоторой величиной. <br> В листинге 7.1 приведен пример построения индекса и просмотра таблицы books при помощи управляющей команды \d psql. Помимо типов полей команда также выводит имена индексов таблицы. <br> <br><br> <h1>Создание новых функций</h1> <br> <br> Создание новых функций <br><br> Разновидность команды SQL99 CREATE FUNCTION, поддерживаемая в PostgreSQL, не обладает прямой совместимостью со стандартом, но зато обеспечивает широкие возможности для расширения PostgreSQL за счет создания пользовательских функций (за информацией о встроенных операторах и функциях обращайтесь к главе 5). <br> Синтаксис команды CREATE FUNCTION: <br> CREATE FUNCTION имя ( [ тип_аргумента [. ...] ] ) <br> RETURNS тип_возвращаемого_значения <br> AS 'определение' <br> LANGUAGE 'язык' <br> [ WITH ( атрибут [. ...] ) ] <br> <ul> <li> CREATE FUNCTION имя ( [ тпип_аргумента [, ...] ] ). После ключевых слов CREATE FUNCTION указывается имя создаваемой функции, после чего в круглых скобках перечисляются типы аргументов, разделенные запятыми. Если список в круглых скобках пуст, функция вызывается без аргументов (хотя сами круглые скобки обязательно должны присутствовать как в определении функции, так и при ее использовании). </li> <li> RETURNS тип_возвращаемого^значения. Тип данных, возвращаемый функцией. </li> <li> AS ' определение'. Программное определение функции. В процедурных языках (таких, как PL/pgSQL) оно состоит из кода функции. Для откомпилированных функций С указывается абсолютный системный путь к файлу, содержащему объектный код. </li> <li> LANGUAGE 'язык'. Название языка, на котором написана функция. В аргументе может передаваться имя любого процедурного языка (такого, как plpgsql или plperl, если соответствующая поддержка была установлена при компиляции), С или SQL. </li> <li> [ WITH ( атрибут [. ...] ) ]. В PostgreSQL 7.1.x аргумент атрибут может принимать два значения: iscachablen isstrict.</li></ul> <ul> <li> i scachabl e. Оптимизатор может использовать предыдущие вызовы функций для ускоренной обработки будущих вызовов с тем же набором аргументов. Кэширование обычно применяется при работе с функциями, сопряженными с большими затратами ресурсов, но возвращающими один и тот же результат при одинаковых значениях аргументов. </li> <li> i sstri ct. Функция всегда возвращает NULL в случае, если хотя бы один из ее аргументов равен NULL. При передаче атрибута isstrict результат возвращается сразу, без фактического выполнения функции. </li> </ul> Примечание 1 <br>Примечание 1<br><br><br> PostgreSQL позволяет перегружать функции, то есть присваивать одно имя нескольким функциям, отличающимся по типу аргументов. Перегрузка позволяет связать с одним именем функции несколько выполняемых операций в зависимости от количества и типа аргументов. <br> <br><br> <h1>Создание новых операторов</h1> <br> <br> Создание новых операторов <br><br> Кроме пользовательских функций PoslgreSQL позволяет создавать пользовательские операторы. С технической точки зрения операторы всего лишь обеспечивают альтернативный синтаксис для вызова функций. Например, оператор сложения (+) в действительности вызывает одну из встроенных функций (numeri c_add() и т. д.). Пример: <br> booktown=# SELECT I + 2 AS by_operator. numeric_add(l,2) AS by_function; <br> by_operator [ by_function <br> 3 | 3 <br> (1 row) <br> Определение оператора сообщает, к какому типу данных относятся левый и правый операнды. Кроме того, в определении указывается функция, которой при вызове в качестве аргументов передаются операнды. <br> <br><br> <h1>Создание оператора</h1> <br> <br> Создание оператора <br><br> Новые операторы создаются командой SQL CREATE OPERATOR. Синтаксис команды <br> CREATE OPERATOR: <br> CREATE OPERATOR оператор ( PROCEDURE = функция <br> [. LEFTARG = тип! ] <br> [. RIGHTARG = тип2 ] <br> [. COMMUTATOR = коммутатор ] <br> [. NEGATOR = инвертор ] <br> [. RESTRICT = функция ограничения ] <br> [. JOIN = функция_обьединения ] <br> [. HASHES ] <br> [. SORT1 = левдя_сортировкд ] <br> [. SORT2 = правая_сортировка ] ) <br> В этом определении оператор — символ нового оператора, а функция — имя функции, вызываемой этим оператором. Остальные секции не обязательны, хотя в определении должна присутствовать хотя бы одна из секций LEFTARG или RIGHTARG. Оператор может состоять из следующих символов: <br> *-*/<>=~!@#*Л&|-?$ <br> Примечание 2 <br>Примечание 2<br><br><br> За дополнительной информацией об остальных секциях команды CREATE OPERATOR и ограничениях на символы операторов обращайтесь к документации. <br> Если в команде CREATE OPERATOR указан только тип данных LEFTARG, оператор работает только с левым операндом (константой или идентификатором). И наоборот, если указан только тип RIGHTARG, оператор работает только с правым операндом. При указании обоих типов данных, LEFTARG и RIGHTARG, оператор работает с обоими операндами, левым и правым. <br> Хорошим примером встроенного оператора, использующего только левый операнд, является оператор факториала (!), а оператор сложения работает с обоими операндами. Количество аргументов функции, указанной в команде CREATE OPERATOR, должно соответствовать использованию ключевых слов LEFTARG и RIGHTARG (один или два аргумента). Более того, типы аргументов функции должны соответствовать типам, указанным в команде CREATE OPERATOR. <br> В листинге 7.53 создается оператор !#, левый операнд которого передается функции is_zero() (см. листинг 7.49). Следовательно, обозначение х !# эквивалентно вызову функции is_zero(x). <br> <br><br> <h1>Создание полей со значениямимассивами</h1> <br> <br>Создание полей со значениями-массивами <br><br> Чтобы создать простейшее поле-массив, включите в команду CREATE TABLE или ALTER TABLE пару квадратных скобок после имени поля. Квадратные скобки показывают, что вместо одного значения в поле может храниться массив указанного типа. Например, команда для создания поля single_array типа type выглядит так: <br> single_array type[] -- Одномерный массив <br> Дополнительные квадратные скобки определя ют многомерные массивы, то есть «массивы массивов». Пример: <br> mu1ti_array type[][] -- Многомерный массив <br> Теоретически в квадратных скобках можно указать целое число, чтобы созданный массив имел фиксированный размер (то есть всегда состоял из п элементов по указанному измерению и не более). Тем не менее в PostgreSQL 7.1.x это ограничение не соблюдалось, и на практике массив фиксированной длины ничем не отличался от обычного массива. <br> В листинге 7.16 создается таблица с именем favorite_books, связывающая целочисленный код работника с одномерным массивом строк books. <br> <br><br> <h1>Создание последовательности</h1> <br> <br> Создание последовательности <br><br> Последовательности создаются командой SQL CREATE SEQUENCE с положительным или отрицательным приращением. Синтаксис команды CREATE SEQUENCE: <br> CREATE SEQUENCE последовательность <br> [ INCREMENT приращение ] <br> [ MINVALUE минимум ]<br> [ MAXVALUE максимум ] <br> [ START начало ] <br> [ CACHE кэш ]<br> [ CYCLE ] <br> В этом определении единственный обязательный параметр последовательность определяет имя создаваемой последовательности. Значения последовательности .представляются типом Integer, поэтому максимальное и минимальное значения должны лежать в интервале от 2 147 483 647 до -2 147 483 647. <br> Ниже описаны необязательные секции команды CREATE SEQUENCE. <br> <ul> <li> INCREMENT приращение. Числовое изменение текущего значения последовательности. Используется при вызове для последовательности функции nextvaK). Отрицательное приращение создает убывающую последовательность. По умолчанию приращение равно 1. </li> <li> MINVALUE минимум. Минимальное допустимое значение последовательности. Попытка уменьшить текущее значение ниже заданного минимума приведет к ошибке или циклическому переходу к максимальному значению (если последовательность создавалась с ключевым словом CYCLE). По умолчанию минимальное значение равно 1 для возрастающих последовательностей или -2 147 483 647 для убывающих последовательностей. </li> <li> MAXVALUE максимум. Максимальное допустимое значение последовательности. Попытка увеличить текущее значение выше заданного максимума приведет к ошибке или циклическому переходу к минимальному значению. По умолчанию максимальное значение равно 2 147 483 647 для возрастающих последовательностей или -1 для убывающих последовательностей. </li> <li> START начало. Начальное значение последовательности, которым является любое целое число в интервале между минимальным и максимальным значениями. По умолчанию последовательность начинается с нижнего порога для возрастающих последовательностей или с верхнего порога для убывающих последовательностей. </li> <li> CACHE кэш. Возможность предварительного вычисления и хранения значений последовательности в памяти. Кэширование ускоряет доступ к часто используемым последовательностям. Минимальное значение, заданное по умолчанию, равно 1; увеличение объема кэша приводит к увеличению числа кэшируемых значений. </li> <li> CYCLE. При достижении нижнего или верхнего порога последовательность продолжает генерировать новые значения. В этом случае она переходит к минимальному значению (для возрастающих последовательностей) или к максимальному значению (для убывающих последовательностей). </li> </ul> В листинге 7.28 создается простая возрастающая последовательность с именем shipments_ship_Td_seq, которая начинается со значения 0 и увеличивается со стандартным приращением 1 до тех пор, пока не достигнет максимального значения по умолчанию 2 147 483 647. Ключевое слово CYCLE не указано, поэтому последовательность заведомо принимает уникальные значения. <br> <br><br> <h1>Создание производной таблицы</h1> <br> <br> Создание производной таблицы <br><br> Производная таблица создается командой SQL CREATE TABLE, в которую включается секция INHERITS. Секция состоит из ключевого слова INHERITS и имени базовой таблицы (или нескольких таблиц). <br> Часть команды CREATE TABLE, относящаяся к наследованию, выглядит так: <br> CREATE TABLE производная_таблица определение<br> INHERITS ( базовая_таблица [. ...] ) <br> В этом определении производная таблица — имя создаваемой таблицы, определение — полное определение таблицы со всеми стандартными секциями команды CREATE TABLE, а базовая _таблица — таблица, структура которой наследуется новой таблицей. Дополнительные имена базовых таблиц перечисляются через запятую. <br> В листинге 7.11 создается таблица distinguished_authors, определение которой состоит из единственного текстового поля award. Поскольку в команде создания таблицы указано ключевое слово INHERITS, таблица содержит четыре поля — одно собственное и три унаследованных.<br> <br><br> <h1>Создание триггера</h1> <br> <br> Создание триггера <br><br> Триггер создается на основе существующей функции. PostgreSQL позволяет создавать функции на разных языках программирования, в том числе на SQL, PL/ pgSQL и С. В PostgreSQL 7.1.x триггеры могут вызывать функции, написанные на любом языке, но за одним исключением: функция не может быть полностью реализована на SQL. <br> В определении триггера указывается, должна ли заданная функция вызываться до или после выполнения некоторой операции с таблицей. Синтаксис определения триггера выглядит так: <br> CREATE TRIGGER триггер { BEFORE | AFTER } { событие [ OR событие ...]} <br> ON таблица <br> FOR EACH { ROW STATEMENT } <br> EXECUTE PROCEDURE функция ( аргументы ) <br> Ниже приводятся краткие описания компонентов этого определения. <br> <ul> <li> CREATE TRIGGER триггер. В аргументе триггер указывается произвольное имя создаваемого триггера. Имя может совпадать с именем триггера, уже существующего в базе данных — при условии, что этот триггер установлен для другой таблицы. Кроме того, по аналогии с большинством других несистемных объектов баз данных, имя триггера (в сочетании с таблицей, для которой он устанавливается) должно быть уникальным лишь в контексте базы данных, в которой он создается. </li> <li> { BEFORE AFTER }. Ключевое слово BEFORE означает, что функция должна выполняться перед попыткой выполнения операции, включая все встроенные проверки ограничений данных, реализуемые при выполнении команд INSERT и DELETE. Ключевое слово AFTER означает, что функция вызывается после завершения операции, приводящей в действие триггер. </li> <li> { событие [ OR событие ... ] }. События SQL, поддерживаемые в PostgreSQL При перечислении нескольких событий в качестве разделителя используется ключевое слово OR. </li> <li> ON таблица. Имя таблицы, модификация которой заданным событием приводит к срабатыванию триггера. </li> <li> FOR EACH { ROW STATEMENT }. Ключевое слово, следующее за конструкцией FOR EACH и определяющее количество вызовов функции при наступлении указанного события. Ключевое слово ROW означает, что функция вызывается для каждой модифицируемой записи. Если функция должна вызываться всего один раз для всей команды, используется ключевое слово STATEMENT. </li> <li> EXECUTE PROCEDURE функция ( аргументы ). Имя вызываемой функции с аргументами. </li> </ul> Примечание 3 <br>Примечание 3<br><br><br> Создание триггеров разрешено только владельцу базы данных или суперпользователю. <br> Механизм ограничений PostgreSQL позволяет реализовать простое сравнение данных со статическими значениями, но иногда проверка входных данных должна производиться по более сложным критериям. Это типичный пример ситуации, в которой удобно воспользоваться триггером. <br> Проверка входных данных с применением триггеров может осуществляться перед вставкой данных в таблицу или перед их обновлением в таблице. Функция триггера может убедиться в том, что новые данные удовлетворяют сложной системе ограничений, и даже вернуть признак ошибки через систему регистрации ошибок PostgreSQL. <br> Предположим, вы написали на процедурном языке функцию, которая проверяет данные, переданные при вызове команды INSERT или UPDATE для таблицы shipments, и затем обновляет таблицу stock, снимая поставленный товар со складского учета. Такую функцию можно написать на любом языке, поддерживаемом PostgreSQL (кроме «чистого» SQL, о чем говорилось выше). <br> Прежде всего функция убеждается в том, что переданный код покупателя (customerj d) и код ISBN (i sbn) присутствуют в таблицах customers и ech ti ons. Если хотя бы один из кодов отсутствует, функция возвращает признак ошибки. Если оба кода присутствуют в таблицах, команда SQL выполняется, и после успешного завершения количество товара на складе в таблице stock автоматически уменьшается в соответствии с объемом поставки. <br> Триггер, создаваемый в листинге 7.35, срабатывает непосредственно перед выполнением команды INSERT или UPDATE в таблице shi pments. Триггер вызывает функцию check_sh1pment addition() для каждой изменяемой записи. <br> <br><br> <h1>Срезы</h1> <br> <br> Срезы <br><br> В PostgreSQL также поддерживается возможность создания срезов при выборке из массива. Срез аналогичен обычному обращению к элементам по индексу, но он описывает интервал значений. Срез задается парой целочисленных индексов, разделенных двоеточием и заключенных в квадратные скобки. Например, конструкция [2:5] описывает второй, третий, четвертый и пятый элемент заданного массива. Результат среза возвращается в виде константы-массива, которая фактически описывает подмножество элементов исходного массива (впрочем, срез может содержать все элементы исходного массива). <br> В листинге 7.24 выбираются первые два элемента массива books в записях таблицы favorite_books. Хотя первая запись содержит только одно название книги, оно возвращается в виде массива из одного элемента. <br> <br><br> <h1>Атрибуты последовательностей</h1> <br> <br> Таблица 7.1. Атрибуты последовательностей <br><br> <table border=1> <tr> <td> Атрибут</td> <td> Тип</td> </tr> <tr> <td> sequence name</td> <td> name</td> </tr> <tr> <td> last_value</td> <td> integer</td> </tr> <tr> <td> increment by</td> <td> integer</td> </tr> <tr> <td> max value</td> <td> integer</td> </tr> <tr> <td> min value</td> <td> integer</td> </tr> <tr> <td> cache value</td> <td> integer</td> </tr> <tr> <td> log cnt</td> <td> integer</td> </tr> <tr> <td> is_cycled</td> <td> "char"</td> </tr> <tr> <td> is called</td> <td> "char"</td> </tr> </table> В листинге 7.29 приведен пример запроса к последовательности shipments_ship_id_seq. Запрос возвращает атрибуты last_value (текущее значение последовательности) и increment_by (приращение при очередном вызове nextval О). <br> <br><br> <h1>Таблица shipments</h1> <br> <br> Таблица 7.2. Таблица shipments <br><br> <table border=1> <tr> <td> Поле</td> <td> Тип</td> <td> Модификатор</td> </tr> <tr> <td> Id</td> <td> Integer</td> <td> NOT NULL DEFAULT nextval ( 'shipments^ship id seq1)</td> </tr> <tr> <td> customerjd</td> <td> Integer</td> <td> </td> </tr> <tr> <td> isbn</td> <td> text</td> <td> </td> </tr> <tr> <td> ship_date</td> <td> timestamp with time zone</td> <td> </td> </tr> </table> Команда создания таблицы shipments с автоматически увеличивающимся значением по умолчанию и ограничением первичного ключа выглядит так: <br> CREATE TABLE shipments <br> (id integer DEFAULT nextval ('shipments_shipjd_seq') <br> PRIMARY KEY. customerjd integer, isbn text. ship_date timestamp) <br> В качестве значения по умолчанию для поля id назначается результат вызова nextval () для последовательности shi pments_shi p_i d_seq. Таким образом, при вставке записей без указания поля id значение автоматически генерируется по результату вызова функции. <br> ВНИМАНИЕ<br> Простая установка ограничения DEFAULT не гарантирует его применения. Пользователь способен вручную задать любое значение, что может привести к потенциальному нарушению уникальности в будущем. Для предотвращения конфликтов можно воспользоваться триггером. За дополнительной информацией обращайтесь к подразделу «Триггеры» этого раздела. <br> После вызова функции nextval О для последовательности в некотором сеансе (то есть подключении к PostgreSQL) функция currval () возвращает значение, полученное при предыдущем вызове nextval () в активном сеансе. <br> Примечание 2 <br>Примечание 2<br><br><br> Текущее значение последовательностей ассоциируется с определенным сеансом, чтобы одновременные обращения со стороны нескольких пользователей не приводило к ошибкам. Два пользователя могут работать с одной последовательностью в разных сеансах, но при этом функция currval () возвращает последнее текущее значение последовательности для того сеанса, в котором она была вызвана. <br> В листинге 7.31 в таблицу shi pments вставляется новая запись, в которой не указано значение поля id. В этой ситуации используется значение по умолчанию, которое (см. табл. 7.2) определяется результатом приращения последовательности <br> shipments_ship_id_seq функцией nextvaK). <br> Затем функция currva() используется для выборки только что вставленной записи. <br> <br><br> <h1>Таблица pgjrigger</h1> <br> <br> Таблица 7.3. Таблица pgjrigger <br><br> <table border=1> <tr> <td> Поле </td> <td>Тип</td> </tr> <tr> <td> tgrelid</td> <td> old</td> </tr> <tr> <td> tgname</td> <td> name</td> </tr> <tr> <td> tgfoid</td> <td> old</td> </tr> <tr> <td> tgtype</td> <td> smallint</td> </tr> <tr> <td> tgenabled</td> <td> boo'i ean</td> </tr> <tr> <td> tgisconstraint</td> <td> boolean</td> </tr> <tr> <td> tgconstrname</td> <td> name</td> </tr> <tr> <td> tgconstrrelid</td> <td> oid</td> </tr> <tr> <td> tgdeferrable</td> <td> boolean</td> </tr> <tr> <td> tginltdef erred</td> <td> boolean</td> </tr> <tr> <td> tgnargs</td> <td> small int</td> </tr> <tr> <td> tgattr</td> <td> int2vector</td> </tr> <tr> <td> tgargs</td> <td> bytea</td> </tr> </table> Большинство полей, перечисленных в табл. 7.3, в прямых запросах не используется. Среди атрибутов триггеров в системной таблице pg_trigger центральное место занимают атрибуты tgrelid и tgname. <br> В поле tgrel id хранится идентификатор отношения, с которым связан данный триггер. Значение относится к типу oid и соответствует содержимому поля rel f i I enode системной таблицы pg_cl ass. В поле tgname хранится имя триггера, указанное в команде CREATE TRIGGER при его создании. <br> <br><br> <h1>Типы индексов</h1> <br> <br> Типы индексов <br><br> Необязательная секция USING задает реализуемый тип индекса. В PostgreSQL 7.1.x поддерживаются три типа индексов: <br> <ul> <li> В-дерево; </li> <li> R-дерево; </li> <li> кэш. </li> </ul> В первом варианте с высокой степенью параллельности используются алгоритмы В-деревьев Лемана-Яо (Lehman-Yao). Это самый распространенный способ индексации, обладающий наибольшими возможностями. По этой причине он используется по умолчанию. <br> Реализация R-дерева, основанная на квадратичном разбиении по алгоритму Гуттмана (Guttman), применяется главным образом при операциях с геометрическими типами данных. Реализация хэша основана на алгоритмах линейного хэширования Литвина (Litwin), которые традиционно используются для индексов с частой проверкой равенства (то есть ориентированы на оператор =). <br> На момент написания книги в PostgreSQL версии 7.1.x реализация индексов на основе В-дерева значительно превосходила остальные типы но универсальности и широте возможностей. В-дерево рекомендуется использовать вместо хэша даже при прямых сравнениях оператором =. Хэш поддерживается в первую очередь по соображениям совместимости, хотя ничто не мешает вам выбрать эту реализацию, если вы твердо уверены в выигрыше от перехода на нее от В-дерева. <br> Как сказано выше, реализацию на основе R-дерева рекомендуется использовать для индексации геометрических типов данных, но при этом необходимо помнить о специфике этого типа. Например, для R-дерева нельзя построить уникальный индекс или провести индексацию по нескольким полям. В таких случаях лучше положиться на реализацию В-дерева, обладающую более широкими возможностями. <br> Тип индекса задается в секции USING при помощи ключевых слов BTREE, RTREE и HASH. По умолчанию используется тип BTREE. <br> В листинге 7.4 создается таблица с именем polygons, предназначенная для хранения геометрических данных типа polygon. Затем для поля shape создается индекс spaci a I _1 ndex типа RTREE. <br> <br><br> <h1>Транзакции и курсоры</h1> <br> <br>Транзакции и курсоры <br><br> В PostgreSQL используется специфический подход к обработке транзакций в базах данных. В терминологии SQL транзакцией называется процесс синхронизации результатов выполнения команды с состоянием данных в базе. Данные не записываются на диск немедленно, а лишь отражаются в «текущей» информации состояния, хранящейся в базе. В результате фиксации транзакции последствия выполнения команды окончательно фиксируются в текущем состоянии базы данных. <br> Возникает очевидная проблема — что произойдет, если два пользователя одновременно попытаются зафиксировать взаимоисключающие изменения в одном объекте базы данных? В некоторых СУБД подобные конфликты предотвращаются путем блокировки (locking). <br> Блокировкой называется механизм, запрещающий выборку из объекта базы данных на время его модификации, и наоборот. Применение блокировки связано с очевидными проблемами из области быстродействия. Например, выборка заблокированных данных становится невозможной до момента завершения обновления. <br> В PostgreSQL используется механизм MVCC (Multi-Version Concurrency Control), позволяющий выполнять команды SQL в отложенных транзакционных блоках. Таким образом, каждое подключение к серверу PostgreSQL до фиксации результатов фактически поддерживает временный «образ» объектов базы данных, модифицируемых в транзакцпопном блоке. <br> Если в программе отсутствует команда начала транзакциопного блока, все команды SQL, передаваемые PostgreSQL, фиксируются автоматически, то есть база данных синхронизируется с. результатами команд сразу же после их выполнения. Тем не менее при явном создании транзакщюнного блока изменения в базе данных остаются невидимыми для других пользователей вплоть до фиксации. Таким образом, появляется возможность одновременного внесения изменений в разные объекты базы данных. Далее все изменения либо фиксируются, либо откатываются (отменяются). <br> При откате транзакции все объекты возвращаются к состоянию, в котором они находились до начала транзакционпого блока. Такая возможность может пригодиться при восстановлении после незавершенных операций или при отмене любых частичных изменений. Отмененные транзакции не фиксируются в базе данных, и другие пользователи даже не замечают последствий незавершенной транзакции. <br> В PostgreSQL также поддерживаются курсоры — универсальный и гибкий механизм ссылок на выполненные запросы SQL. Курсор позволяет перебрать содержимое итогового набора и включить в выборку только некоторые из полученных записей. При правильном использовании курсоры повышают эффективность работы со статическими наборами записей в приложениях. Курсоры выполняются только в транзакционных блоках. <br> В следующем подразделе описаны основные принципы работы с транзакциями и курсорами. В частности, в нем рассматриваются команды создания, фиксации и отката транзакций, а также способы объявления, перемещения и выборки в курсорах. <br> <br><br> <h1>Транзакционные блоки</h1> <br> <br> Транзакционные блоки <br><br> Транзакционные блоки создаются командой SQL BEGIN, за которой могут следовать необязательные ключевые слова WORK или TRANSACTION. Эти ключевые слова делают команду более наглядной, но никак не влияют на работу ее пли транзакци-онного блока. <br> В листинге 7.38 приведен пример создания транзакционного блока в базе данных booktown. <br> <br><br> <h1>Триггеры</h1> <br> <br> Триггеры <br><br> Довольно часто перед некоторыми событиями SQL или после них должны выполняться определенные операции — например, проверка логической целостности данных, заносимых в базу, предварительное форматирование данных перед вставкой или модификация других таблиц, логически обусловленная удалением или модификацией записей. Традиционно такие операции выполнялись на программном уровне приложением, подключившимся к базе данных, а не самой СУБД. <br> В PostgreSQL поддерживаются нестандартные расширения, называемые триггерами (trigger) и упрощающие взаимодействие приложения с базой данных. Триггер определяет функцию, которая должна выполняться до или после некоторой операции с базой данных. Триггеры реализуются на языке С, PL/pgSQL или любом другом функциональном языке (кроме SQL), который может использоваться в PostgreSQL для определения функций. Дополнительная информация о создании функций приведена в разделе «Расширение PostgreSQL» этой главы, а языки PL/ pgSQL описаны в главе 11. <br> ВНИМАНИЕ <br> Триггеры относятся к числу специфических расширений PostgreSQL, поэтому их не рекомендуется использовать в решениях, требующих высокой степени совместимости с другими РСУБД. <br> Триггеры срабатывают при выполнении с таблицей команды SQL INSERT, UPDATE или DELETE. <br> <br><br> <h1>Удаление индекса</h1> <br> <br> Удаление индекса <br><br> Для удаления индексов из таблицы используется команда DROP INDEX. Синтаксис команды DROP INDEX: DROP INDEX индекс [. ...] <br> В качестве параметра команде передается имя удаляемого индекса. Допускается одновременное удаление нескольких индексов, перечисленных через запятую. В листинге 7.6 удаляется индекс upper_title_idx, созданный в листинге 7.5. <br> <br><br> <h1>Удаление ограничений</h1> <br> <br> Удаление ограничений <br><br> В PostgreSQL 7.1.x не поддерживается прямое удаление ограничений из таблицы. Добиться нужного результата можно лишь одним способом — создать копию таблицы, практически полностью повторяющую оригинал, но не содержащую удаляемых ограничений. Данные копируются из исходной таблицы в новую, после чего таблицы переименовываются командой ALTER TABLE и копия заменяет оригинал. <br> ВНИМАНИЕ <br> Применяя этот прием, следует учитывать, что кто-то из пользователей может подключиться к базе данных и работать с модифицируемыми таблицами. Вставка или любые модификации данных в процессе копирования недопустимы; таким образом, если таблица активно используется, вы можете временно запретить подключения к PostgreSQL, внести необходимые изменения и перезапустить систему. <br> В листинге 7.10 снятие ограничений продемонстрировано на примере ограничения FOREIGN KEY с именем legal_subjects, установленного для таблицы books (см. листинг 7.9). Обратите внимание на удаление индекса books_1d_pkey перед созданием новой таблицы, что позволяет создать таблицу с индексом books_id_pkey. На самом деле это не обязательно, но имя индекса первичного ключа лучше сохранить. <br> <br><br> <h1>Удаление оператора</h1> <br> <br> Удаление оператора <br><br> Операторы удаляются командой DROP OPERATOR. Выполнение этой команды разрешено либо пользователю, создавшему оператор, либо суперпользователю PostgreSQL. <br> ВНИМАНИЕ<br> Команда DROP OPERATOR применима не только к пользовательским, но и к встроенным операторам, поэтому при выполнении этой команды с правами суперпользователя необходимо действовать очень осторожно. <br> Так как операторы определяются не только именем, но и типом операндов, в команде DROP OPERATOR необходимо задать типы левого и правого операндов. Если какой-либо из операндов не используется, вместо типа указывается ключевое слово NONE. <br> Синтаксис команды DROP OPERATOR: <br> DROP OPERATOR оператор ( { левый_тип \ NONE } . <br> { правый_тип \ NONE } ) <br> В листинге 7.57 удаляется версия оператора ! #, работающая с двумя операндами. <br> <br><br> <h1>Удаление последовательности</h1> <br> <br> Удаление последовательности <br><br> Команда SQL DROP SEQUENCE удаляет последовательность или несколько последовательностей одновременно. Синтаксис команды DROP SEQUEICE: DROP SEQUENCE последовательность [. ...] <br> В качестве параметра команде передается имя удаляемой последовательности. Допускается одновременное удаление нескольких последовательностей, перечисленных через запятую. <br> В листинге 7.33 удаляется последовательность shipments_ship_id_seq. <br> <br><br> <h1>Удаление триггера</h1> <br> <br> Удаление триггера <br><br> Команда DROP TRIGGER удаляет триггер из базы данных. Удаление триггеров, как и их создание командой CREATE TRIGGER, может выполняться только владельцем триггера или суперпользователем. <br> Синтаксис удаления существующих триггеров: <br> DROP TRIGGER имя ON таблица <br> В листинге 7.36 приведен пример удаления триггера check_shipment, установленного для таблицы shipments. <br> <br><br> <h1>Уничтожение функций</h1> <br> <br> Уничтожение функций <br><br> Функции уничтожаются владельцем или суперпользователем при помощи команды SQL DROP FUNCTION. Синтаксис команды DROP FUNCTION: <br> DELETE FUNCTION имя ( [ тип_аргуменга [. ...] ] ): <br> В листинге 7.52 приведен пример удаления функции 1sbn_to_t1tle(text). Обратите внимание: типы аргументов должны указываться обязательно, даже если функция и не перегружалась. <br> <br><br> <h1>Уникальные индексы</h1> <br> <br> Уникальные индексы <br><br> Создание индекса с ключевым словом UNIQUE говорит о том, что индекс является уникальным, то есть индексируемое поле (или поля) не может содержать повторяющихся значений. Фактически создание уникального индекса эквивалентно созданию таблицы с ограничением уникальности (см. ниже подраздел «Ограничения в таблицах» в разделе «Нетривиальное использование таблиц»). <br> В листинге 7.3 для поля name таблицы publ ishers создается уникальный индекс unique_publ IsheMdx. Это означает, что в таблице не могут присутствовать два издательства с одинаковыми названиями. <br> <br><br> <h1>Вставка значений в полямассивы</h1> <br> <br> Вставка значений в поля-массивы <br><br> В PostgreSQL предусмотрен специальный синтаксис вставки нескольких значений в одно поле. Этот синтаксис основан на определении массивов-констант. Как упоминалось в главе 3, массив-константа (предназначенный для ссылки на массивы PostgreSQL в командах SQL) состоит из фигурных скобок, апострофов и запятых, заключенных в апострофы. Кавычки нужны только при работе с массивами строк. Таким образом, обобщенная форма массива-константы выглядит так: <br> '{ "текст" [. ...] }' -- массив строк <br> '{ число [. ...]}' -- числовой массив <br> В этих примерах использованы строковые и числовые массивы, но поле может определяться как массив произвольного типа (включая типы boolean, date и time). Как правило, если для описания величины в скалярном контексте должны использоваться апострофы (например, в строковых константах или данных типа timestamp), в контексте массива эта величина заключается в кавычки. <br> В листинге 7.18 в таблицу favorite_books вставляются две записи. Первая команда создает массив с одним элементом для работника с кодом 102, а вторая запись создает массив с двумя элементами для работника с кодом 103. В обеих командах INSERT используются массивы-константы. <br> <br><br> <h1>Выборка из курсора</h1> <br> <br> Выборка из курсора <br><br> Выборка записей из курсора производится командой FETCH. Синтаксис команды <br> FETCH: <br> FETCH [ FORWARD BACKWARD | RELATIVE ] <br> [ число ALL | NEXT | PRIOR ] <br> { IN | FROM } курсор <br> В этом объявлении курсор — имя курсора, из которого производится выборка записей. Курсор всегда указывает па «текущую» позицию итогового набора выполненной команды, а в выборке могут участвовать записи, находящиеся до или после текущей позиции. Направление выборки определяется ключевыми словами FORWARD и BACKUARD, но умолчанию используется прямая выборка (FORWARD). Ключевое слово RELATIVE не обязательно и поддерживается лишь для совместимости со стандартом SQL92. <br> ВНИМАНИЕ <br> В команде также может использоваться ключевое слово ABSOLUTE, но в PostgreSQL 7.1.x возможности абсолютного позиционирования и выборки в курсорах не реализованы. Курсор использует относительное позиционирование и выводит сообщение о том, что абсолютное позиционирование не поддерживается. <br> За ключевым словом, идентифицирующим направление, может указываться следующий аргумент — количество записей. Допускается указание конкретного числа записей (в виде целочисленной константы) или одного из нескольких ключевых слов. Ключевое слово ALL означает, что команда возвращает все записи, начиная с текущей позиции курсора. С ключевым словом NEXT (используется по умолчанию) команда возвращает следующую запись от текущей позиции курсора. С ключевым словом PRIOR возвращается запись, находящаяся перед текущей позицией курсора. <br> Ключевые слова IN и FROM эквивалентны, из них в команде должно присутствовать одно. <br> В листинге 7.43 выбираются первые четыре записи итогового набора, на который ссылается курсор all_books. Направление не указано, поэтому по умолчанию используется ключевое слово FORWARD. Далее команда FETCH с ключевым словом NEXT выбирает пятую запись, после чего команда FETCH с ключевым словом PRIOR снова возвращается к четвертой записи. <br> <br><br> <h1>Выборка из полеймассивов</h1> <br> <br> Выборка из полей-массивов <br><br> При выборке из поля-массива весь массив возвращается в формате константы, описанном в предыдущем разделе. В листинге 7.20 команда SELECT выбирает все элементы массивов в поле books таблицы favorite_books. <br> <br><br> <h1>Закрытие курсора</h1> <br> <br> Закрытие курсора <br><br> Команда CLOSE закрывает ранее открытый курсор. Курсор также автоматически закрывается при выходе из транзакционного блока, в котором он находится, при фиксации транзакции командой COMMIT или ее откате командой ROLLBACK. Синтаксис команды CLOSE (курсор — имя закрываемого курсора): <br> CLOSE курсор <br> В листинге 7.45 курсор all_books закрывается и освобождает занимаемую им память, вследствие чего данные курсора становятся недоступными. <br> <br><br>  <br> <a name="47"><h1>  <img src="/8.gif">  Базы данных: Разработка - Управление - Excel</h1> <ul> <li><a href="/578-1/index.htm">Базы данных</a><br> <li><a href="/579-1/index.htm">Разработка баз данных</a><br> <li><a href="/580-1/index.htm">СУБД и базы данных</a><br> <li><a href="/581-1/index.htm">Управление базами данных</a><br> <li><a href="/582-1/index.htm">Классика баз данных</a><br> <br> <li><a href="/583-1/index.htm">Софт для создания базы данных</a><br> <li><a href="/584-1/index.htm">SQL</a><br> <li><a href="/585-1/index.htm">Access</a><br> <li><a href="/586-1/index.htm">FoxProо</a><br> <li><a href="/587-1/index.htm">Расширенная оптимизация подзапросов в Oracle</a><br> <br> <li><a href="/588-1/index.htm">Informix</a><br> <li><a href="/589-1/index.htm">Линтер</a><br> <li><a href="/590-1/index.htm">Postgres</a><br> <li><a href="/591-1/index.htm">СУБД DB2</a><br> <li><a href="/592-1/index.htm">InterBase</a><br> <br> <li><a href="/593-1/index.htm">Excel</a><br> <li><a href="/594-1/index.htm">Таблицы Excel</a><br> <li><a href="/595-1/index.htm">Справка Excel</a><br> <li><a href="/596-1/index.htm">Программирование в Excel</a><br> <li><a href="/597-1/index.htm">Деньги в Excel</a><br> <br> <li><a href="/598-1/index.htm">Задачи Excel</a><br> </ul> <br> <hr> <center> <!--LiveInternet counter--><a href="https://www.liveinternet.ru/click" target="_blank"><img id="licnt5E16" width="88" height="31" style="border:0" title="LiveInternet: показано число просмотров Р·Р° 24 часа, посетителей Р·Р° 24 часа Рё Р·Р° сегодня" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAEALAAAAAABAAEAAAIBTAA7" alt=""/></a><script>(function(d,s){d.getElementById("licnt5E16").src= "https://counter.yadro.ru/hit?t14.4;r"+escape(d.referrer)+ ((typeof(s)=="undefined")?"":";s"+s.width+"*"+s.height+"*"+ (s.colorDepth?s.colorDepth:s.pixelDepth))+";u"+escape(d.URL)+ ";h"+escape(d.title.substring(0,150))+";"+Math.random()}) (document,screen)</script><!--/LiveInternet--> </center> <hr> </div></div> </body> </html>