Введение в структурированный язык запросов SQL. SQL краткое описание

Язык программирования

SQL (Structured Query Language — Структурированный язык запросов) — язык управления базами данных для реляционных баз данных. Сам по себе SQL не является Тьюринг-полным языком программирования, но его стандарт позволяет создавать для него процедурные расширения, которые расширяют его функциональность до полноценного языка программирования.

Язык был создан в 1970х годах под названием “SEQUEL” для системы управления базами данных (СУБД) System R. Позднее он был переименован в “SQL” во избежание конфликта торговых марок. В 1979 году SQL был впервые опубликован в виде коммерческого продукта Oracle V2.

Первый официальный стандарт языка был принят ANSI в 1986 году и ISO — в 1987. С тех пор были созданы еще несколько версий стандарта, некоторые из них повторяли предыдущие с незначительными вариациями, другие принимали новые существенные черты.

Несмотря на существование стандартов, большинство распространенных реализаций SQL отличаются так сильно, что код редко может быть перенесен из одной СУБД в другую без внесения существенных изменений. Это объясняется большим объемом и сложностью стандарта, а также нехваткой в нем спецификаций в некоторых важных областях реализации.

SQL создавался как простой стандартизированный способ извлечения и управления данными, содержащимися в реляционной базе данных. Позднее он стал сложнее, чем задумывался, и превратился в инструмент разработчика, а не конечного пользователя. В настоящее время SQL (по большей части в реализации Oracle) остается самым популярным из языков управления базами данных, хотя и существует ряд альтернатив.

SQL состоит из четырех отдельных частей:

  1. язык определения данных (DDL) используется для определения структур данных, хранящихся в базе данных. Операторы DDL позволяют создавать, изменять и удалять отдельные объекты в БД. Допустимые типы объектов зависят от используемой СУБД и обычно включают базы данных, пользователей, таблицы и ряд более мелких вспомогательных объектов, например, роли и индексы.
  2. язык манипуляции данными (DML) используется для извлечения и изменения данных в БД. Операторы DML позволяют извлекать, вставлять, изменять и удалять данные в таблицах. Иногда операторы select извлечения данных не рассматриваются как часть DML, поскольку они не изменяют состояние данных. Все операторы DML носят декларативный характер.
  3. язык определения доступа к данным (DCL) используется для контроля доступа к данным в БД. Операторы DCL применяются к привилегиям и позволяют выдавать и отбирать права на применение определенных операторов DDL и DML к определенным объектам БД.
  4. язык управления транзакциями (TCL) используется для контроля обработки транзакций в БД. Обычно операторы TCL включают commit для подтверждения изменений, сделанных в ходе транзакции, rollback для их отмены и savepoint для разбиения транзакции на несколько меньших частей.

Следует отметить, что SQL реализует декларативную парадигму программирования: каждый оператор описывает только необходимое действие, а СУБД принимает решение о том, как его выполнить, т.е. планирует элементарные операции, необходимые для выполнения действия и выполняет их. Тем не менее, для эффективного использования возможностей SQL разработчику необходимо понимать то, как СУБД анализирует каждый оператор и создает его план выполнения.

Примеры:

Hello, World!:

Пример для версий Oracle 10g SQL , Oracle 11g SQL

Строка ‘Hello, World!’ выбирается из встроенной таблицы dual , используемой для запросов, не требующих обращения к настоящим таблицам.

select "Hello, World!" from dual ;

Факториал:

Пример для версий Oracle 10g SQL , Oracle 11g SQL

SQL не поддерживает циклы, рекурсии или пользовательские функции. Данный пример демонстрирует возможный обходной путь, использующий:

  • псевдостолбец level для создания псевдотаблиц t1 и t2 , содержащих числа от 1 до 16,
  • агрегатную функцию sum , позволяющую суммировать элементы множества без явного использования цикла,
  • и математические функции ln и exp , позволяющие заменить произведение (необходимое для вычисления факториала) на сумму (предоставляемую SQL).

Строка “0! = 1” не войдет в набор строк, полученный в результате, т.к. попытка вычислить ln(0) приводит к исключению.

Числа Фибоначчи:

Пример для версий Oracle 10g SQL , Oracle 11g SQL

SQL не поддерживает циклы или рекурсии, кроме того, конкатенация полей из разных строк таблицы или запроса не является стандартной агрегатной функцией. Данный пример использует:

  • формулу Бине и математические функции ROUND , POWER и SQRT для вычисления n-ого числа Фибоначчи;
  • псевдостолбец level для создания псевдотаблицы t1, содержащей числа от 1 до 16;
  • встроенную функцию SYS_CONNECT_BY_PATH для упорядоченной конкатенации полученных чисел.

SELECT REPLACE (MAX (SYS_CONNECT_BY_PATH (fib || ", " , "/" )), "/" , "" ) || "..." fiblist FROM ( SELECT n , fib , ROW_NUMBER () OVER (ORDER BY n ) r FROM (select n , round ((power ((1 + sqrt (5 )) * 0 . 5 , n ) - power ((1 - sqrt (5 )) * 0 . 5 , n )) / sqrt (5 )) fib from (select level n from dual connect by level <= 16 ) t1 ) t2 ) START WITH r = 1 CONNECT BY PRIOR r = r - 1 ;

Hello, World!:

Пример для версий Microsoft SQL Server 2005 , Microsoft SQL Server 2008 R2 , Microsoft SQL Server 2012 , MySQL 5 , PostgreSQL 8.4 , PostgreSQL 9.1 , sqlite 3.7.3

select "Hello, World!" ;

Факториал:

Пример для версий Microsoft SQL Server 2005 , Microsoft SQL Server 2008 R2 , Microsoft SQL Server 2012

Используется рекурсивное определение факториала, реализованное через рекурсивный запрос. Каждая строка запроса содержит два числовых поля — n и n!, и каждая следующая строка вычисляется с использованием данных из предыдущей.

Можно вычислить целочисленные факториалы только до 20!. При попытке вычислить 21! возникает ошибка “Arithmetic overflow error”, т.е. происходит переполнение разрядной сетки.

Для вещественных чисел вычисляется факториал 100! (Для этого в примере необходимо заменить bigint на float в 3-ей строке)

Числа Фибоначчи:

Пример для версий Microsoft SQL Server 2005 , Microsoft SQL Server 2008 R2 , Microsoft SQL Server 2012

Используется итеративное определение чисел Фибоначчи, реализованное через рекурсивный запрос. Каждая строка запроса содержит два соседних числа последовательности, и следующая строка вычисляется как (последнее число, сумма чисел) предыдущей строки. Таким образом все числа, кроме первого и последнего, встречаются дважды, поэтому в результат входят только первые числа каждой строки.

Факториал:

Пример для версий Oracle 10g SQL , Oracle 11g SQL

Этот пример демонстрирует использование оператора model , доступного начиная с версии Oracle 10g и позволяющего обработку строк запроса как элементов массива. Каждая строка содержит два поля — номер строки n и его факториал f.

select n || "! = " || f factorial from dual model return all rows dimension by ( 0 d ) measures ( 0 f , 1 n ) rules iterate (17 ) ( f [ iteration_number ] = decode (iteration_number , 0 , 1 , f [ iteration_number - 1 ] * iteration_number ), n [ iteration_number ] = iteration_number );

Числа Фибоначчи:

Пример для версий Oracle 10g SQL , Oracle 11g SQL

Этот пример демонстрирует использование оператора model , доступного начиная с версии Oracle 10g и позволяющего обработку строк запроса как элементов массива. Каждая строка содержит два поля — само число Фибоначчи и конкатенация всех чисел, меньше или равных ему. Итеративная конкатенация чисел в том же запросе, в котором они генерируются, выполняется проще и быстрее, чем агрегация как отдельное действие.

select max (s ) || ", ..." from (select s from dual model return all rows dimension by ( 0 d ) measures ( cast (" " as varchar2 (200 )) s , 0 f ) rules iterate (16 ) ( f [ iteration_number ] = decode (iteration_number , 0 , 1 , 1 , 1 , f [ iteration_number - 1 ] + f [ iteration_number - 2 ]), s [ iteration_number ] = decode (iteration_number , 0 , to_char (f [ iteration_number ]), s [ iteration_number - 1 ] || ", " || to_char (f [ iteration_number ])) ) );

Факториал:

Пример для версий MySQL 5

select concat (cast (t2 . n as char ), "! = " , cast (exp (sum (log (t1 . n ))) as char )) from ( select @ i : = @ i + 1 AS n from TABLE , (select @ i : = 0 ) as sel1 limit 16 ) t1 , ( select @ j : = @ j + 1 AS n from TABLE , (select @ j : = 0 ) as sel1 limit 16 ) t2 where t1 . n <= t2 . n group by t2 . n

Числа Фибоначчи:

Пример для версий MySQL 5

Замените TABLE на любую таблицу, к которой есть доступ, например, mysql.help_topic .

select concat (group_concat (f separator ", " ), ", ..." ) from (select @ f : = @ i + @ j as f , @ i : = @ j , @ j : = @ f from TABLE , (select @ i : = 1 , @ j : = 0 ) sel1 limit 16 ) t

Hello, World!:

Пример для версий Oracle 10g SQL , Oracle 11g SQL

В этом примере используется анонимный блок PL/SQL, который выводит сообщение в стандартный поток вывода с помощью пакета dbms_output .

begin dbms_output . put_line ("Hello, World!" ); end ;

Факториал:

Пример для версий Oracle 10g SQL , Oracle 11g SQL

Этот пример демонстрирует итеративное вычисление факториала средствами PL/SQL.

declare n number : = 0 ; f number : = 1 ; begin while (n <= 16 ) loop dbms_output . put_line (n || "! = " || f ); n : = n + 1 ; f : = f * n ; end loop ; end ;

Числа Фибоначчи:

Пример для версий Oracle 10g SQL , Oracle 11g SQL

Этот пример использует итеративное определение чисел Фибоначчи. Уже вычисленные числа хранятся в структуре данных varray — аналоге массива.

declare type vector is varray (16 ) of number ; fib vector : = vector (); i number ; s varchar2 (100 ); begin fib . extend (16 ); fib (1 ) : = 1 ; fib (2 ) : = 1 ; s : = fib (1 ) || ", " || fib (2 ) || ", " ; for i in 3 .. 16 loop fib (i ) : = fib (i - 1 ) + fib (i - 2 ); s : = s || fib (i ) || ", " ; end loop ; dbms_output . put_line (s || "..." ); end ;

Квадратное уравнение:

Пример для версий Oracle 10g SQL , Oracle 11g SQL

Этот пример тестировался в SQL*Plus, TOAD и PL/SQL Developer.

Чистый SQL позволяет вводить переменные в процессе исполнения запроса в виде заменяемых переменных. Для определения такой переменной ее имя (в данном случае A, B и C) следует использовать с амперсандом & перед ним каждый раз, когда нужно сослаться на эту переменную. Когда запрос выполняется, пользователь получает запрос на ввод значений всех заменяемых переменных, использованных в запросе. После ввода значений каждая ссылка на такую переменную заменяется на ее значение, и полученный запрос выполняется.

Существует несколько способов ввести значения для заменяемых переменных. В данном примере первая ссылка на каждую переменную предваряется не одинарным, а двойным амперсандом && . Таким образом значение для каждой переменной вводится только один раз, а все последующие ссылки на нее будут заменены тем же самым значением (при использовании одиночного амперсанда в SQL*Plus значение для каждой ссылки на одну и ту же переменную приходится вводить отдельно). В PL/SQL Developer ссылки на все переменные должны предваряться одиночным знаком & , иначе будет возникать ошибка ORA-01008 “Not all variables bound”.

Первая строка примера задает символ для десятичного разделителя, который используется при преобразовании чисел-корней в строки.

Сам запрос состоит из четырех разных запросов. Каждый запрос возвращает строку, содержащую результат вычислений, в одном из случаев (A=0, D=0, D>0 и D<0) и ничего — в трех остальных случаях. Результаты всех четырех запросов объединяются, чтобы получить окончательный результат.

alter session set NLS_NUMERIC_CHARACTERS = ". " ; select "Not a quadratic equation." ans from dual where && A = 0 union select "x = " || to_char (-&& B / 2 /& A ) from dual where & A != 0 and & B *& B - 4 *& A *&& C = 0 union select "x1 = " || to_char ((-& B + sqrt (& B *& B - 4 *& A *& C )) / 2 /& A ) || ", x2 = " || to_char (-& B - sqrt (& B *& B - 4 *& A *& C )) / 2 /& A from dual where & A != 0 and & B *& B - 4 *& A *& C > 0 union select "x1 = (" || to_char (-& B / 2 /& A ) || "," || to_char (sqrt (-& B *& B + 4 *& A *& C ) / 2 /& A ) || "), " || "x2 = (" || to_char (-& B / 2 /& A ) || "," || to_char (- sqrt (-& B *& B + 4 *& A *& C ) / 2 /& A ) || ")" from dual where & A != 0 and & B *& B - 4 *& A *& C < 0 ;

Зарезервированные слова являются постоянной частью языка SQL и имеют фиксированное значение . Их следует записывать в точности так, как это установлено, нельзя разбивать на части для переноса с одной строки на другую. Слова, определяемые пользователем, задаются им самим (в соответствии с синтаксическими правилами) и представляют собой идентификаторы или имена различных объектов базы данных . Слова в операторе размещаются также в соответствии с установленными синтаксическими правилами.

Идентификаторы языка SQL предназначены для обозначения объектов в базе данных и являются именами таблиц , представлений, столбцов и других объектов базы данных . Символы, которые могут использоваться в создаваемых пользователем идентификаторах языка SQL , должны быть определены как набор символов. Стандарт SQL задает набор символов, который используется по умолчанию, – он включает строчные и прописные буквы латинского алфавита (A-Z , a-z ), цифры (0-9 ) и символ подчеркивания (_ ). На формат идентификатора накладываются следующие ограничения:

  • идентификатор может иметь длину до 128 символов;
  • идентификатор должен начинаться с буквы;
  • идентификатор не может содержать пробелы.

<идентификатор>::=<буква> {<буква>|<цифра>}[,...n]

Большинство компонентов языка не чувствительны к регистру. Поскольку у языка SQL свободный формат, отдельные SQL - операторы и их последовательности будут иметь более читаемый вид при использовании отступов и выравнивания.

Язык, в терминах которого дается описание языка SQL, называется метаязыком . Синтаксические определения обычно задают с помощью специальной металингвистической символики, называемой Бэкуса-Науэра формами (БНФ). Прописные буквы используются для записи зарезервированных слов и должны указываться в операторах точно так, как это будет показано. Строчные буквы употребляются для записи слов, определяемых пользователем. Применяемые в нотации БНФ символы и их обозначения показаны в таблице .

Таблица 1.1.
Символ Обозначение
::= Равно по определению
| Необходимость выбора одного из нескольких приведенных значений
<…> Описанная с помощью метаязыка структура языка
{…} Обязательный выбор некоторой конструкции из списка
[…] Необязательный выбор некоторой конструкции из списка
[,…n] Необязательная возможность повторения конструкции от нуля до нескольких раз

Описание учебной базы данных

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

Исходя из анализа предметной области , можно выделить два типа сущностей – ТОВАР и КЛИЕНТ , которые связаны между собой отношением "многие–ко–многим", т.к. каждый покупатель может купить много наименований товара, а каждый товар может быть куплен многими покупателями. Однако реляционная модель данных требует заменить отношение "многие–ко-многим" на несколько отношений "один–ко-многим". Добавим еще один тип сущностей, отображающий процесс продажи товаров, – СДЕЛКА .

Установим связи между объектами. Один покупатель может неоднократно покупать товары, поэтому между объектами КЛИЕНТ и СДЕЛКА имеется связь "один–ко–многим". Каждое наименование товара может неоднократно участвовать в сделках, в результате между объектами ТОВАР и СДЕЛКА имеется связь " один-ко-многим ".

Определим атрибуты и свяжем их с сущностями и связями . К объекту ТОВАР относятся такие характеристики, как название, тип, цена, сорт. К объекту КЛИЕНТ – имя, отчество, фамилия, фирма , город, телефон. Тип сущности СДЕЛКА может быть охарактеризован такими признаками, как дата и количество проданного товара.

Важным этапом в создании базы данных является определение атрибутов, которые однозначно определяют каждый экземпляр сущности , т.е. выявление первичных ключей .

Для таблицы ТОВАР название не может служить первичным ключом , т.к. товары разных типов могут иметь одинаковые названия, поэтому введем первичный ключ КодТовара , под которым можно понимать, например, артикул товара . Точно так же ни Имя , ни Фирма , ни Город не могут служить первичным ключом в таблице КЛИЕНТ . Введем первичный ключ КодКлиента , под которым можно понимать номер паспорта, идентификационный номер налогоплательщика или любой другой атрибут , однозначно определяющий каждого клиента. Для таблицы СДЕЛКА первичным ключом является поле КодСделки , т.к. оно однозначно определяет дату, покупателя и другие элементы данных. В качестве первичного ключа можно было бы выбрать не одно поле , а некоторую совокупность полей, но для иллюстрации конструкций языка ограничимся простыми первичными ключами .

Оконные функции поддерживаются не во всех элементах запросов, а только в предложениях SELECT и ORDER BY. Чтобы вы поняли причину такого ограничения, я сначала объясню принцип, который называется логической обработкой запроса . После этого я вернусь к инструкциям, которые поддерживают оконные функции, и в конце объясню, как обойти это ограничение в других предложениях.

Логическая обработка запросов

Логическая обработка запросов описывает принципы оценки запроса SELECT в соответствии с логической системой языка. Она описывает процесс, состоящий из нескольких этапов, или фаз, которые начинаются входными таблицами запроса и заканчиваются результирующим набором запроса.

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

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

На следующем рисунке представлена схема логической обработки запроса в SQL Server 2012:

Заметьте, что при написании запроса предложение SELECT всегда пишется первым, но в процессе логической обработки оно находится практически в самом конце - непосредственно перед обработкой предложения ORDER BY.

Логической обработке запросов можно посвятить целую книгу, но для нашей цели достаточно более лаконичного изложения. Для целей нашей дискуссии важно заметить порядок, в которой обрабатываются разные предложения. Следующий список представляет этот порядок (фазы, в которых разрешены оконные функции, выделены цветом):

    1. Вычисление выражений

      Удаление дубликатов

  1. OFFSET-FETCH/TOP

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

Предложения, поддерживающие оконные функции

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

Я попытаюсь продемонстрировать эту неоднозначность на примере. Сначала выполните следующий код, чтобы создать таблицу T1 и наполнить ее данными:

SET NOCOUNT ON; USE TSQL2012; IF OBJECT_ID("dbo.T1", "U") IS NOT NULL DROP TABLE dbo.T1; GO CREATE TABLE dbo.T1 (col1 VARCHAR(10) NOT NULL CONSTRAINT PK_T1 PRIMARY KEY); INSERT INTO dbo.T1(col1) VALUES("A"),("B"),("C"),("D"),("E"),("F"); GO

Допустим, что оконные функции разрешены на этапах, предшествующих SELECT, например на этапе WHERE. Посмотрите на следующий запрос и попытайтесь определить, какие значения col1 должны содержаться в результате:

Прежде чем говорить, что это очевидно, что это должны быть значения C, D и Е, вспомните о принципе «все сразу» в SQL. Этот принцип подразумевает, что с точки зрения концепции все выражения одного логического этапа выполняются одновременно. Это значит, что порядок следования выражений не должен влиять на результат. Если так, то следующий запрос должен быть семантически эквивалентен такому:

Сможете ли вы на этот раз определить, какое выражение правильное? Это C, D и Е или только C?

Это пример неоднозначности, о которой я говорил. Разрешение использовать оконные функции только в предложениях SELECT и ORDER BY позволяет избавиться от этой неоднозначности.

При анализе блок-схемы на рисунке выше вы могли заметить, что на этапе SELECT оконные функции поддерживает шаг 5-1 (Вычисление выражений) и он выполняет перед шагом 5-2 (Удаление дубликатов). Если вы спросите, почему так важно знать такие детали, я продемонстрирую, зачем это нужно.

Вот вопрос, возвращающий атрибуты empid и country всех сотрудников из таблицы сотрудников Employees:

SELECT empid, country FROM HR.Employees;

А теперь посмотрите на следующий запрос и попытайтесь до выполнения запроса определить, каким будет результат:

SELECT DISTINCT country, ROW_NUMBER() OVER(ORDER BY country) AS rownum FROM HR.Employees;

Некоторые будут ожидать такой результат:

Но на самом деле вы получите это:

А теперь вспомните, что в этом запросе функция ROW_NUMBER вычисляется на шаге 5-1, на котором вычисляются выражения списка SELECT - до удаления дубликатов на шаге 5-2. Функция ROW_NUMBER назначает девять уникальных номеров строк, содержащих информацию о сотрудниках, поэтому предложению DISTINCT нечего удалять.

Когда вы осознаете, что причина в порядке логической обработки запроса разных элементов, вы можете подумать о решении. Например, можно создать табличное выражение, основанное на запросе, которое просто возвращает уникальные страны, и назначать номера строк внешним запросом после удаления дубликатов:

WITH EmpCountries AS (SELECT DISTINCT country FROM HR.Employees) SELECT country, ROW_NUMBER() OVER(ORDER BY country) AS rownum FROM EmpCountries;

Можете ли вы представить себе другие способы решения задачи, по крайней мере проще, чем это?

Тот факт, что оконные функции оцениваются на этапе SELECT или ORDER BY означает, что окно, определенное для вычисления, - до применения последующих ограничений - является промежуточной формой строк, полученной после всех предшествующих фаз, то есть после применения FROM со всеми табличными операторами (например, соединениями), а также фильтрации с применением WHERE, группировки и фильтрации групп. Такой запрос можно считать примером:

Сначала вычисляется предложение FROM, после чего выполняется соединение. Затем фильтр оставляет только строки, относящиеся к 2007 году. После этого оставшиеся строки группируются по идентификатору сотрудника. Только после этого вычисляются выражения в списке SELECT, в числе которых функция RANK, которая вычисляется с использование упорядочения по убыванию общего количества. Если бы в списке SELECT были другие оконные функции, в них в качестве исходной точки использовался этот же набор результатов.

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

В обход ограничений

Я объяснил, почему запретили использование оконных функций на этапах логической обработки запроса, предшествующих предложению SELECT. Но что, если нужно выполнять фильтрацию или группировку на основе вычислений, выполненных в оконных функциях? Решение заключается в использовании табличного выражения, такого как CTE или производная таблица. Заставьте запрос вызывать оконную функцию в его списке SELECT, назначив выражению псевдоним. Определите на основе этого запроса табличное выражение, после чего сошлитесь на него в запросе по псевдониму.

Вот пример, демонстрирующий, как можно фильтровать на основе результатов оконной функции с использованием CTE:

В инструкциях, изменяющих данные, оконные функции полностью запрещены, потому что в этих инструкциях не поддерживаются предложения SELECT и ORDER BY. Но есть случаи, когда оконные функции нужны в изменяющих данные инструкциях. Табличные выражения позволяют решить и эту проблему, потому что T-SQL позволяет менять данные через табличные выражения. Продемонстрирую это поведение на примере UPDATE. Сначала выполните следующий код, чтобы создать таблицу T1 со столбцами col1 и col2 и наполнить ее данными:

SET NOCOUNT ON; USE TSQL2012; IF OBJECT_ID("dbo.T1", "U") IS NOT NULL DROP TABLE dbo.T1; GO CREATE TABLE dbo.T1 (col1 INT NULL, col2 VARCHAR(10) NOT NULL); INSERT INTO dbo.T1(col2) VALUES("C"),("A"),("B"),("A"),("C"),("B"); GO

Значения столбца col2 определены явно, a col1 был заполнен значениями NULL.

Представьте, что эта таблица иллюстрирует ситуацию с проблемами с качеством данных. В этой таблице не создан ключ, поэтому невозможно уникально идентифицировать строки. Вы хотите назначить уникальные значения в столбце col1 для всех строк. Вы подумали, что удобно было бы использовать функцию ROW_NUMBER в инструкции UPDATE следующим образом:

UPDATE dbo.T1 SET col1 = ROW_NUMBER() OVER(ORDER BY col2);

Но, как вы помните, в такой инструкции это запрещено. Обходной способ заключается в создании запроса по отношению к T1, который возвращает col1, и выражения, основанного на функции ROW_NUMBER (назовем ее rownum); определите табличное выражение, основанное на этом запросе, и, наконец, примените инструкцию UPDATE к CTE для присвоения значения rownum столбцу col1:

WITH C AS (SELECT col1, col2, ROW_NUMBER() OVER(ORDER BY col2) AS rownum FROM dbo.T1) UPDATE C SET col1 = rownum; SELECT col1, col2 FROM dbo.T1;

Получите данные из T1 - вы увидите, что все строки получили уникальное значение в столбце col1:

Возможность создания дополнительных фильтров

Я показал, как в T-SQL можно прибегнуть к обходному решению и косвенным образом использовать оконные функции в элементах, которые не поддерживают их напрямую. Это обходное решение основано на применении табличного выражения в форме CTE или производной таблицы. Приятно иметь дополнительный вариант, но в табличном выражении используется дополнительный уровень запроса и все немного усложняется. Приведенные мной примеры просты, но как насчет длинных и сложных запросов. Возможно ли более простое решение без этого дополнительного уровня?

Если говорить об оконных функциях, то в SQL Server на текущий момент нет другого решения. Вместе с тем, интересно посмотреть, как другие справляются с этой проблемой. Например, в Teradata создали фильтрующее предложение, которое называется QUALIFY и принципиально вычисляется после предложения SELECT. Это означает, что в нем можно напрямую обращаться к оконным функциям, как в следующем примере:

Не работает в SQL Server 2012 SELECT orderid, orderdate, val FROM Sales.OrderValues QUALIFY RANK() OVER(ORDER BY val DESC)

Более того, можно ссылаться на псевдонимы столбцов, определенных в списке SELECT, так:

Не работает в SQL Server 2012 SELECT orderid, orderdate, val, RANK() OVER(ORDER BY val DESC) AS rnk FROM Sales.OrderValues QUALIFY rnk

Предложения QUALIFY нет в стандартном SQL - оно поддерживается только в продуктах Teradata. Но оно кажется очень интересным решением, и было бы неплохо, если бы и стандарт, и в SQL Server удовлетворили такую потребность.

Повторное использование определений окон

Представьте, что вам нужно вызвать несколько оконных функций в одном запросе, при этом часть определения окна (или все определение) у нескольких функций совпадает. Если указать определение окна во всех функциях, код может сильно увеличиться в объеме, как в этом примере:

SELECT empid, ordermonth, qty, SUM(qty) OVER (PARTITION BY empid ORDER BY ordermonth ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS run_sum_qty, AVG(qty) OVER (PARTITION BY empid ORDER BY ordermonth ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS run_avg_qty, MIN(qty) OVER (PARTITION BY empid ORDER BY ordermonth ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS run_min_qty, MAX(qty) OVER (PARTITION BY empid ORDER BY ordermonth ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS run_max_qty FROM Sales.EmpOrders;

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

SQL Server пока не поддерживает предложение WINDOW . В стандартном SQL можно сократить предыдущий запрос с использованием предложения WINDOW так:

Не работает в SQL Server 2012 SELECT empid, ordermonth, qty, SUM(qty) OVER W1 AS run_sum_qty, AVG(qty) OVER W1 AS run_avg_qty, MIN(qty) OVER W1 AS run_min_qty, MAX(qty) OVER W1 AS run_max_qty FROM Sales.EmpOrders WINDOW W1 AS (PARTITION BY empid ORDER BY ordermonth ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW);

Как видите, разница ощутима. В данном случае предложение WINDOW присваивает имя W1 полному определению окна с параметрами секционирования, упорядочения и кадрирования. После этого W1 используется в качестве определения окна во всех четырех функциях. Предложение WINDOW довольно сложное. Как уже говорилось, не обязательно присваивать имя полному определению окна - можно назначать имя только части определения. В таком случае определение окна содержит смесь именованных частей и явно заданных параметров. Кстати сказать, описание предложения WINDOW в стандарте SQL занимает целых десять страниц! И разобраться в них не так-то просто.

Было бы замечательно, если бы в SQL Server добавили поддержку это-го предложения, особенно теперь, когда расширилась поддержка оконных функций и пользователям придется писать длинные определения окон.

Последнее обновление: 24.06.2017

SQL Server является одной из наиболее популярных систем управления базами данных (СУБД) в мире. Данная СУБД подходит для самых различных проектов: от небольших приложений до больших высоконагруженных проектов.

SQL Server был создан компанией Microsoft. Первая версия вышла в 1987 году. А текущей версией является версия 16, которая вышла в 2016 году и которая будет использоваться в текущем руководстве.

SQL Server долгое время был исключительно системой управления базами данных для Windows, однако начиная с версии 16 эта система доступна и на Linux.

SQL Server характеризуется такими особенностями как:

    Производительность. SQL Server работает очень быстро.

    Надежность и безопасность. SQL Server предоставляет шифрование данных.

    Простота. С данной СУБД относительно легко работать и вести администрирование.

Центральным аспектом в MS SQL Server, как и в любой СУБД, является база данных. База данных представляет хранилище данных, организованных определенным способом. Нередко физически база данных представляет файл на жестком диске, хотя такое соответствие необязательно. Для хранения и администрирования баз данных применяются системы управления базами данных (database management system) или СУБД (DBMS). И как раз MS SQL Server является одной из такой СУБД.

Для организации баз данных MS SQL Server использует реляционную модель. Эта модель баз данных была разработана еще в 1970 году Эдгаром Коддом. А на сегодняшний день она фактически является стандартом для организации баз данных.

Реляционная модель предполагает хранение данных в виде таблиц, каждая из которых состоит из строк и столбцов. Каждая строка хранит отдельный объект, а в столбцах размещаются атрибуты этого объекта.

Для идентификации каждой строки в рамках таблицы применяется первичный ключ (primary key). В качестве первичного ключа может выступать один или несколько столбцов. Используя первичный ключ, мы можем ссылаться на определенную строку в таблице. Соответственно две строки не могут иметь один и тот же первичный ключ.

Через ключи одна таблица может быть связана с другой, то есть между двумя таблицами могут быть организованы связи. А сама таблица может быть представлена в виде отношения ("relation").

Для взаимодействия с базой данных применяется язык SQL (Structured Query Language). Клиент (например, внешняя программа) отправляет запрос на языке SQL посредством специального API. СУБД должным образом интерпретирует и выполняет запрос, а затем посылает клиенту результат выполнения.

Изначально язык SQL был разработан в компании IBM для системы баз данных, которая называлась System/R. При этом сам язык назывался SEQUEL (Structured English Query Language). Хотя в итоге ни база данных, ни сам язык не были впоследствии официально опубликованы, по традиции сам термин SQL нередко произносят как "сиквел".

В 1979 году компания Relational Software Inc. разработала первую систему управления баз данных, которая называлась Oracle и которая использовала язык SQL. В связи с успехом данного продукта компания была переименована в Oracle.

Впоследствии стали появляться другие системы баз данных, которые использовали SQL. В итоге в 1989 году Американский Национальный Институт Стандартов (ANSI) кодифицировал язык и опубликовал его первый стандарт. После этого стандарт периодически обновлялся и дополнялся. Последнее его обновление состоялось в 2011 году. Но несмотря на наличие стандарта нередко производители СУБД используют свои собственные реализации языка SQL, которые немного отличаются друг от друга.

Выделяются две разновидности языка SQL: PL-SQL и T-SQL. PL-SQL используется в таких СУБД как Oracle и MySQL. T-SQL (Transact-SQL) применяется в SQL Server. Собственно поэтому в рамках текущего руководства будет рассматриваться именно T-SQL.

В зависимости от задачи, которую выполняет команда T-SQL, он может принадлежать к одному из следующих типов:

    DDL (Data Definition Language / Язык определения данных). К этому типу относятся различные команды, которые создают базу данных, таблицы, индексы, хранимые процедуры и т.д. В общем определяют данные.

    В частности, к этому типу мы можем отнести следующие команды:

    • CREATE : создает объекты базы данных (саму базу даных, таблицы, индексы и т.д.)

      ALTER : изменяет объекты базы данных

      DROP : удаляет объекты базы данных

      TRUNCATE : удаляет все данные из таблиц

    DML (Data Manipulation Language / Язык манипуляции данными). К этому типу относят команды на выбору данных, их обновление, добавление, удаление - в общем все те команды, с помощью которыми мы можем управлять данными.

    К этому типу относятся следующие команды:

    • SELECT : извлекает данные из БД

      UPDATE : обновляет данные

      INSERT : добавляет новые данные

      DELETE : удаляет данные

    DCL (Data Control Language / Язык управления доступа к данным). К этому типу относят команды, которые управляют правами по доступу к данным. В частности, это следующие команды:

    • GRANT : предоставляет права для доступа к данным

      REVOKE : отзывает права на доступ к данным

Стандарт языка SQL был принят в 1992 году и используется до сих пор. Именно он и стал эталоном для многих Конечно, некоторые производители используют свои интерпретации стандарта. Но в любой системе все же имеются главные составляющие — операторы SQL.

Введение

С помощью операторов SQL в происходит управление значениями, таблицами и получение их для дальнейшего анализа и отображения. Они представляют собой набор ключевых слов, по которым система понимает, что делать с данными.

Определяют несколько категорий операторов SQL:

  • определение объектов базы данных;
  • манипулирование значениями;
  • защита и управление;
  • параметры сеанса;
  • информация о базе;
  • статический SQL;
  • динамический SQL.

Операторы SQL для манипулирования данными

INSERT. Вставляет строки в существующую таблицу. Может использоваться как для одного значения, так и нескольких, определённых по некоему условию. Например:

имя таблицы (имя столбца 1, имя столбца 2)

VALUES (значение 1, значение 2).

Для использования оператора INSERT при нескольких значениях, применяется такой синтаксис:

имя таблицы 1 (имя столбца 1, имя столбца 2)

SELECT имя столбца 1, имя столбца 2

FROM имя таблицы 2

WHERE имя таблицы 2.имя столбца 1>2

Этот запрос выберет все данные из таблицы 2, которые больше 2 по столбцу 1 и вставит их в первую.

UPDATE. Как видно из названия, этот оператор SQL запроса обновляет данные в существующей таблице по определённому признаку.

UPDATE имя таблицы 1

SET имя столбца 2 = «Василий»

WHERE имя таблицы 1.имя столбца 1 = 1

Данная конструкция заполнит значением Василий все строки, в которых встретит цифру 1 в первом столбце.

Данные из таблицы. Можно указать какое-либо условие или же убрать все строки.

DELETE FROM имя таблицы

WHERE имя таблицы.имя столбца 1 = 1

Приведённый запрос удалит из базы все данные со значением один в первом столбце. А вот так можно очистить всю таблицу:

Оператор SELECT

Главное назначение SELECT — выборка данных по определенным условиям. Результатом его работы всегда является новая таблица с отобранными данными. Оператор MS может быть использован в массе различных запросов. Поэтому наряду с ним можно рассмотреть и другие смежные ключевые слова.

Для выбора всех данных из определённой таблицы используется знак «*».

FROM имя таблицы 1

Результатом работы данного запроса будет точная копия таблицы 1.

А здесь происходит выборка по условию WHERE, которое достаёт из таблицы 1 все значения, больше 2 в столбце 1.

FROM имя таблицы 1

WHERE имя таблицы 1.имя столбца 1 > 2

Также можно указать в выборке, что нужны только определённые столбцы.

SELECT имя таблицы 1.имя столбца 1

FROM имя таблицы 1

Результатом данного запроса будут все строки, со значениями из столбца 1. С помощью операторов MS SQL можно составить собственную таблицу, на ходу заменив, вычислив и подставив определённые значения.

имя таблицы 1.имя столбца 1

имя таблицы 1.имя столбца 2

имя таблицы 1.имя столбца 3

имя таблицы 1.имя столбца 2 * имя таблицы 1.имя столбца 3 AS SUMMA

FROM имя таблицы 1

Данный, на первый взгляд сложный запрос выполняет выборку всех значений из таблицы 1, затем создаёт новые колонки EQ и SUMMA. В первую заносит знак «+», во вторую произведение данных из столбца 2 и 3. Полученный результат можно представить в виде таблицы, для понимания как это работает:

При использовании оператора SELECT, можно сразу провести упорядочивание данных по какому-либо признаку. Для этого используется слово ORDER BY.

имя таблицы 1.имя столбца 1

имя таблицы 1.имя столбца 2

имя таблицы 1.имя столбца 3

FROM имя таблицы 1

ORDER BY имя столбца 2

Результирующая таблица будет выглядеть таким образом:

То есть все строки были установлены в таком порядке, чтобы в столбце 2 значения шли по возрастанию.

Данные можно получать и из нескольких таблиц. Для наглядности сначала нужно представить, что их в базе имеется две, примерно такие:

Таблица «Сотрудники»

Таблица «Зарплата»

Теперь нужно, как-то связав эти две таблицы получить общие значения. Используя основные операторы SQL сделать это можно так:

Сотрудники.Номер

Сотрудники.Имя

Зарплата.Ставка

Зарплата.Начислено

FROM Сотрудники, Зарплата

WHERE Сотрудники.Номер = Зарплата.Номер

Здесь происходит выборка из двух разных таблиц значений, объединённых по номеру. Результатом будет следующий набор данных:

Ещё немного о SELECT. Использование агрегатных функций

Один из основных операторов может производить некоторые вычисления при выборке. Для этого он использует определённые функции и формулы.

К примеру, чтобы получить количество записей из таблицы «Сотрудники», нужно использовать запрос:

SELECT COUNT (*) AS N

FROM Сотрудники

В результате получится таблица с одним значением и столбцом.

Можно применить такой запрос и посмотреть что получится:

SUM(Зарплата.Начислено) AS SUMMA

MAX(Зарплата.Начислено) AS MAX

MIN(Зарплата.Начислено) AS MIN

AVG(Зарплата.Начислено) AS SRED

FROM Зарплата

Итоговая таблица будет такой:

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

Объединение, пересечение и разности

Объединить несколько запросов в SQL

SELECT Сотрудники.Имя

FROM Сотрудники

WHERE Сотрудники.Номер = 1

SELECT Сотрудники.Имя

FROM Сотрудники, Зарплата

WHERE Зарплата.Номер = 1

При этом стоит учитывать, что при таком объединении таблицы должны быть совместимы. То есть иметь одинаковое количество столбцов.

Синтаксис оператора SELECT и порядок его обработки

Первым делом SELECT определяет область, из которой он будет брать данные. Для этого используется ключевое слово FROM. Если не указано, что именно выбрать.

Затем может присутствовать SQL оператор WHERE. С его помощью SELECT пробегает по всем строкам таблицы и проверяет данные на соответствие условию.

Если в запросе имеется GROUP BY, то происходит группировка значений по указанным параметрам.

Операторы для сравнения данных

Их имеется несколько типов. В SQL операторы сравнения могут проверять различные типы значений.

    «=». Обозначает, как можно догадаться, равенство двух выражений. Например, он уже использовался в примерах выше - WHERE Зарплата.Номер = 1.

    «>». Знак больше. Если значение левой части выражения больше, то возвращается логическое TRUE и условие считается выполненным.

    «<». Знак меньше. Обратный предыдущему оператор.

    Знаки «<=» и «>=». Отличается от простых операторов больше и меньше, тем, что при равенстве операндов условие также будет истинным.

LIKE

Перевести данное ключевое слово можно как «похожий». Оператор LIKE в SQL используется примерно по такому же принципу — выполняет запрос по шаблону. То есть он позволяет расширить выборку данных из базы используя регулярные выражения.

Например, поставлена такая задача: из уже известной базы «Сотрудники» получить всех людей, чьё имя заканчивается на «я». Тогда запрос можно составить так:

FROM Сотрудники

WHERE Имя LIKE `%я`

Знак процента в данном случае означает маску, то есть любой символ и их количество. А по букве «я» SQL определит что последний символ должен быть именно таким.

CASE

Данный оператор SQL Server представляет собой реализацию множественного выбора. Он напоминает конструкцию switch во многих языках программирования. Оператор CASE в SQL выполняет действие по нескольким условиям.

Например, нужно выбрать из таблицы «Зарплата» максимальное и минимальное значение.

Тогда запрос можно составить так:

FROM Зарплата

WHERE CASE WHEN SELECT MAX(Начислено) THEN Максимум

WHEN SELECT MIN(Начислено) THEN Минимум

В данном контексте система ищет максимальное и минимальное значение в столбце «Начислено». Затем с помощью END создаётся поле «итог», в которое будет заноситься «Максимум» или «Минимум» в зависимости от результата выполнения условия.

Кстати, в SQL имеется и более компактная форма CASE — COALESCE.

Операторы определения данных

Это вид позволяет проводить разнообразное изменение таблиц — создание, удаление, модификации и работу с индексами.

Первый из них, который стоит рассмотреть — CREATE TABLE. Он делает не что иное, как создаёт таблицу. Если просто набрать запрос CREATE TABLE, ничего не случится, так как нужно ещё указать несколько параметров.

Например, для создания уже знакомой таблицы «Сотрудники» нужно использовать команды:

CREATE TABLE Сотрудники

(Номер number(10) NOT NULL

Имя varchar(50) NOT NULL

Фамилия varchar(50) NOT NULL)

В это запросе, в скобках сразу же определяются имена полей и их типы, а также может ли он быть равен NULL.

DROP TABLE

Выполняет одну простую задачу — удаление указанной таблицы. Имеет дополнительный параметр IF EXISTS. Он поглощает ошибку при удалении, если искомая таблица не существует. Пример использования:

DROP TABLE Сотрудники IF EXISTS.

CREATE INDEX

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

CREATE INDEX название_индекса

ON название_таблицы(название_столбца)

Используется данный оператор в T-SQL, Oracle, PL SQL и многих других интерпретациях технологиях.

ALTER TABLE

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

    ADD. Осуществляет добавление столбца в таблицу. Синтаксис его такой: ALTER TABLE название_таблицы ADD название_столбца тип_хранимых_данных. Может иметь параметр IF NOT EXISTS, что подавить ошибку, если создаваемый столбец уже есть;

    DROP. Удаляет столбец. Также имеет ключ IF EXISTS, без которого сгенерируется ошибка, говорящая о том, что требуемый столбец отсутствует;

    CHANGE. Служит для переименования имени поля в указанное. Пример использования: ALTER TABLE название_таблицы CHANGE старое_имя новое_имя;

    MODIFY. Данная команда поможет сменить тип и дополнительные атрибуты определённого столбца. А используется он вот так: ALTER TABLE название_таблицы MODIFY название_столбца тип_данных атрибуты;

CREATE VIEW

В SQL имеется такое понятие, как представление. Вкратце, это некая виртуальная таблица с данными. Образуется она в результате выборки с помощью оператора языка SQL SELECT. Представления могут ограничивать доступ к базе данных, скрывать их, заменять реальные имена столбцов.

Процесс создания происходит с помощью простого запроса:

CREATE VIEW название представления AS SELECT FROM * название таблицы

Выборка может происходить как всей базы целиком, так и по некоторому условию.

Немного о функциях

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

    COUNT. Производит подсчёт записей или строк в конкретной таблице. В качестве параметра можно указать имя столбца, тогда данные будут взяты из него. SELECT COUNT * FROM Сотрудники;

    AVG. применяется только на столбцы с числовыми данными. Ее результатом является определение среднего арифметического всех значений;

    MIN и MAX. Эти функции уже использовались в этой статье. Определяют они максимальное и минимальное значения из указанного столбца;

    SUM. Все просто — функция вычисляет сумму значений столбца. Применяется исключительно для числового вида данных. Добавив в запрос параметр DISTINCT, будут суммироваться только уникальные значения;

    ROUND. Функция округления десятичных дробных чисел. В синтаксисе используется название столбца и количество знаков после запятой;

    LEN. Простая функция, вычисляющая длину значений столбца. Результатом будет новая таблица с указанием количества символов;

    NOW. Это ключевое слово используется для вычисления текущей даты и времени.

Дополнительные операторы

Многие примеры с операторами SQL имеют ключевые слова, которые выполняют небольшие задачи, но тем не менее сильно упрощают выборку или действия с базами данных.

    AS. Применяется, когда нужно визуально оформить результат, присваивая указанное имя получившейся таблице.

    BETWEEN. Очень удобный инструмент для выборки. Он указывает область значений, среди которых нужно получить данные. На вход принимает параметр от и до какого числа используется диапазон;.

    NOT. Оператор придаёт противоположность выражению.

    TRUNCATE. Удаляет данные из указанного участка базы. Отличается от аналогичных операторов тем, что восстановить данные после его использования невозможно. Стоит учесть, что реализация данного ключевого слова в различных интерпретациях SQL может отличаться. Поэтому перед тем как пробовать использовать TRUNCATE, лучше ознакомиться со справочной информацией.

    LIMIT. Устанавливает количество строк для вывода. Особенность оператора в том, что он всегда располагается в конце. Принимает один обязательный параметр и один опциональный. Первый указывает, сколько строк с выбранными данными нужно показать. А если используется второй, то оператор срабатывает как для диапазона значений.

    UNION. Очень удобный оператор для объединения нескольких запросов. Он уже встречался среди примеров этой в этой статье. Можно вывести нужные строки из нескольких таблиц, объединив их UNION для более удобного использования. Синтаксис его такой: SELECT имя_столбца FROM имя_таблицы UNION SELECT имя_другого_столбца FROM имя_другой таблицы. В результате получится сводная таблица с объединёнными запросами.

    PRIMARY KEY. Переводится как «первичный ключ». Собственно, именно такая терминология и используется в справочных материалах. Он означает уникальный идентификатор строки. Применяется, как правило, при создании таблицы для указания поля, которое и будет содержать его.

    DEFAULT. Так же, как и предыдущий оператор, используется в процессе выполнения создающего запроса. Он определяет значение по умолчанию, которым будет заполнено поле при его создании.

    NULL. Начинающие и не только программисты при составлении запросов очень часто забывают о возможности получения значения NULL. В итоге в код закрадывается ошибка, которую трудно отследить в процессе отладки. Поэтому при создании таблиц, выборке или пересчёте значений нужно остановиться и подумать, а учтено ли возникновение NULL в это участке запроса.

    Память. В этой статье были показаны несколько функций, способные выполнять некоторые задачи. При разработке оболочки для работы с базой, можно «перевесить» вычисление простых выражений на систему управления базами данных. В некоторых случаях это даёт значительный прирост в производительности.

    Ограничения. Если нужно получить из базы с тысячами строк всего лишь двух, то стоит использовать операторы типа LIMIT или TOP. Не нужно извлекать данные средствами языка разработки оболочки.

    Соединение. После получения данных из нескольких таблиц многие программисты начинают сводить их воедино средствами памяти оболочки. Но зачем? Ведь можно составить один запрос в котором это все будет присутствовать. Не придётся писать лишний код и резервировать дополнительную память в системе.

    Сортировка. Если есть возможность применять упорядочивание в запросе, то есть силами СУБД, то нужно её использовать. Это позволит значительно сэкономить на ресурсах при работе программы или сервиса.

    Много запросов. Если приходится вставлять множество записей последовательно, то для оптимизации следует задуматься о пакетной вставке данных одним запросом. Это также позволит увеличить производительность всей системы в целом.

    Продуманное размещение данных. Перед составлением структуры базы нужно задуматься о том, а необходимо ли такое количество таблиц и полей. Может есть способ объединить их или отказаться от некоторых. Очень часто программисты применяют избыточное количество данных, которые нигде и никогда не будут использоваться.

    Типы. Для экономии места и ресурсов нужно чутко относиться к видам используемых данных. Если есть возможность воспользоваться менее «тяжёлым» для памяти типом, то надо применять именно его. Например, если известно, что в данном поле числовое значение не будет превышать 255, то зачем использовать 4-байтный INT, если есть TINYINT в 1 байт.

Заключение

В заключение нужно отметить, что язык структурированных запросов SQL сейчас используется практически повсеместно — сайты, веб-сервисы, программы для ПК, приложения для мобильных устройств. Поэтому знание SQL поможет всем отраслям разработки.

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

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