25. Оператор SELECT

 

25.1. Простейший вид оператора SELECT *

25.2. Использование предложения WHERE *

25.2.1. Сравнение значения столбца с константой *

25.2.2. Сравнение значения столбца из одной таблицы со значением столбца из другой таблицы (внутреннее соединение) *

25.3. Использование псевдонимов таблиц *

25.4. Предложение ORDER BY - определение сортировки *

25.5. Устранение повторяющихся значений *

25.6. Расчет значений результирующих столбцов на основе арифметических выражений *

25.7. Агрегатные функции *

25.8. Использование группировок записей *

25.9. Предложение HAVING - наложение ограничений на группировку записей *

25.10. Предложение WHERE : задание сложных условий поиска *

25.10.1. Использование логических выражений *

25.10.2. Сравнение столбца с результатом вычисления выражения *

25.10.3. Использование BETWEEN *

25.10.4. Использование IN (список значений) *

25.10.5. Использование STARTING *

25.10.6. Использование CONTAINING *

25.10.7. Использование функции UPPER *

25.10.8. Использование LIKE *

25.10.9. Использование функции CAST *

25.11. Использование подзапросов *

25.12. Вложение подзапросов *

25.13. Дополнительные возможности использования подзапросов, возвр единичное значение *

25.13.1. Использование EXISTS *

25.13.2. Использование SINGULAR *

25.14. Использование подзапросов, возвращающих множество значений *

25.14.1. Использование ALL, SOME *

25.14.2. Использование HAVING и агрегатных функций для вложенных подзапросов *

25.15. Внешние соединения *

25.16. UNION - объединение результатов выполнения нескольких операторов SELECT *

25.17. Использование IS NULL *

25.18. Использование операции сцепления строк *

25.19. Работа с разными БД в одном запросе *

25. Оператор SELECT

Оператор SELECT - один из наиболее важных и самый используемый оператор SQL. Он позволяет производить выборки данных из ТБД и преобразовывать к нужному виду полученные результаты. Это очень мощный оператор. При его помощи можно реализовать весьма сложные и громоздкие условия выбора данных из различных таблиц.

Для тех, кто ранее не использовал SQL для доступа к БД, примеры использования данного оператора наглядно продемонстрируют один из основополагающих принципов "больших" (промышленных) СУБД: средства хранения данных и доступа к ним отделены от средств представления данных; операции над данными производятся в масштабе наборов данных, а не отдельных записей. Разработчики, долгое время использовавшие локальные ("персональные") СУБД, в процессе перехода от Paradox, dBase, Clarion и т.п. к архитектуре "клиент-сервер" обычно при изучении оператора SELECT вынуждены менять устоявшиеся парадигмы мышления: локальные СУБД реализуют в основном навигационный подход доступа к данным (выборка по одной записи) и подразумевают достаточно прочную обратную связь между способами хранения данных, доступа к ним и их представления пользователю в приложении.

Оператор SELECT - средство, которое полностью абстрагировано от вопросов представления данных; все внимание при его применении сконцентрировано на проблемах доступа к данным.

Оператор SELECT имеет следующий формат:

SELECT [DISTINCT | ALL] {* | <значение1> [, <значение2> ...]}

FROM <таблица1> [, < таблица2> ...]

[WHERE <условия_поиска>]

[GROUP BY столбец [COLLATE collation} [,столбец! [COLLATE collation] ...]

[HAVING < условия поиска >]

[UNION <оператор select>]

[PLAN <план выполнения_запроса>]

[ORDER BY <список_столбцов>]

Этот формат с первого взгляда достаточно громоздок и кажется поэтому сложным. Такое впечатление при дальнейшем изучении оператора SELECT наверняка покажется Вам неверным. Поэтапно рассмотрим возможности, которые предоставляет оператор SELECT.

25.1. Простейший вид оператора SELECT

(SELECT ..FROM)

В простейшем случае оператор SELECT имеет вид

SELECT {* | <значение1> [, <значение2> ...]}

FROM <таблица1> [, < таблица2> ...]

После ключевого слова FROM приводится список ТБД, из которых будет происходить выборка данных.

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

Пример. Выдать набор данных, состоящий из всех столбцов и всех записей из таблицы RASHOD (рис. 25.1).

SELECT * FROM RASHOD

что эквивалентно

SELECT N_RASH, DAT_RASH, KOLVO, TOVAR, POKUP FROM RASHOD

25.2. Использование предложения WHERE

С использованием предложения WHERE оператор SELECT имеет следующий формат:

SELECT {* | <значение1> [, <значение2> ...]}

FROM <таблица1> [, < таблица2> ...]

WHERE <условия поиска>

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

Пока разберем два простейших условия поиска.

25.2.1. Сравнение значения столбца с константой

При сравнении значения столбца с константой условие поиска имеет вид

<имя столбца> <оператор> константа

где в качестве оператора могут выступать операции отношения = равно

< меньше

> больше

<= меньше или равно

>= больше или равно

!< не меньше (т.е. больше или равно)

!> не больше (т.е. меньше или равно)

<> не равно

!= не равно

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

Пример. Показать все операции отпуска товаров объемом 20 единиц (результат на рис. 25.2)

SELECT *

FROM RASHOD R

WHERE KOLVO=20

25.2.2. Сравнение значения столбца из одной таблицы со значением столбца из другой таблицы (внутреннее соединение)

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

<имя столбца таблицы 1> <оператор> <имя столбца таблицы 2>

Пример. Выдать все записи о расходе товара из таблицы RASHOD. Для каждого товара выдать его цену из таблицы ТО VARY (результат на рис. 25.3)

SELECT RASHOD.*, TOVARY.ZENA

FROM RASHOD, TOVARY

WHERE RASHOD.TOVAR = TOVARY.TOVAR

При выполнении оператора SELECT для каждой записи из таблицы RASHOD ищется запись в таблице TOVARY, у которой значение в поле TOVAR совпадает со значением в поле TOVAR текущей записи таблицы RASHOD

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

RASHOD. TOVAR = TOVARY. TOVAR идентично условию

TOVARY.TOVAR = RASHOD.TOVAR

Такой способ соединения таблиц называется внутренним соединением

При внутреннем соединении двух таблиц А и В логический порядок формирования результирующего НД можно представить себе следующим образом.

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

2 Из получившегося НД отбрасываются все записи, не удовлетворяющие условию поиска в предложении WHERE

ЗАМЕЧАНИЕ Определение "логический порядок формирования результирующего набора данных" употреблено не случайно В проектировании данных всегда различают два уровня - логический и физический. Логический уровень - это часто достаточно абстрактный уровень; физический уровень определяет действительно протекающие процессы, в большинстве случаев скрытые от взгляда, не лежащие на поверхности.

Поэтому, когда мы говорим о "логическом порядке выполнения запроса", это подразумевает, что так нам легче понимать процессы, происходящие при выполнении внутреннего соединения; на самом же деле физические процессы, реально протекающие на сервере БД при выполнении запроса, могут не совпадать с нашим логическим представлением о них.

SQL-сервер при выполнении запроса всегда стремится его оптимизировать, то есть выполнить с максимальной быстротой при минимально возможных затратах ресурсов. В частности, оптимизация запросов в InterBase представляет собой "черный ящик", то есть нельзя сказать, как именно будет выполняться конкретный запрос, поскольку, помимо прочего, при оптимизации не последнюю роль играет текущее состояние БД. Подобные вопросы рассматриваются ниже в разделе, посвященном оптимизации запросов.

Пример. Пусть имеются таблицы А и В. Тогда выполнение оператора

SELECT А.P1, A.P2, В.Р2

FROM А, В

WHERE A.P2 = В.P1

с логической точки зрения приведет к формированию такого декартова произведения таблиц А (столбцы А Р1 и А Р2) и В (столбцы В.Р1 и В.Р2)

Примечание. Столбец В.Р1, которого нет в результирующем запросе, показан для наглядности.

Затем путем исключения из декартова произведения записей, не удовлетворяющих условию "A.P2 = В.Р1", будет получен такой результирующий НД:

Пример. Выдать все записи о расходе товара из таблицы RASHOD Для каждого покупателя выдать его адрес из таблицы POKUPATELI (результат на рис 25 4)

SELECT RASHOD.*, POKUPATELI.ADRES

FROM RASHOD, POKUPATELI

WHERE POKUPATELI.POKUP = RASHOD.POKUP

Рис 25.4 Как можно видеть, в результирующий НД не включены:

1. записи из таблицы RASHOD с пустым наименованием покупателя (записи с пустым наименованием покупателя в таблице POKUPATELI нет);

2. запись из таблицы POKUPATELI (POKUP = "Геракл"), поскольку по данному покупателю нет записей в таблице RASHOD.

Пример. Используя оператор SELECT из предыдущего примера, выдать декартово произведение по всем столбцам таблицы RASHOD и по столбцу ADRES из таблицы POKUPATELI. Для этого нужно удалить из оператора SELECT предложение WHERE. Результат выполнения запроса не приводим из-за его величины (8 * 4 = 32 записи).

SELECT RASHOD.*, POKUPATELI.ADRES

FROM RASHOD, POKUPATELI

25.3. Использование псевдонимов таблиц

В приведенном выше примере оператора SELECT

SELECT RASHOD.*, POKUPATELI.ADRES

FROM RASHOD, POKUPATELI

WHERE POKUPATELI.POKUP = RASHOD.POKUP

в перечне возвращаемых столбцов после слова SELECT и в условии поиска после слова WHERE перед именем столбца через точку пишется название таблицы:

WHERE POKUPATELI.POKUP = RASHOD.POKUP

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

Использование общих имен таблиц для идентификации столбцов неудобно из-за своей громоздкости. Намного лучше присвоить каждой таблице какое-нибудь краткое обозначение, псевдоним. Такие псевдонимы называются псевдонимами таблиц. Они определяются после имени каждой таблицы в указании списка таблиц-источников после слова FROM:

SELECT

FROM <таблица1 псевдоним1> [, < таблица2 псевдоним2> ...]

WHERE ...

Например, приведенный выше запрос

SELECT RASHOD.*, POKUPATELI.ADRES

FROM RASHOD, POKUPATELI

WHERE POKUPATELI.POKUP = RASHOD.POKUP

после введения в него псевдонимов таблиц выглядит намного компактнее:

SELECT R.*, Р.ADRES

FROM RASHOD R, POKUPATELI P

WHERE P.POKUP = R.POKUP

25.4. Предложение ORDER BY - определение сортировки

Набор данных, выдаваемый в результате выполнения оператора SELECT, в общем случае возвращается в неотсортированном виде. Это удобно далеко не всегда. Определить, по каким полям необходимо отсортировать записи в результирующем НД, можно, указав после предложения, следующего за словом WHERE, предложение

ORDER BY <список_столбцов>

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

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

Пример. Выдать все записи отпуска товара "Кока-кола", отсортировав их по каждому покупателю (результат на рис. 25.5)

SELECT POKUP, DAT_RASH, TOVAR, KOLVO

FROM RASHOD

WHERE TOVAR = "Кока-кола"

ORDER BY POKUP

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

SELECT POKUP, DAT_RASH, TOVAR, KOLVO

FROM RASHOD

ORDER BY POKUP

Пример. Выдать все записи из таблицы RASHOD, отсортировав их по каждому покупателю, для каждого покупателя - по названию товара, для каждого товара - по дате (результат на рис. 25.8)

SELECT POKUP, TOVAR, DAT_RASH, KOLVO

FROM RASHOD

ORDER BY POKUP, TOVAR, DAT_RASH

25.5. Устранение повторяющихся значений

Часто в результирующий НД необходимо включать не все записи с одинаковым значением какого-либо столбца (комбинации столбцов), а только одну из них. В этом случае после ключевого слова SELECT указывают ключевое слово DISTINCT

SELECT [DISTINCT | ALL] {* <значение1> [, <значение2> ...]}

FROM <таблица1> [, < таблица2> ...]

Повторяющимися считаются записи, содержащие идентичные значения во всех столбцах результирующего НД+.

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

Пример. Выдать наименования всех отпущенных со склада товаров (результат на рис. 25.9)

SELECT DISTINCT TOVAR FROM RASHOD

Рис. 25.9.

ЗАМЕЧАНИЕ. Использование в запросе DISTINCT следует ограничивать, кроме случаев, когда это действительно необходимо. Так, в рассматриваемых ниже примерах для агрегатных функций по таблице RASHOD, часто невозможно обойтись без указания DISTINCT.

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

25.6. Расчет значений результирующих столбцов на основе арифметических выражений

Арифметические выраженияиспользуются для расчета значений вычисляемых столбцов результирующего НД. При их формировании следует придерживаться общих правил формирования арифметических выражений, принятых в алгоритмических языках, например Object Pascal для Delphi. При этом в списке возвращаемых столбцов после слова SELECT вместо имени вычисляемого столбца указывается выражение:

SELECT [DISTINCT ALL] {* | <столбец1> [, <выражение1> ...]} FROM <таблица1> [, < таблица2> ...]

Пример. Выдать все записи об отпуске товаров из таблицы RASHOD, для каждого отпуска товара рассчитать общую стоимость отпущенного товара (результат на рис. 25.10)

SELECT R.*, T.ZENA, R.KOLVO * T.ZENA FROM RASHOD R, TOVARY T WHERE R.TOVAR == T.TOVAR

Puc.25.10

Как видно из рисунка, результат вычисления выражения R.KOLVO * T.ZENA для каждой записи из таблицы RASHOD записан в сгенерированный столбец, которому по умолчанию присвоено имя COLUMN7. В случае, если нужно присвоить имя столбцу, содержащему результаты вычисления выражения, это имя можно указать после выражения вслед за ключевым словом AS:

SELECT ... {* | <значение1> [, <выражение1 [AS <имя столбца>]> ...]}

Пример. Выдаваемому в предыдущем примере вычисляемому столбцу присвоить имя STOIM (рис. 25.11)

SELECT R.*, T.ZENA, R.KOLVO * T.ZENA AS STOIM FROM RASHOD R, TOVARY T

WHERE R.TOVAR = T.TOVAR

Рис. 25 11.

25.7. Агрегатные функции

Агрегатные функции предназначены для выдачи итоговых значений. К агрегатным относятся функции:

COUNT (<выражение>) - подсчитывает число вхождений значения выражения во все записи результирующего НД;

• SUM(<выражение>) - суммирует значения выражения;

AVG (<выражение>) - находит среднее значение выражения;

• МАХ(<выражение>) - определяет максимальное значение выражения;

• МIN(<выражение>) - определяет минимальное значение выражения. Если из группы одинаковых записей нужно учитывать только одну, перед выражением в скобках включают слово DISTINCT

COUNT(DISTINCT POKUP)

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

SELECT COUNT(DISTINCT POKUP) AS COUNT_POKUP FROM RASHOD

Пример. Вычислить общую стоимость отпущенных товаров за 10.01.97 (результат на рис. 25.13)

SELECT SUM(R.KOLVO * T.ZENA) AS OBS_ZENA

FROM RASHOD R, TOVARY T

WHERE (R.TOVAR = T.TOVAR) AND

(R.DAT RASH = "10-JAN-1997")

25.8. Использование группировок записей

Часто нужно выдать агрегированные значения (минимум, максимум, среднее) не по всему результирующему НД, а по каждой из входящих в него групп записей, характеризующихся одинаковым значением какого-либо столбца. Например, выдать общее число отпущенного товара по каждому товару. В этом случае в оператор SELECT перед предложением WHERE вводят предложение

GROUP BY столбец [,столбец1 ...]

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

Пример. Выдать общее количество отпуска по каждому из товаров (результат на рис. 25.14)

SELECT R.TOVAR, SUM(R.KOLVO) AS OTPUSK FROM RASHOD R GROUP BY R.TOVAR

Пример. Выдать общую сумму отпуска по каждому из товаров (результат на рис. 25.15)

SELECT R.TOVAR, SUM(R.KOLVO * T.ZENA) FROM RASHOD R, TOVARY T

WHERE T.TOVAR = R.TOVAR GROUP BY R.TOVAR

Пример. Выдать общую сумму отпуска по каждому из товаров на каждую дату (результат на рис. 25.16)

SELECT R.TOVAR, R.DAT_RASH, SUM(R.KOLVO * T.ZENA)

FROM RASHOD R, TOVARY T

WHERE T.TOVAR = R.TOVAR GROUP BY R.TOVAR, R.DAT_RASH

Пример. Выдать число покупателей на каждую дату (результат на рис. 25.17)

SELECT DAT_RASH, COUNT(DISTINCT POKUP)

FROM RASHOD GROUP BY DAT RASH

25.9. Предложение HAVING - наложение ограничений на группировку записей

Если нужно в результирующем НД выдавать агрегацию не по всем группам, а только по тем из них, которые отвечают некоторому условию, после предложения GROUP BY указывают предложение

HAVING < условия_поиска >

где условия поиска указываются по тем же правилам, что и условия поиска для предложения WHERE, за важным исключением: в условии поиска предложения HAVING можно указывать агрегатные функции, чего нельзя делать в условии поиска для WHERE.

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

SELECT POKUP, MIN(KOLVO) FROM RASHOD

GROUP BY POKUP HAVING MIN(KOLVO) >= 100

Если не указывать

HAVING MIN(KOLVO) >= 100

будут выданы все группы (рис. 25.19).

Можно указывать различные агрегатные функции для возвращаемого столбца и условия в HAVING.

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

SELECT POKUP, SUM(KOLVO) FROM RASHOD GROUP BY POKUP HAVING MIN(KOLVO) >= 100

ЗАМЕЧАНИЕ. Следует всегда помнить, чем условие в HAVING отличается от условия в WHERE:

• HAVING исключает из результирующего НД группы с результатами агрегированных значений;

• WHERE исключает из расчета агрегатных значений по группировкам записи, не удовлетворяющие условию;

• в условии поиска WHERE нельзя указывать агрегатные функции.

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

SELECT DAT_RASH,COUNT(*) FROM RASHOD

WHERE KOLVO >= 1000 GROUP BY DAT RASH

Пример. Выдать даты отпусков товаров, в которых количество отпускаемого товара больше или равно 1000 единиц. В результирующий НД включить только те группы, по которым число таких отпусков товаров больше 1 (результат на рис. 25.22).

SELECT DAT_RASH,COUNT(*) FROM RASHOD

WHERE KOLVO >= 1000 GROUP BY DAT_RASH HAVING COUNT(*) > 1

25.10. Предложение WHERE : задание сложных условий поиска

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

25.10.1. Использование логических выражений

Может указываться более одного условия поиска. В этом случае они объединяются между собой при помощи логических операторов AND, OR и NOT. Их использование, а также построение из них сложных выражений подчиняется стандартным правилам, принятым для большинства алгоритмических языков (например, Object Pascal для Delphi) с одним важным исключением: операции отношения в них имеют меньший приоритет, чем логические операции, что избавляет от необходимости расстановки многочисленных скобок в сложных условиях поиска (я не работал с InterBase, но в диалекте SQL для TQuery и для MS SQL-сервер это так. Либо удалить это замечание, либо исправить примеры ниже по тексту).

Пример. Выдать все записи из таблицы RASHOD, для каждого товара выдать его цену из таблицы TOVARY, для каждого покупателя выдать его город из таблицы POKUPATELI (результат на рис. 25.23).

SELECT R.*, T.ZENA, P.ADRES FROM RASHOD R, TOVARY T, POKUPATELI P

WHERE (R.TOVAR = T.TOVAR) AND (R.POKUP = P.POKUP)

Рис. 25.23.

Пример. Выдать записи из таблицы RASHOD плюс соответствующую каждому товару цену из таблицы TOVARY. При этом количество отпуска товара должно быть не больше 30 или должно быть не меньше 3000, и название покупателя должно присутствовать (результат на рис. 25.24).

SELECT R.*, T.ZENA FROM RASHOD R, TOVARY T

WHERE (R.TOVAR = T.TOVAR) AND ((R.KOLVO <=30) OR (R.KOLVO >= 3000)) AND (R.POKUP IS NOT NULL)

ORDER BY R.KOLVO

Puc. 25.24.

25.10.2. Сравнение столбца с результатом вычисления выражения

Условие поиска в предложении WHERE может быть сформулировано при помощи выражения:

<выражение> <оператор> <столбец>

Может использоваться и другой способ написания условия поиска, <столбец> <оператор> <выражение>

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

Пример. Выдать из таблицы RASHOD дату, товар, стоимость отпущенного товара. При этом показывать только записи, у которых стоимость отпущенного товара больше 120 (результат на рис. 25.25).

SELECT R.DAT_RASH, R.TOVAR, (R.KOLVO * T.ZENA) AS STOIM FROM RASHOD R, TOVARY T

WHERE (R.TOVAR = T.TOVAR) AND ((R.KOLVO * T.ZENA) > 120)

ORDER BY R.DAT_RASH

25.10.3. Использование BETWEEN

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

<значение> [NOT] BETWEEN <значение1> AND <значение2>

Зарезервированное слово NOT инвертирует условие (значение не должно находиться в интервале между значением! и значением 2).

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

SELECT * FROM RASHOD WHERE KOLVO BETWEEN 1000 AND 3000

IN.RASH

DAT_RAS

[KOLVO

tovar

KUP

10.01.97

3000

Ставрида консерв.

Адмирал, АО

8

120.01.97

1000

Кока-кола

Адмирал.АО

25.10.4. Использование IN (список значений)

Если нужно, чтобы значение какого-либо столбца (или результат вычисления некоторого выражения) совпадало с одним из дискретных значений, в условии поиска указывается предложение

<значение> [NOT] IN (<значеиие1> 1, <значение2> ...1)

Тогда в результирующий набор данных будут включены только те записи, для которых значение, стоящее слева от слова IN, равно одному из значений, указанных в списке (<значение1> [, <значение2>...]).

Пример. Выдать сведения обо всех отпусках товара, где количество отпущенного товара (в единицах) равно или 100, или 1000, или 3000 (результат на рис. 25.27).

SELECT * FROM RASHOD WHERE KOLVO IN (100, 1000, 3000)

N_RAS'

DAT_RAS

KOL

TOVAR

POKUP

4

10.01.97

3000

Ставрида консерв.

:Аамирал.АО ;

8

,20.01.97

1000

Кока-кола

Адмирал АО

1

10.01.97

100

Кока-кола

Адмирал, АО

Рис. 25.27.

ЗАМЕЧАНИЕ. Существует вторая форма использования IN, где список возможных значений возвращается вложенным подзапросом. Этот вариант рассматривается в подразделе, посвященном подзапросам.

25.10.5. Использование STARTING

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

<значение> (NOT) STARTING [WITH] <подстрока>

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

Пример. Выдать все товары, начинающиеся с буквы "С" (результат на рис.25.28).

SELECT * FROM TOVARY WHERE TOVAR STARTING WITH "C"

25.10.6. Использование CONTAINING

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

<значение> [NOT] CONTAINING <значение>

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

Пример. Выдать список всех покупателей, чей адрес содержит подстроку "Стр" (результат на рис. 25.29)

SELECT * FROM POKUPATELI WHERE ADRES CONTAINING "Стр"

25.10.7. Использование функции UPPER

Функция UPPER(<значение>) используется для преобразования букв символьных значений (содержимого столбца, результата вычисления выражения) к заглавным. Обычно эта функция используется в условиях поиска, когда необходимо игнорировать возможную разницу в высоте букв.Функция UPPER может фигурировать как в списке столбцов результирующего набора данных (после слова SELECT), так и в условии поиска в предложении WHERE.

Пример. Пусть нам необходимо найти всех покупателей из Москвы. Однако в таблице POKUPATELI два покупателя имеют в столбце GOROD имя города Москвы, однако в одном случае это значение 'Москва', в другом 'МОСКВА'. Если попытаться выполнить следующий запрос, то будет выдан только один покупатель (рис. 25.30). То есть результирующий НД будет неполным:

SELECT * FROM POKUPATELI WHERE GOROD = 'Москва'

Проблема решается приведением обеих составляющих условия поиска к одному виду (рис. 25.31).

SELECT * FROM POKUPATELI WHERE UPPER(GOROD) = 'МОСКВА'

25.10.8. Использование LIKE

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

<значение> [NOT] LIKE < шаблон> [ESCAPE <подшаблон>]

В шаблоне используются специальные символы - "%" и "_" . Символ "%" (процент) используется для указания любого значения любой длины и символ "_" (подчеркивание) для указания любого единичного символа. Например:

LIKE "%USD" - указывает, что сравниваемое значение должно оканчиваться символами 'USD' (Надо раз и навсегда решить, какими символами выделять строки. Обычно в тексте книги используются типографские или двойные кавычки, а в примерах - по требованию синтаксиса - апострофы. Проверить и исправить дальше по тексту), независимо от того, какие символы и сколько расположены перед ними;

LIKE "_94" - указывает, что сравниваемое значение может содержать 4 символа, из которых первые два - любые и последние два - '94'.

ESCAPE <подша6лон> используется, если в предложении LIKE символы '%' или '_' должны использоваться в шаблоне подобия как обычные символы (без учета их специальных функций). В этом случае с помощью ESCAPE указывается символ, появление которого в шаблоне отменяет специальные функции следующего за ним символа WHERE STOLBEZ LIKE "%!%" ESCAPE "!"

Пример. Пусть нужно выдать информацию о покупателе, имя которого мы забыли, и название улицы мы помним неточно - то ли Стромынка, то ли Стормынка, то ли Сторомынка. Точно помним, что название улицы заканчивается на 'мынка'. Тогда нужно выполнить такой запрос (результат на рис. 25.32).

SELECT * FROM POKUPATELI WHERE ADRES LIKE "%мынка%"

При этом шаблон "%мынка%" заканчиваем символом '%' потому, что после названия улицы в адресе идут другие реквизиты, которых, естественно, мы не помним.

25.10.9. Использование функции CAST

Иногда возникает потребность трактовать значение одного типа как значение другого типа. Например, использовать числовое значение как символьную строку или наоборот. В этом случае применяют функцию

CAST (<значение> AS <тип данных>)

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

Пример. Найти покупателя, который делал закупки то ли на 209, то ли на 309 единиц товара. На сколько именно, никто не помнит; вспомнили лишь, что последними разрядами в количестве отпускаемого товара были цифры '09'. Тогда приводим значения столбца KOLVO к типу CHARACTER и к результату применяем LIKE (рис. 25.33).

ЗАМЕЧАНИЕ. Значение типа DATE не нужно приводить к строковому типу (в примере не используется тип DATE! убрать ссылку на пример), поскольку два этих типа являются совместимыми и значение DATE в InterBase может трактоваться как строковое. Например, в приводимом ниже запросе объединяются значения типа DATE и строковое, и результат трактуется как строковое значение (результат на рис. 25.34).

SELECT "Дата расхода: " I I DAT_RASH, POKUP, KOLVO FROM RASHOD WHERE KOLVO > 1000

Нигде до этого не объяснен синтаксис ||

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

• в приложении, разработанном на Delphi, анализировать даты при помощи процедуры DecodeDate;

написать UDF (User Defined Function, определенную пользователем функцию), которая реализует выделение номера дня из даты, и использовать имя этой функции в операторе SELECT;

• привести значение даты к типу CHAR (или, что лучше, трактовать значение даты как строковое значение) и применить к полученному значению LIKE, CONTAINING или STARTING WITH, в зависимости от потребности.

Воспользуемся последним способом (результат на рис. 25.35).

SELECT DAT_RASH, TOVAR, POKUP, KOLVO FROM RASHOD .

WHERE CAST(DAT_RASH AS CHAR(6)) STARTING WITH "20"

или, устранив ненужное, в данном случае, приведение типов,

SELECT DAT_RASH, TOVAR, POKUP, KOLVO FROM RASHOD WHERE DAT_RASH STARTING WITH "20"

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

25.11. Использование подзапросов

Часто невозможно решить поставленную задачу путем использования одного запроса. Это особенно актуально в тех случаях, когда при использовании условия поиска в предложении WHERE

Сравниваемое значение> <оператор> <значение, с которым сравнивать>

значение, с которым надо сравнивать, заранее не определено и должно быть вычислено в момент выполнения оператора SELECT.

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

Внутренний подзапрос представляет собой также оператор SELECT и кодирование его предложений подчиняется тем же правилам, что и для основного оператора SELECT.

В общем случае оператор SELECT с подзапросом имеет вид

SELECT .. .

FROM ...

WHERE Сравниваемое значение> <оператор> SELECT ...

FROM ...

WHERE ...

Пример. Выдать все даты, на которые приходится максимальный отпуск товаров (результат на рис. 25.36).

SELECT KOLVO, DAT_RASH FROM RASHOD

WHERE KOLVO = (SELECT MAX(KOLVO) FROM RASHOD

KOLVO

DAT_RASH

1

10.01.97

Puc. 25.36.

Сначала нужно найти количество максимального отпуска товаров, поскольку это значение неизвестно. Это и делает внутренний подзапрос (SELECT MAX(KOLVO) FROM RASHOD )

Далее выполняется основной запрос, как если бы он был записан так:

SELECT KOLVO, DAT_RASH FROM RASHOD WHERE KOLVO = 4000

Пример. Усложним предыдущий пример. Определить дату, когда со склада было отгружено максимальное количество товара, и реквизиты покупателя, который этот товар купил (результат на рис. 25.37).

SELECT R.KOLVO, R.DAT_RASH, P.POKUP, P.GOROD, P.ADRES

FROM RASHOD R, POKUPATELI P

WHERE (R.POKUP = P.POKUP) AND

KOLVO =(SELECT MAX(KOLVO)

FROM RASHOD

)

По сравнению с предыдущим примером в запрос включено внутреннее соединение таблиц RASHOD и POKUPATELI.

ЗАМЕЧАНИЕ. Распространенной ошибкой является использование вложенного оператора SELECT, который вместо единичного значения способен возвращать список значений.

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

Пример. Найти в таблице POKUPATELI покупателя, у которого поле GOROD содержит "С-Петербург" и выдать все осуществленные им покупки товаров, из таблицы RASHOD. Может быть написан следующий потенциально ошибочный запрос (результат на рис. 25.38).

SELECT R.DAT_RASH, R.TOVAR, R.KOLVO, R.POKUP FROM RASHOD R

WHERE R.POKUP = (SELECT POK.POKUP FROM POKUPATELI РОК

WHERE UPPER(РОК.GOROD) = 'С-ПЕТЕРБУРГ '

)

Хотя для значения "С-Петербург" и был выдан корректный результат, такой запрос потенциально ошибочен, поскольку способен возвращать несколько значений; например, если поменять "С-Петербург" на "Москва", получим уведомление об ошибке (рис. 25.39)

SELECT R.DAT_RASH, R.TOVAR, R.KOLVO, R.POKUP FROM RASHOD R

WHERE R.POKUP = (SELECT POK.POKUP FROM POKUPATELI РОК

WHERE UPPER(РОК.GOROD) = 'МОСКВА' )

Geneial SQL eiroi. multiple rows in singleton select.

Рис. 25.39. "Общая ошибка при выполнении SQL; возвращено множество значений, когда требуется единичное значение ".

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

Поэтому следует придерживаться правила оценивать, какой результат -множественный или единичный - будет в общем случае возвращать подзапрос. (И что делать после оценки? Я бы изменил оператор = на in where r.pokup in select.... и пояснил отсутствие ошибки)

25.12. Вложение подзапросов

Часто невозможно обойтись одним подзапросом. Тогда в подзапросе используют вложенный подзапрос.

Пример. Составить список отгрузки товаров покупателю, который в свое время купил максимальную партию какого-либо товара (результат на рис. 25.40).

SELECT RRR.* FROM RASHOD RRR

WHERE RRR.POKUP IN

(SELECT R.POKUP FROM RASHOD R

WHERE KOLVO = (SELECT MAX(RSH.KOLVO) FROM RASHOD RSH)

)

ЗАМЕЧАНИЕ. IN использован вместо знака равенства на тот случай, если встретится два и более покупателя, имеющие одинаковое число максимальных покупок. В этом случае запрос вернет записи из RASHOD по всем таким покупателям. Использование знака равенства '=' вместо IN способно привести к ошибке при выдаче в качестве результата "среднего" запроса (SELECT R.POKUP...) множества значений вместо требуемого одного.

Логический порядок выполнения запроса. Вычисляется максимальное значение в столбце KOLVO ("самый вложенный" подзапрос SELECT MAX). Далее в "среднем" подзапросе SELECT R.POKUP выбирается покупатель, купивший какой-либо товар в количестве, равном значению, вычисленному в "самом вложенном" подзапросе. Вслед за этим "самый главный" запрос SELECT RRR выбирает записи с покупателем, наименование которого выдано "средним" подзапросом.

ЗАМЕЧАНИЕ. Поставленную задачу могут выполнить и другие запросы,например

SELECT RRR.* FROM RASHOD RRR

WHERE RRR.POKUP IN

(SELECT R.POKUP FROM RASHOD R GROUP BY R.POKUP

HAVING MAX(R.KOLVO) = (SELECT MAX(RSH.KOLVO) FROM RASHOD RSH)

)

25.13. Дополнительные возможности использования подзапросов, возвращающих единичное значение

25.13.1. Использование EXISTS

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

Пример. Выдать список всех покупателей, которые получали товар со склада (результат на рис. 25.41).

SELECT P.POKUP FROM POKUPATELI P

WHERE EXISTS (SELECT R.POKUP FROM RASHOD R WHERE R.POKUP = P.POKUP)

25.13.2. Использование SINGULAR

Если в условии поиска нужно указать, что из таблицы требуется выбрать лишь те записи, для которых подзапрос возвращает только одно значение, указывается предложение

SINGULAR (<onepaTOp_select >)

Пример. Выдать список всех покупателей, купивших только один товар (результат на рис. 25.42).

SELECT P.* FROM POKUPATELI P

WHERE SINGULAR (SELECT * FROM RASHOD R WHERE R.POKUP = P.POKUP)

POKUP

GOROD

ADRES

ЛИРА ТОО

МОСКВА

пр. Стромыкина 21

Рис. 25.42

25.14. Использование подзапросов, возвращающих множество значений

25.14.1. Использование ALL, SOME

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

<Сравниваемое значение> {[NOT] {ALL | SOME | ANY} (<подзапрос>)

где подзапрос может возвращать более одного значения. Оператор определяет операцию сравнения (>, >=, < и т.д.). Отношение сравниваемого значения и значений, возвращаемых подзапросом, устанавливается словами ALL и SOME (ANY).

ALL определяет, что условие поиска истинно, когда сравниваемое значение находится в отношении, определяемом оператором, со всеми значениями, возвращаемыми подзапросом. Например:

WHERE STOLBEZ > ALL (SELECT POLE FROM TABLIZA)

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

SOME (вместо него можно указать ANY) что условие поиска истинно, когда сравниваемое значение находится в отношении, определяемом оператором, хотя бы с одним значением, возвращаемым подзапросом. Например: WHERE STOLBEZ > SOME (SELECT POLE FROM TABLIZA)

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

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

SELECT * FROM RASHOD R1

WHERE R1.KOLVO > ALL (SELECT AVG(R2.KOLVO) FROM RASHOD R2 GROUP BY POKUP)

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

SELECT * FROM RASHOD R1

WHERE Rl.KOLVO > SOME (SELECT AVG(R2.KOLVO) FROM RASHOD R2 GROUP BY POKUP )

25.14.2. Использование HAVING и агрегатных функций для вложенных подзапросов

Если в условиях поиска для вложенного запроса нужно указать агрегатную функцию, используется HAVING..

Пример. Определить покупателя, у которого средняя покупка больше средней покупки других покупателей, и среднее число покупки этого покупателя (результат на рис. 25.45).

SELECT R1.POKUP, AVG(Rl.KOLVO) FROM RASHOD R1

GROUP BY R1.POKUP HAVING AVG(R1.KOLVO) >= ALL

(SELECT AVG(R2.KOLVO) FROM RASHOD R2 GROUP BY R2 . POKUP )

Пример. Определить адрес покупателя, который приобрел наибольшее количество товаров (результат на рис 25.46).

SELECT P.* FROM POKUPATELI P

WHERE P.POKUP =

(SELECT RR.POKUP FROM RASHOD RR

GROUP BY RR.POKUP HAVING SUM(RR.KOLVO) >= ALL

(SELECT SUM(RRR.KOLVO) FROM RASHOD RRR GROUP BY RRR.POKUP)

)

Пример. Перечислить все товары, которые приобрел покупатель, купивший наибольшее количество товаров (результат на рис. 25.47).

SELECT DISTINCT R.TOVAR FROM RASHOD R

WHERE R.POKUP =

(SELECT RR.POKUP FROM RASHOD RR

GROUP BY RR.POKUP HAVING SUM(RR.KOLVO) >= ALL

(SELECT SUM(RRR.KOLVO) FROM RASHOD RRR GROUP BY RRR.POKUP)

)

Пример. Перечислить стоимость единиц товаров, которые приобрел покупатель, купивший наибольшее количество товаров (результат на рис 25.48)

SELECT DISTINCT R.TOVAR, T.ED_IZM, T.ZENA FROM RASHOD R, TOVARY T

WHERE T.TOVAR = R.TOVAR AND R.POKUP = (SELECT RR.POKUP FROM RASHOD RR

GROUP BY RR.POKUP HAVING SUM(RR.KOLVO) >= ALL

(SELECT SUM(RRR.KOLVO) FROM RASHOD RRR GROUP BY RRR.POKUP )

25.15. Внешние соединения

Выше нами были рассмотрены внутренние соединения таблиц базы данных Напомним, что внутренние соединения имеют место, если в предложении WHERE указано условие

<имя столбца таблицы 1> <оператор> <имя столбца таблицы 2>

Например,

SELECT RASHOD.*, TOVARY.ZENA FROM RASHOD, TOVARY

WHERE RASHOD.TOVAR = TOVARY.TOVAR

В этом случае осуществляется декартово произведение таблиц 1 и 2 и из полученного НД отбираются записи, удовлетворяющие условию поиска (RASHOD TOVAR = TOVARY.TOVAR)

Существует также и другой вид соединения таблиц, внешнее соединение. Оно определяется в предложении FROM согласно спецификации SELECT {* | <значение1> [, <значение2> ...1}

FROM <таблица1> <вид соединения> JOIN < таблица2> ON <условие поиска>

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

LEFT - (левое внешнее соединение), когда ведущей является таблица1 (расположенная слева от вида соединения);

RIGHT - (правое внешнее соединение), когда ведущей является таблица1 (расположенная справа от вида соединения);

Пример. Пусть имеем таблицы

A.P1

А.Р2

В.Р2

а

х

1

B

х

1

С

у

2

d

1

Рис 25.49

A.P1

А.Р2

В.Р2

а

х

1

b

х

1

с

у

2

2

Рис 25.50

Таблица А Таблица В

Р1

Р2

РЗ

а

х

400

b

х

200

с

у

500

d

PI

Р2

х

1

у

2

z

2

Тогда выполнение оператора SELECT, реализующего внешнее левое соединение,

SELECT A.P1, А.Р2, В.Р2 FROM A LEFT JOIN В ON А.Р2 = В.Р1

приведет к выдаче результирующего НД (рис 25.49):

Пунктиром показаны столбцы ведущей таблицы А. Как видно, для записи таблицы А, где столбец A.P1 имеет значение 'd', нет парных записей в таблице В, для которых удовлетворялось бы условие поиска А.Р2 = В.Р1. Поэтому данная запись таблицы А показана в соединении с пустой записью.

В то же время, выполнение оператора SELECT, реализующего внешнее правое соединение,

SELECT A.P1, А.Р2, В.Р2 FROM A RIGHT JOIN B ON А.Р2 = В.Р1

приведет к выдаче такого результирующего НД (рис 25.50)

Пунктиром показаны столбцы ведущей таблицы В. Как видно, для записи таблицы В, где столбец В.Р1 имеет значение 'z' и столбец В.Р2 имеет значение '2', нет парных записей в таблице А, для которых удовлетворялось бы условие поиска А.Р2= В.Р1. Поэтому данная запись таблицы В показана в соединении с пустой записью.

Пример. Построить внешнее соединение по таблице RASHOD с таблицей POKUPATELI, т.е. показать покупателя, соответствующего каждому расходу (результат на рис.25.51).

SELECT R.DAT_RASH, R.TOVAR, R.KOLVO, P.POKUP, P.GOROD

FROM RASHOD R LEFT JOIN POKUPATELI P ON R.POKUP = P.POKUP

или

SELECT R.DAT_RASH, R.TOVAR, R.KOLVO, P.POKUP, P.GOROD

FROM POKUPATELI P RIGHT JOIN RASHOD R ON R.POKUP = P.POKUP

DAT_RASH

TOVAR

KOLVO

POKUP

GOROD

10.01.97

Сахар

20

Лира, ТОО

МОСКВА

10.01.97

Сахар

509

10.01.97

Ставрида консерв

3000

Адмирал. АО

С-Петербург

10.01.97

Кока-кола

4000

Саяны. ИЧП

Москва

10.01.97

Сахар

30

Саяны. ИЧП

Москва

20.01.97

Кока-кола

20

20.01.97

Кока-кола

1000

Адмирал, ДО

С-Петербург

10.01.97

Кока-кола

100

Адмирал. ДО

С-Петербург

Рис. 25.51.

Пример. Построить внешнее соединение по таблице POKUPATELI с таблицей RASHOD, т.е. показать все расходы по каждому покупателю (результат на рис.25.52).

SELECT P.POKUP, P.GOROD, R.DAT_RASH, R.TOVAR, R.KOLVO

FROM POKUPATELI P LEFT JOIN RASHOD R ON R.POKUP = P.POKUP

или

SELECT P.POKUP, P.GOROD, R.DAT_RASH, R.TOVAR, R.KOLVO

FROM RASHOD R RIGHT JOIN POKUPATELI P ON R.POKUP = P.POKUP

PQKUP

GOROD

DAT_RASH

TOVAR

KOLVO

Лира ТОО

МОСКВА

10.01.97

Сахар

20

Саяны. ИЧП

Москве

10.01.97

Кока-кола

4000

Саяны, ИЧП

Москва

20.01.97

Сахар

30

Адмирал, АО

С.Петербург

10.6l.97

Ставрида консорв,

3000

Адмирал. АО

С-Петербург

20.01.97

Кока-кола

1000

Адмирал. АО

С-Петербург

10.01.97

Кока-кола

100

Геракл

Уфа

Рис. 25.52.

25.16. UNION - объединение результатов выполнения нескольких операторов SELECT

Иногда бывает полезным объединять два или более результирующих НД, возвращаемых после выполнения двух или более операторов SELECT. Такое объединение производится при помощи оператора UNION. Результирующие НД должны иметь одинаковую структуру, т.е. одинаковый состав возвращаемых столбцов. Если в результирующих НД имеется одна и та же запись, в сводном НД она не дублируется.

Пример. Соединить результаты выполнения трех запросов:

1. (результирующий НД на рис. 25.53).

SELECT R.* FROM RASHOD R

WHERE R.TOVAR CONTAINING 'Ставрида'

2. (результирующий НД на рис. 25.54).

SELECT R.* FROM RASHOD R

WHERE R.KOLVO >= 3000

3. (результирующий НД на рис. 25.55).

SELECT R.* FROM RASHOD R

WHERE R.POKUP = 'Лира, ТОО'

Произведем объединение трех результирующих наборов данных (результат объединений на рис. 25.56).

SELECT R.* FROM RASHOD R WHERE R.TOVAR CONTAINING 'Ставрида'

UNION SELECT R.* FROM RASHOD R WHERE R.KOLVO >= 3000

UNION SELECT R.* FROM RASHOD R WHERE R.POKUP = 'Лира, ТОО'

25.17. Использование IS NULL

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

<значение> IS [NOT] NULL

Пример. Показать все факты отгрузки товаров со склада, для которых не указан покупатель (результат на рис. 25.57).

SELECT * FROM RASHOD WHERE POKUP IS NULL

25.18. Использование операции сцепления строк

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

<строковое выражение1> || <строковое выражение2>

Операцию || можно использовать как после слова SELECT для указания возвращаемых значений, так и в предложении WHERE.

Пример. Выдать в виде единого столбца имена покупателей и названия их городов (результат на рис. 25.58).

SELECT POKUP || ' (' || GOROD || ')' FROM POKUPATELI

COLUMN1

Лира ТОО (МОСКВА)

[Саяны ИЧП (Москва]

[Адмирал АО (С Петербург)

| Геракл (Уфа]

Рис 25.58

25.19. Работа с разными БД в одном запросе

В одном запросе можно использовать таблицы из разных БД. В этом случае имя таблицы указывается в формате ПсевдонимБД:ИмяТаблицы

Под псевдонимом БД понимается псевдоним, определенный в утилите BDE Administrator.

Ниже приведен пример обращения в одном запросе к таблицам БД InterBase (псевдоним ' MONITOR') и Oracle (псевдоним 'DWH'):

SELECT U.* FROM ":MONITOR:NLS " N, ":DWH:OLAP_UPE" U

WHERE U.SC_CODE = N.COD_SCENARIO

ORDER BY U.SC CODE