Новости
Документация
Download
Webboard
Поиск
FAQ/ЧаВо
Обратная связь




MySQL.RU - Webboard



Вернуться
JOIN (Дима) 26/12/2001 - 10:26:20
      Re: JOIN (Константин) 26/12/2001 - 11:40:15
      Re: Товарищи, всё есть (Василий) 26/12/2001 - 14:18:27
      Re: Товарищи, всё есть (Дима) 26/12/2001 - 14:53:48
      Re: JOIN (Василий) 26/12/2001 - 19:56:03
      Re: JOIN (Константин) 27/12/2001 - 11:55:08
      Re: OLAP & mysql (Дима) 27/12/2001 - 12:39:47
      Re: OLAP & mysql (Василий) 27/12/2001 - 13:23:16
      Re: JOIN (Константин) 28/12/2001 - 06:46:55
      Re: JOIN (Василий) 28/12/2001 - 10:30:55

> Original message text:
> From: Дима - 26/12/2001 - 10:26:20
> Subject:JOIN
> -----------------
> Где можно в инете поподробней почитать о всяких (LEFT|RIGHT|..) JOIN ?
>


From: Василий - 26/12/2001 - 19:56:03
Subject:JOIN
-----------------
SQL в массы.

На самом деле, предмет прост (тем не менее, это все описано as is, как я сам понимаю вопрос, гарантий я давать не буду. сами проверьте). Но ввиду того, что мне не ясно, каков уровень, хм, аудитории, я начну с начала.


Как следует из перевода слова, join объединяет две и более таблиц по нескольким полям.

Что это значит.

На примерах.

create table parents(id int not null, name varchar(20), family varchar(20), primary key (id));

insert into parents(id, name, family) values (1, 'Unknown', 'Dima');

insert into parents(id, name, family) values (2, 'Unknown', 'Konstantin');

insert into parents(id, name, family) values (3, 'Unknown', 'Vasiliy');


create table children(child_id int not null, parent_id int, name varchar(20), primary key (child_id), unique(parent_id, name));

insert into children(child_id, parent_id, name) values (1,1,'Masha');
insert into children(child_id, parent_id, name) values (2,1,'Lena');
insert into children(child_id, parent_id, name) values (3,2,'Natasha');

Таким образом, у Димы две прелестных дочурки - Маша и Лена, у Константина - Наташенька, у меня (Василия) детей нет.
Между родителями и детьми смоделированы возможные отношения - 1:N (N>1) - Дима, 1:1 - Константин, 1:0 - Василий.
Конечно, могут быть и дети без родителей. Но от этого мы пока отвлечемся.

1.

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

select * from parents, children;

+----+---------+------------+----------+-----------+---------+
| id | name | family | child_id | parent_id | name |
+----+---------+------------+----------+-----------+---------+
| 1 | Unknown | Dima | 1 | 1 | Masha |
| 2 | Unknown | Konstantin | 1 | 1 | Masha |
| 3 | Unknown | Vasiliy | 1 | 1 | Masha |
| 1 | Unknown | Dima | 2 | 1 | Lena |
| 2 | Unknown | Konstantin | 2 | 1 | Lena |
| 3 | Unknown | Vasiliy | 2 | 1 | Lena |
| 1 | Unknown | Dima | 3 | 2 | Natasha |
| 2 | Unknown | Konstantin | 3 | 2 | Natasha |
| 3 | Unknown | Vasiliy | 3 | 2 | Natasha |
+----+---------+------------+----------+-----------+---------+

заметим сразу, что синонимом этого запроса будет
select * from parents join children;
select * from parents cross join children;
select * from parents straight_join children;

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

2.

первое, что хочется, это объединить родителей со СВОИМИ детьми. Очень просто.

select * from parents, children where parents.id = children.parent_id;

+----+---------+------------+----------+-----------+---------+
| id | name | family | child_id | parent_id | name |
+----+---------+------------+----------+-----------+---------+
| 1 | Unknown | Dima | 1 | 1 | Masha |
| 1 | Unknown | Dima | 2 | 1 | Lena |
| 2 | Unknown | Konstantin | 3 | 2 | Natasha |
+----+---------+------------+----------+-----------+---------+

Что произошло. Из всевозможных пар, которые дает декартово объединение, оставлены только те, у которых идентификатор родителя в таблицах parents и children одинаковы.

синонимы :
если ко всем перчисленным ранее синонимам приписать условие where, полуим то же самое.
но есть ещё один синоним :

select * from parents inner join children on parents.id = children.parent_id;

3.

Дальше - как насчет родителей, у которых нет детей? Они выпадают из результата пункта 2.
Есть и на этот случай специальное объединение.

select * from parents left join children on parents.id = children.parent_id;

+----+---------+------------+----------+-----------+---------+
| id | name | family | child_id | parent_id | name |
+----+---------+------------+----------+-----------+---------+
| 1 | Unknown | Dima | 1 | 1 | Masha |
| 1 | Unknown | Dima | 2 | 1 | Lena |
| 2 | Unknown | Konstantin | 3 | 2 | Natasha |
| 3 | Unknown | Vasiliy | NULL | NULL | NULL |
+----+---------+------------+----------+-----------+---------+

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

синонимы :

select * from parents left outer join children on parents.id = children.parent_id;

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

select * from parents left join children on parents.id = children.parent_id where children.parent_id is null;

+----+---------+---------+----------+-----------+------+
| id | name | family | child_id | parent_id | name |
+----+---------+---------+----------+-----------+------+
| 3 | Unknown | Vasiliy | NULL | NULL | NULL |
+----+---------+---------+----------+-----------+------+

4.

Все, что в этом пункте, MySQL не подерживает.

Ну, где левое, там и правое объединение :)

select * from parents right join children on parents.id = children.parent_id;

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

а там недалеко и до полного объединения

select * from parents full join children on parents.id = children.parent_id;

выбрало бы всех родителей и всех детей. Для детей с родителями выбрало бы пары детей-родителей, а если у родителя нет детей или у ребенка нет родителей, туда прописало бы NULL-лы.

И финальным аккордом выбираем родителей без детей и детей без родителей.

select * from parents union join children on parents.id = children.parent_id;

Да, жалко, что MySQL всего этого не подерживает. Впрочем (философское замечание) в жизни ещё не видел чего-нибудь, что целиком поддерживало официальные стандарты. Как нам справедливо пишет Date в своей КНИГЕ, поддержка SQL в современных СУБД поддерживает надмножеств подмножества стандартного SQL.

5.

Я намеренно опустил NATURAL JOIN, так же как и выражение USING , потому что считаю его излишним и затемняющим вопрос. Того, что уже описано, вполне хватит для счастливой жизни.
Сами разбирайтесь, если интересно.

6.

Для объединений можно и нужно использовать условия where и group by.
Надо лишь не забывать, что where производится ДО объединения, а group by ПОСЛЕ.
Повторю другими словами, это важно. Сначала отбираются все записи, отвечающие условию where из таблиц, описанных в from. Потом они объединяются по условиям, описанным в join-ах.
И только потом группируются в group by.

7.

Надеюсь, ясно, что можно объединять не только две таблицы, но и более. Можно объединять и одну таблицу с самой собой. Когда вы храните какие-нибудь деревья, это особенно актуально.

например,

create table tree(root int, leaf int);

insert into tree(root, leaf) values (0,1);
insert into tree(root, leaf) values (1,2);
insert into tree(root, leaf) values (1,3);
insert into tree(root, leaf) values (0,4);


а теперь выберем терминальные элементы. Т.е. те, у которых нет дочерних.

select distinct t1.leaf from tree t1 left join tree t2 on t1.leaf=t2.root where t2.root is null;

+------+
| leaf |
+------+
| 2 |
| 3 |
| 4 |
+------+

Синонимы (t1, t2) нужны и очень полезны!

8.

Вот, что удалось найти в сети по этому вопросу. Не так уж плохо, по-моему, могли бы и сами покопать. Разве что без примеров.

=========================================================================

http://citforum.primorye.ru/database/dblearn/dblearn05.shtml
Синтаксис соединенных таблиц
В разделе FROM оператора SELECT можно использовать соединенные таблицы. Пусть в результате некоторых операций мы получаем таблицы A и B. Такими операциями могут быть, например, оператор SELECT или другая соединенная таблица. Тогда синтаксис соединенной таблицы имеет следующий вид:
Соединенная таблица ::=
Перекрестное соединение
| Естественное соединение
| Соединение посредством предиката
| Соединение посредством имен столбцов
| Соединение объединения
Тип соединения ::=
INNER
| LEFT [OUTER]
| RIGTH [OUTER]
| FULL [OUTER]
Перекрестное соединение ::=
Таблица А CROSS JOIN Таблица В
Естественное соединение ::=
Таблица А [NATURAL] [Тип соединения] JOIN Таблица В
Соединение посредством предиката ::=
Таблица А [Тип соединения] JOIN Таблица В ON Предикат
Соединение посредством имен столбцов ::=
Таблица А [Тип соединения] JOIN Таблица В USING (Имя столбца.,..)
Соединение объединения ::=
Таблица А UNION JOIN Таблица В
Опишем используемые термины.
CROSS JOIN - Перекрестное соединение возвращает просто декартово произведение таблиц. Такое соединение в разделе FROM может быть заменено списком таблиц через запятую.
NATURAL JOIN - Естественное соединение производится по всем столбцам таблиц А и В, имеющим одинаковые имена. В результатирующую таблицу одинаковые столбцы вставляются только один раз.
JOIN … ON - Соединение посредством предиката соединяет строки таблиц А и В посредством указанного предиката.
JOIN … USING - Соединение посредством имен столбцов соединяет отношения подобно естественному соединению по тем общим столбцам таблиц А и Б, которые указаны в списке USING.
OUTER - Ключевое слово OUTER (внешний) не является обязательными, оно не используется ни в каких операциях с данными.
INNER - Тип соединения "внутреннее". Внутренний тип соединения используется по умолчанию, когда тип явно не задан. В таблицах А и В соединяются только те строки, для которых найдено совпадение.
LEFT (OUTER) - Тип соединения "левое (внешнее)". Левое соединение таблиц А и В включает в себя все строки из левой таблицы А и те строки из правой таблицы В, для которых обнаружено совпадение. Для строк из таблицы А, для которых не найдено соответствия в таблице В, в столбцы, извлекаемые из таблицы В, заносятся значения NULL.
RIGHT (OUTER) - Тип соединения "правое (внешнее)". Правое соединение таблиц А и В включает в себя все строки из правой таблицы В и те строки из левой таблицы А, для которых обнаружено совпадение. Для строк из таблицы В, для которых не найдено соответствия в таблице А, в столбцы, извлекаемые из таблицы А заносятся значения NULL.
FULL (OUTER) - Тип соединения "полное (внешнее)". Это комбинация левого и правого соединений. В полное соединение включаются все строки из обеих таблиц. Для совпадающих строк поля заполняются реальными значениями, для несовпадающих строк поля заполняются в соответствии с правилами левого и правого соединений.
UNION JOIN - Соединение объединения является обратным по отношению к внутреннему соединению. Оно включает только те строки из таблиц А и В, для которых не найдено совпадений. В них используются значения NULL для столбцов, полученных из другой таблицы. Если взять полное внешнее соединение и удалить из него строки, полученные в результате внутреннего соединения, то получится соединение объединения.
Использование соединенных таблиц часто облегчает восприятие оператора SELECT, особенно, когда используется естественное соединение. Если не использовать соединенные таблицы, то при выборе данных из нескольких таблиц необходимо явно указывать условия соединения в разделе WHERE. Если при этом пользователь указывает сложные критерии отбора строк, то в разделе WHERE смешиваются семантически различные понятия - как условия связи таблиц, так и условия отбора строк (см. примеры 13, 14, 15 данной главы).
=========================================================================


[Это сообщение - спам!]

Последние сообщения из форума

Уважаемые посетители форума MySQL.RU!
Убедительная просьба, прежде чем задавать свой вопрос в этом форуме, обратите внимание на разделы:
- ответы на наиболее часто задаваемые вопросы - FAQ
- раздел документация
- раздел поиск по сообщениям форума и документации
Также, старайтесь наиболее подробно указывать свою ситуацию (версию операционной системы, версию MySQL, версию программного обеспечения, по которому возникает вопрос, текст возникающих ошибок, и др.)
Помните, чем конкретнее Вы опишете ситуацию, тем больше шансов получить реальную помощь.
 Имя:
 E-mail:
 Тема:
 Текст:
Код подтверждения отправки: Code
1369



РЕКЛАМА НА САЙТЕ
  Создание сайтов | |