Система Visual FoxPro поддерживает SQL-Соединения  (Join) стандарта "SQL-92", поэтому вы можете создавать Запросы, в которых соединяются записи из двух или даже нескольких Таблиц в соответствие со значениями ключевых Полей Связывания. Для выборки данных из нескольких Таблиц создаются Запроосы или Представления, в которых используется операция Соединения / Присоединения (Join), построенная на специальных Условиях Соединения (Join Condition), которые контролируют процесс сравнения связываемых Записей данных. Данные условия основываются на Первичных или других индексных Ключах (primary and foreign keys). Специальные соединения Таблиц могут быть основаны на других полях таблиц, отличных от индексных ключей (primary and foreign keys), однако большинство Запросов используют для соединения таблиц именно индексные поля.

Данный раздел содержит следующие параграфы:

Для создания Запросов или Представлений, содержащих операции Соединения таблиц данных, вы можете использовать соответствующие Дизайнеры Запросов или Представлений, а также языковые возможности системы Visual FoxPro. Смотрите, дополнительно, разделы: Закладка Join, Дизайнеры Запросов и Представлений и SELECT - SQL, команда.

Составные части операции Соединения (Join)

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

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

  • Тип Соединения Таблиц или групп Полей таблиц в результирующем наборе Запроса или Представления.

  • Последовательность Соединения.

  • Условия Соединения, построенные на операциях сравнения, таких как: Диапазон (BetWeen), Равенство (=),Больше (>), Меньше (<).

Типы Соединений

В силу того, что технология SQL базируется на математических алгоритмах, каждая таблица данных может быть представлена в виде круга  в диаграмме Венна (Venn diagram). Секция ON оператора SQL SELECT определяет Условие Соединения Таблиц данных, подмножество точек пересечения (перекрытия) рассматриваемых крогов, или соответствующих наборов Записей данных связываемых Таблиц. Например, Внутреннее соединение (Inner Join) представляет собой область пересечения двух кругов, общее подмножество точек. Внешнее Соединение (Outer Join) включает в себя не только общие наборы записей данных внутреннего соединения (общие данные), но и записи, размещенные слева или справа от области Пересечения (общих точек). 

Вы можете расширить или уменьшить  результирующий набор вашего Запроса выбирая требуемый вид Соединения Таблиц. Далее представлены возможные варианты типов Соединения

Тип Join Описание

Inner

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

Внутреннее соединение (Inner join) является наиболее общим случаем Соединений.

Left (outer)

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

Right (outer)

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

Full

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

Точное сопоставление записей в результирующем Наборе Запроса

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

Например, положим, вам требуется выбрать только те Компании, которые имеют Заказы, которые всегда имеют ссылку на соответствующую компанию, которая сделала заказ. В следуюшем примере программного кода выполняется выборка только тех компаний (из таблицы Customer - клиент), для которых имеются заказы, и только те Заказы (из таблицы Orders), для которых указана Компания-заказчик. В примере используется Внутреннее соединение, создающее результирующий набор записей из двух таблиц, в соответствие условию соединения, построенному на ключевом поле Cust_ID.

NoteОбратите внимание

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

  CopyCode imageКопировать Код
CLOSE ALL
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'Data\TestData')
SELECT TAlias1.company, TAlias2.order_ID ;
FROM customer AS TAlias1 ;
INNER JOIN orders AS TAlias2 ;
ON TAlias1.cust_id = TAlias2.cust_id ;
ORDER BY TAlias1.company ASC

Множественные операции Соединений (Joins)

Вы можете определить несколько операций Соединения данных из нескольких исходных Таблиц.

Например, предположим, вам требуется создать Запрос для выборки Компаний, имеющих Заказы, но также требуется знать имя сотрудника компании, который выполнял конкретный Заказ. В представленном программном коде выполняется выборка Компаний, имеющих Заказы (таблица Customer), (таблица Orders), и имена сотрудников выполняющих выбранные Заказы. В примере используется два Внутренних Соединения по соответствующим ключевым полям: Cust_ID и Emp_ID.

NoteОбратите внимание

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

  CopyCode imageКопировать Код
CLOSE ALL
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'Data\TestData')
SELECT TAlias1.company, TAlias2.order_ID, ;
TAlias3.first_name, TAlias3.last_name ;
FROM customer AS TAlias1 ;
INNER JOIN orders AS TAlias2 ;
ON TAlias1.cust_id = TAlias2.cust_id ;
INNER JOIN employee AS TAlias3 ;
ON TAlias2.emp_id = TAlias3.emp_id ;
ORDER BY TAlias1.company ASC

Несогласованные Записи в результирующих наборах Запроса

Если вам требуется включить в результирующих набор Запроса записи данных, не удовлетворяющие условию Соединения, вы можете использовать Левое-внешнее, Правое-внешнее или Полное соединение данных (left outer, right outer, or full join). Когда вы используете перечисленные виды соединений, то отсутствующие поля Записей принимают значения = NULL.

Например, предположим, требуется создать Запрос по выборке всек клиентов (Компаний), независимо от того имеют ли данные компании Заказы, и Заказы, номеры которых известны для компаний. В следующем примере используется Левое-внешнее соединение (left outer join) для выборки всех записей из одной таблицы и только, соответствующих условию соединения, записей из другой таблицы.

NoteОбратите внимание

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

В данном примере выполняется выборка из тестовой базы данных Visual FoxPro: TestData.dbc, в результирующий набор Запроса включаются все записи из таблицы Customer и только соответствующие записи из таблицы Orders. Тем не менее, не все записи из таблицы Customer имеют соответствующие записи из таблицы Orders.

NoteОбратите внимание

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

  CopyCode imageКопировать Код
CLOSE ALL
CLOSE DATABASES

OPEN DATABASE (HOME(2) + 'Data\TestData')

SELECT TAlias1.company, TAlias2.order_id ;

   FROM customer TAlias1 ;

   LEFT JOIN orders TAlias2 ;

      ON TAlias1.cust_id = TAlias2.cust_id

В результирующем наборе Запроса присутствуют Имена всех имеющихся компаний, в поле Order_ID выгружаются номера соответствующих Заказов. Для клиента с именем "Wenna Wines" данное поле содержит значение = nul, значит Заказы - отсутситвуют.

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

Последовательность Соединений

Когда вы выполняете выборку данных из нескольких таблиц, результирующий набор Запроса зависит от типа выбранного Соединения и от последовательности Таблиц, которые участвуют в данном соединении. Порядок соединяемых таблиц указывается с помощью соответствующего инструментария в Дизайнерах Запросов или Представлений или с помощью соответствующей конструкции JOIN оператора выборки SQL SELECT.

Например, предположим, вам требуется выбрать все записи из одной таблицы и только соответствующие условию Соединения записи из другой таблицы. Вы можете использовать конструкцию LEFT JOIN, в которой Слева размещается первая таблица, а вторая таблица размещена Справа от ключевого слова JOIN. Тем не менее, если вы используете тип соединения RIGHT JOIN, вам необходимо поменять местами имена-алиасы исходных таблиц, чтобы получить аналогичные результаты в результирующем наборе Запроса.

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

NoteПримечание

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

  CopyCode imageКопировать Код
CLOSE ALL
CLOSE DATABASES

OPEN DATABASE (HOME(2) + 'Data\TestData')

Для начала, рассматривается оператор SQL SELECT, в котором выполняется выборка всех имен Компаний из соответствующей таблицы Клиенты и только соответствующие условию соединения записи из таблицы Заказы, соединение по полю идентификатора Клиента Cust_ID.

SELECT TAlias1.company, TAlias2.order_id ;

   FROM customer TAlias1 ;

   LEFT JOIN orders TAlias2 ;

      ON TAlias1.cust_id = TAlias2.cust_id

Далее, выполняется оператор SQL SELECT, в котором ключевая конструкция LEFT JOIN заменяется на следующую RIGHT JOIN, последовательность соединения таблиц не изменяется. Однако, получается совсем другой результирующий набор Запроса. Выполняется выборка всех записей из таблицы Заказов, но не для всех заказов имеются соответствующие компании. Только для тех компаний, для которых имеются заказы - выполняется соответствующая выборка (область пересечения).

SELECT TAlias1.company, TAlias2.order_id ;

   FROM customer TAlias1 ;

   RIGHT JOIN orders TAlias2 ;

      ON TAlias1.cust_id = TAlias2.cust_id

Третий вариант, выполняется оператор SQL SELECT, в котором остается конструкция RIGHT JOIN, а последовательность указания исходных таблиц - меняется: первая становится второй, вторая - первой. Результирующий набор Запроса соответствует перврму варианту оператора SQL SELECT.

SELECT TAlias1.company, TAlias2.order_id ;

   FROM orders TAlias2 ;

   RIGHT JOIN customer TAlias1 ;

      ON TAlias1.cust_id = TAlias2.cust_id

Смотрите дополнительные разделы: Закладка Join, Дизайнеры Запросов и Представлений и SELECT - SQL, команда.

Условия Соединения

Условие Соединения (Join conditions) определяет логическое условие, с помощью которого в операторе SQL SELECT выполняется операция соединения Таблиц данных. Например, вы можете использовать Условия Соединения для сравнения значений соответствующих полей из разных таблиц, что, в свою очередь, определяет условие выборки данных записей в результирующий набор Запроса.

NoteПримечание

Если в вашем Запросе соединяются несколько таблиц, вы должны определить Условие Соединения для каждой присоединяемой таблицы, кроме первой.

Вы можете создавать различные Условия Соединения исходных таблиц при выполнении Запросов или Представлений, которые определяют результирующий набор запроса, как обычные выражения Фильтра (условные выражения). Однако, в Условиях Соединения сравниваются значения Полей из разных таблиц, а в выражениях Фильтра сравнивается значение поля из таблицы и некоторое выражение Фильтра. Смотрите дополнительную информацию в разделе: Условие Фильтра для Запросов и Представлений.

Например,  вы можете использовать операнд равенства (=) для определения условия соединения двух таблиц по некоторому идентификатору, к примеру: Customer.cust_id = Orders.cust_id. В этом случае в результирующий набор запроса включаются соответствующие условию соединения записи из исходных таблиц и удовлетврояющие дополнительному условию Фильтра. Для другого примера, если вы используете для условия соединения поле типа date, вы можете использовать другой оператор сравнения, для вкдючения в результирующий набор записей с меньшей или большей датой (по выбранному полю связывания).

В следующей таблице представлены операнды сравнения, допустимые в Условиях Соединения:

Операнд Описание

=

Equal (равенство)

==

Exactly equal (полное равенство)

LIKE

Операция "по-шаблону" SQL LIKE

<>, !=, #

Not equal (не равно)

>

Greater than (Больше, чем)

>=

Greater than or equal to (больше-или-равно)

<

Less than (Меньше чем)

<=

Less than or equal to (меньше-или-равно)

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

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

В рассматриваемом далее примере выполняется выборка всех имен компаний из таблицы Клиенты и только соответствующих условию соединения записей из таблицы Заказы. Однако, из второй таблицы выбираются только те записи , для которых выполняется условие Order_date < {^1994-02-16}. Если Компания не имеет заказов в указанный интервал времени, то соответствующие номера заказов будут иметь значения = NULL.

NoteПримечание

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

  CopyCode imageКопировать Код
CLOSE ALL
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'Data\TestData')
SELECT TAlias1.company, TAlias2.order_date, TAlias2.shipped_on ;
FROM customer TAlias1 ;
LEFT JOIN orders TAlias2 ;
ON TAlias1.cust_id = TAlias2.cust_id ;
AND TAlias2.order_date < {^1994-02-16}

Дополнительная информация об Условиях Соединения таблиц данных имеется в следующих разделах: SELECT - SQL, команда и Закладка Join, Дизайнеры Запросов и Представлений.

Условие Соединения в ключевой секции WHERE

При создании оператора SQL SELECT, вы модете определять условие соединения таблиц в секции WHERE, вместе с условиями Фильтра. При определении условия Фильтра для Запросов или Представлений в соответствующем Дизайнере данное условие определяется в секции WHERE основного оператора SQL SELECT рассматриваемого Запроса или Представления. Вы можете определить здесь и условие Соединения таблиц, прикрепляя соответствующее логическое выражение в закладке Filter, секция WHERE, или при просмотре полной синтаксической конструкции соответствующего оператора SQL SELECT. Для удаленных Представлений условие соединения всегда размещается в секции WHERE. Это объясняется вопросами совместимости различных вариантов языка SQL.

Например, предположим, требуется выборка Заказов Клиента, содержащая всю информацию о Клиенте и Служащем, который выполнял соответствующий Заказ. В следующем программном коде используется секция WHERE для определения Условия Соединения таблиц Customer и Orders, и , дополнительно, условие соединения с таблицей Employee, по ключевому полю Emp_ID, для таблиц Orders и Employee.

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

  CopyCode imageКопировать Код
CLOSE ALL
CLOSE DATABASES
OPEN DATABASE (HOME(2) + 'Data\TestData')
SELECT * FROM customer TAlias1, orders TAlias2, employee TAlias3 ;
WHERE TAlias1.cust_id = TAlias2.cust_id ;
AND TAlias2.emp_id = TAlias3.emp_id

Дополнительную информацию об использовании секции WHERE смотрите в разделах: Закладка Filter, Дизайнеры Запросов и Представлений и  SELECT - SQL, команда.

Общие рекомендации по использованию Соединений (Join)

При использовании операций Соединения таблиц данных необходимо учитывать следующие аспекты их использования:

  • Если вы выполняете выборку из двух таблиц, и не используете Условие Соединения (join condition), для каждой записи из первой таблицыe выполняется поиск соответствующей записи из второй таблицы также долго, как выполняется Условие фильтрации данных, оно может быть не оптимизируемо. Такие Запросы могут выполняться длительное время.

  • Осмотрительно используйте следующие функции: DELETED( ), EOF( ), FOUND( ), RECCOUNT( )RECNO( ), которые поддерживают дополнительный параметр - алиас или номер рабочей области, в которой открыта таблица данных. Использование указанного параметра может привести к неожиданным результатам. Операторы SQL SELECT не используют имена пользовательских рабочих областей, в которых открываются таблицы; они используют конструкции, тип USE ... AGAIN. Запросы, выполняющие выборку из одной таблицы и использующие указанные функции, возвращают соответствующие результаты. Однако, Запросы, выполняющие выборку из нескольких таблиц, и использующие указанные функции, даже без указания рабочих областей, могут возвращать неожиданные результаты.

  • Осмотрительно используйте операции объединения, основанные на ключевых полях, имеющих пустые значения, так как система  Visual FoxPro выполняет правильные сравнения с пустыми полями. Например, предположим, выполняется соединение таблиц по соответствующим полям Customer.zip и Invoice.zip, соответствующих таблиц Customer и Invoice, из тестовой базы данных TestData.dbc. Если таблица Customer содержит 100 пустых полей Zip, а таблица Invoice содержит 400 пустых полей Zip, то в результирующем наборе запроса будет 40,000 объединенных записей с соответствующими пустыми полями. Для исключения пустых значений из результирующего набора - используйте функцию EMPTY( ).

См. также