Оператор
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 имеет вид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, В.Р2FROM
А, В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
Использование псевдонимов таблицВ приведенном выше примере оператора
SELECTSELECT 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.*,
Р.ADRESFROM RASHOD R, POKUPATELI P
WHERE P.POKUP = R.POKUP
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 указывают ключевое слово DISTINCTSELECT [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.Агрегатные функции предназначены для выдачи итоговых значений. К агрегатным относятся функции:
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
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
Предложение 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
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 |
KUP |
|
10.01.97 |
3000 |
Ставрида консерв. |
Адмирал, АО |
|
8 |
120.01.97 |
1000 |
Кока-кола |
Адмирал.АО |
Если нужно, чтобы значение какого-либо столбца (или результат вычисления некоторого выражения) совпадало с одним из дискретных значений, в условии поиска указывается предложение
<значение> [
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, где список возможных значений возвращается вложенным подзапросом. Этот вариант рассматривается в подразделе, посвященном подзапросам. STARTING Если в условии поиска нужно, чтобы значение какого-либо символьного столбца или выражения начиналось с определенной подстроки, в условии поиска необходимо указать предложение<
значение> (NOT) STARTING [WITH] <подстрока>Тогда в результирующий запрос будут включены только те строки, для которых выполняется указанное условие.
Пример. Выдать все товары, начинающиеся с буквы "С" (результат на рис.
25.28).SELECT * FROM TOVARY WHERE TOVAR STARTING WITH "C"
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) = '
МОСКВА' 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.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)
)
Дополнительные возможности использования подзапросов, возвращающих единичное значение EXISTSБывают случаи, когда в условии поиска нужно указать, что из таблицы требуется отобрать только те записи, для которых подзапрос возвращает одно или более значений. В этом случае в условии поиска указывается предложение
EXISTS (<подзапрос>) Пример. Выдать список всех покупателей, которые получали товар со склада (результат на рис. 25.41).SELECT P.POKUP FROM POKUPATELI P
WHERE EXISTS (SELECT R.POKUP FROM RASHOD R WHERE R.POKUP = P.POKUP)
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. Использование подзапросов, возвращающих множество значений
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 )
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 )
Выше нами были рассмотрены внутренние соединения таблиц базы данных Напомним, что внутренние соединения имеют место, если в предложении 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.
- объединение результатов выполнения нескольких операторов 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