Sql on join: Функция Join в SQL: описание и примеры

Функция Join в SQL: описание и примеры

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

Что такое SQL Join?

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

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

SQL Join помогает настроить фильтр поиска в базе данных, опираясь на взаимосвязи между различными элементами БД и их отличительные черты (теги, ID, наименования и т.п.).

Комьюнити теперь в Телеграм

Подпишитесь и будьте в курсе последних IT-новостей

Подписаться

SQL Inner Join

Этот режим объединения результатов поиска в базах данных SQL включается автоматически. Если вы не укажете намеренно тип Join, то сработает именно Inner Join. С помощью него можно указать сразу два критерия (две таблицы) и по ним отсеять контент. 

Достаточно прописать SQL-запрос в духе:


SELECT *
FROM table-1
JOIN table-2 ON table-1.parameter=table-2.parameter
WHERE table-1.parameter IS ‘myData’

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

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


SELECT *
FROM SevenStringGuitars
JOIN Ibanez ON SevenStringGuitar.brandId=Ibanez.brandId

Таким SQL-запросом мы можем отфильтровать все инструменты бренда Ibanez в категории «Гитары» с 7 струнами.  

SQL Self Join 

Запросы Self Join полезны в тех случаях, когда необходимо выполнить фильтрацию контента внутри одной таблицы. Например, у вас есть список товаров в базе данных. У каждого из них указан свой бренд, но есть и те, что поставляются одним производителем. Self Join можно использовать для объединения двух стеков информации из одной таблицы. 

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

SQL-команда в этом случае может выглядеть следующим образом:


SELECT *
FROM products JOIN products ON table.product=table.brand

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

SQL Cross Join

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

Стандартный SQL-запрос с Cross Join может выглядеть следующим образом:


SELECT *
FROM table-1
CROSS JOIN table-2

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

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

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

SQL Outer Join

Outer Join – это своего рода противоположность Inner Join. Как понятно из названия, Outer Join предоставляет информацию не только из внутренней части поиска, но и из внешней. То есть программа ищет не только точечные совпадения по выбранным ранее критериям, а позволяет немного ослабить «хватку» и предоставить более «свободные» результаты поиска, включающие в себя элементы из таблиц, которые хоть и совпадают с критериями в SQL-запросе, но не полностью. 

Когда такой подход может понадобиться? Например, для скрупулезной фильтрации товаров. Если вы готовы покупать продукцию компании «Шестерочка» и не против, если среди нее окажется молоко, но при этом вы точно не хотите покупать молоко других производителей, то вам подойдет подобный фильтр. Он позволяет дать одному из критериев поиска что-то в духе привилегий. 

Разновидности Outer Join

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

Left

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

На практике это может выглядеть так:


SELECT *
FROM table1
LEFT JOIN table2 ON table1.parameter=table2.parameter

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

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


SELECT * 
FROM table1
LEFT JOIN table2 ON table1.parameter=table2.parameter
WHERE table2.parameter IS NULL

На живом примере фильтрация такого рода может выглядеть так:


SELECT *
FROM Russian
LEFT JOIN Rap ON Russian.genreId=Rap.genreId

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

Right

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

Получится следующий SQL-запрос:


SELECT *
FROM table1
RIGHT JOIN table2 ON table1.parameter=table2.parameter

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


SELECT *
FROM Russian
RIGHT JOIN Rap ON Russian.genreId=Rap.genreId

Full

Это вариант для тех, кто хочет использовать сразу два разных критерия для поиска какого-либо контента. Снова вернемся к примеру с музыкальным приложением. Join Full может пригодиться, если вы хотите послушать либо что-то на русском, либо любой рэп. Вам не важны какие-либо другие параметры. Вас волнуют исключительно две характеристики. При этом вам не так важно, будут ли они пересекаться. То есть вам все равно, будет рэп на русском или же на русском будет какой-то агрессивный металл. 

SQL-запрос с таким Join мог бы выглядеть следующим образом:


SELECT *
FROM table1
FULL OUTER JOIN table2 ON table1. parameter=table2.parameter

Можно исключить из результатов фильтрации все пары. То есть можно выбрать только рэп, но ни в коем случае не русский, и русскую музыку, но ни в коем случае не рэп (вполне могу понять такой выбор, кстати говоря). 

Чтобы это сделать, необходимо написать следующий SQL-запрос. 


SELECT *
FROM Russian
FULL OUTER JOIN Rap ON Russian.genreId=Rap.genreId
WHERE Russian.genreId IS NULL OR Rap.genreId IS NULL

Теперь вы увидите в результатах поиска только непарные строки. 

Вместо заключения

SQL Join – мощнейший инструмент для фильтрации строк в базах данных. Благодаря ему можно легко находить именно ту информацию, что нужна, а не возиться с недоделанными фильтрами, которые обычно предоставляют разработчики сайтов и приложений. Жаль, что такие мощные механизмы поиска доступны далеко не везде. Но, создавая собственные продукты, вы можете их реализовать. Power-пользователи точно останутся довольны.

SQL join в примерах с описанием

Присоединение таблиц в запросах — это базовый инструмент в работе с базами данных. Давайте рассмотрим какие присоединения (JOIN) бывают, и что от этого меняется в результатах запроса.

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

Persons (Сотрудники)

Столбец position_ref (от «position reference») это ссылка на следующую таблицу, где перечислены должности сотрудников.

Positions (должности)

Т.е. чтобы узнать должность сотрудника в таблице Persons, нужно присоединить соответствующие данные из таблицы Positions, связывая их по значениям position_ref и id_pos.

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

INNER JOIN

Внутреннее присоединение. Равносильно просто JOIN или CROSS JOIN (верно для MYSQL, в стандарте SQL INNER JOIN не эквивалентен синтаксически CROSS JOIN, т. к. используется с выражением ON).


SELECT id_person, name, id_pos, title
FROM `persons`
INNER JOIN `positions` ON id_pos = position_ref



 

SELECT id_person, name, id_pos, title

FROM `persons`

INNER JOIN `positions` ON id_pos = position_ref

 


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

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

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

Далее проследим как получить разные части (подмножества) данного множества.

OUTER JOIN

Внешнее присоединение. Различают LEFT OUTER JOIN и RIGHT OUTER JOIN, и обычно опускают слово «OUTER».

Внешнее присоединение включает в себя результаты запроса INNER и добавляются «неиспользованные» строки из одной из таблиц. Какую таблицу использовать в качестве «добавки» — указывает токен LEFT или RIGHT.

LEFT JOIN

Внешнее присоединение «слева».


SELECT id_person, name, id_pos, title
FROM `persons`
LEFT OUTER JOIN `positions` ON id_pos = position_ref



 

SELECT id_person, name, id_pos, title

FROM `persons`

LEFT OUTER JOIN `positions` ON id_pos = position_ref

 


«Левая» таблица persons, содержит строку id_person#3 — «Александр», где указан идентификатор должности, отсутствующей в словаре. Мы увидим все записи из «левой» таблицы, тогда как правая будет присоединена по возможности.

На картинке это можно показать вот так:

RIGHT JOIN

Присоединение «справа».


SELECT id_person, name, id_pos, title
FROM persons
RIGHT OUTER JOIN positions ON id_pos = position_ref



 

SELECT id_person, name, id_pos, title

FROM persons

RIGHT OUTER JOIN positions ON id_pos = position_ref

 


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

Словарь должностей (правая таблица) содержит неиспользуемую запись с id_pos#3 — «программист». Теперь она попала в результат запроса.

Полное множество

MySQL не знает соединения FULL OUTER JOIN. Что если нужно получить полное множество?

Первый способ — объединение запросов LEFT и RIGHT.


(SELECT id_person, name, id_pos, title
FROM persons
LEFT OUTER JOIN positions ON id_pos = position_ref)
UNION
(SELECT id_person, name, id_pos, title
FROM persons
RIGHT OUTER JOIN positions ON id_pos = position_ref)


1

2

3

4

5

6

7

8

9

10

11

 

(SELECT id_person, name, id_pos, title

FROM persons

LEFT OUTER JOIN positions ON id_pos = position_ref)

 

UNION

 

(SELECT id_person, name, id_pos, title

FROM persons

RIGHT OUTER JOIN positions ON id_pos = position_ref)

 


При таком вызове UNION, после слияния результатов, SQL отсечет дубли (как DISTINCT). Для отсечения дублей SQL прибегает к сортировке. Это может сказываться на быстродействии.

Второй способ — объединение LEFT и RIGHT, но в одном из запросов мы исключаем часть, соответствующую INNER. А объединение задаём как UNION ALL, что позволяет движку SQL обойтись без сортировки.


(SELECT id_person, name, id_pos, title
FROM persons
LEFT OUTER JOIN positions ON id_pos = position_ref)
UNION ALL
(SELECT id_person, name, id_pos, title FROM persons
RIGHT OUTER JOIN positions ON id_pos = position_ref
WHERE id_person is NULL)


1

2

3

4

5

6

7

8

9

10

11

 

(SELECT id_person, name, id_pos, title

FROM persons

LEFT OUTER JOIN positions ON id_pos = position_ref)

 

UNION ALL

 

(SELECT id_person, name, id_pos, title FROM persons

RIGHT OUTER JOIN positions ON id_pos = position_ref

WHERE id_person is NULL)

 


Этот пример показывает нам как исключить пересечение и получить только левую или правую часть множества.

Левое подмножество

LEFT JOIN ограничиваем проверкой, что данных из второй таблицы нет.


SELECT id_person, name, id_pos, title
FROM persons
LEFT OUTER JOIN positions ON id_pos = position_ref
WHERE id_pos is NULL


1

2

3

4

5

6

 

SELECT id_person, name, id_pos, title

FROM persons

LEFT OUTER JOIN positions ON id_pos = position_ref

WHERE id_pos is NULL

 


В нашем примере — это специалисты, у которых не задана должность или нет должности с указанным ключом.

Правое подмножество

Аналогично выделяем правую часть.


SELECT id_person, name, id_pos, title
FROM persons
RIGHT OUTER JOIN positions ON id_pos = position_ref
WHERE id_person is NULL


1

2

3

4

5

6

 

SELECT id_person, name, id_pos, title

FROM persons

RIGHT OUTER JOIN positions ON id_pos = position_ref

WHERE id_person is NULL

 


В нашем случае получим должности, которые никому не назначены.

Всё кроме пересечения

Остался один вариант, тот когда исключено пересечение множеств. Его можно сложить из двух предыдущих запросов через UNION ALL (т.к. подмножества не пересекаются).


(SELECT id_person, name, id_pos, title
FROM persons
LEFT OUTER JOIN positions ON id_pos = position_ref
WHERE id_pos is NULL)
UNION ALL
(SELECT id_person, name, id_pos, title
FROM persons
RIGHT OUTER JOIN positions ON id_pos = position_ref
WHERE id_person is NULL)


1

2

3

4

5

6

7

8

9

10

11

12

13

 

(SELECT id_person, name, id_pos, title

FROM persons

LEFT OUTER JOIN positions ON id_pos = position_ref

WHERE id_pos is NULL)

 

UNION ALL

 

(SELECT id_person, name, id_pos, title

FROM persons

RIGHT OUTER JOIN positions ON id_pos = position_ref

WHERE id_person is NULL)

 


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

А графически такое объединение выглядит следующим образом:


Данная запись опубликована в 19.09.2017 20:19 и размещена в mySQL.
Вы можете перейти в конец страницы и оставить ваш комментарий.

SQL Joins

❮ Предыдущий
Далее ❯


SQL JOIN

Предложение JOIN используется для объединения строк из двух или более таблиц на основе
связанный столбец между ними.

Посмотрим на выборку из таблицы «Заказы»:

OrderID идентификатор клиента Дата заказа
10308 2 18 сентября 1996 г.
10309 37 1996-09-19
10310 77 1996-09-20

Затем посмотрите на выбор из таблицы «Клиенты»:

CustomerID ИмяКлиента Имя контакта Страна
1 Альфред Футтеркисте Мария Андерс Германия
2 Ана Трухильо Emparedados y helados Ана Трухильо Мексика
3 Антонио Морено Такерия Антонио Морено Мексика

Обратите внимание, что столбец «CustomerID» в таблице «Заказы» относится к
«CustomerID» в таблице «Клиенты». Отношения между двумя таблицами выше
является столбец «CustomerID».

Затем мы можем создать следующую инструкцию SQL (содержащую
ВНУТРЕННЕЕ СОЕДИНЕНИЕ
),
который выбирает записи, имеющие совпадающие значения в обеих таблицах:

Пример

SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate
FROM Orders
INNER JOIN Customers ON Orders.CustomerID=Customers.CustomerID;

Попробуйте сами »

и он выдаст что-то вроде этого:

OrderID ИмяКлиента Дата заказа
10308 Ана Трухильо Emparedados y helados 18.09.1996
10365 Антонио Морено Такерия 27.11.1996
10383 Вокруг Рога 16.12.1996
10355 Вокруг Рога 15.11.1996
10278 Berglunds snabköp 12. 08.1996


Различные типы SQL JOIN

Вот различные типы JOIN в SQL:

  • (INNER) JOIN : Возвращает записи, которые имеют совпадающие значения в обеих таблицах
  • ЛЕВОЕ (ВНЕШНЕЕ) СОЕДИНЕНИЕ : возвращает все записи из левой таблицы и соответствующие записи из правой таблицы
  • ПРАВОЕ (ВНЕШНЕЕ) СОЕДИНЕНИЕ : Возвращает все записи из правой таблицы и соответствующие
    записи из левой таблицы
  • ПОЛНОЕ (ВНЕШНЕЕ) СОЕДИНЕНИЕ : Возвращает все записи, если есть совпадение в любом левом
    или правый стол

Проверьте себя с помощью упражнений

Упражнение:

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

ВЫБРАТЬ *
ОТ заказов
ВЛЕВО ПРИСОЕДИНЯЙТЕСЬ к клиентам
= 
;

Начать упражнение

❮ Предыдущий
Далее ❯

НОВИНКА

Мы только что запустили
Видео W3Schools

Узнать

ВЫБОР ЦВЕТА
КОД ИГРЫ

Играть в игру




Лучшие учебники

Учебник HTML
Учебник CSS
Учебник JavaScript
Учебник How To
Учебник SQL
Учебник Python
Учебник W3.CSS
Учебник Bootstrap
Учебник PHP
Учебник Java
Учебник по C++
Учебник по jQuery

Основные ссылки

Справочник по HTML
Справочник по CSS
Справочник по JavaScript
Справочник по SQL
Справочник по Python
Справочник по W3.CSS
Справочник по Bootstrap
Справочник по PHP
Цвета HTML
Справочник по Java
Справочник по Angular
Справочник по jQuery

Top0 Examples
Примеры HTML
Примеры CSS
Примеры JavaScript
Примеры инструкций
Примеры SQL
Примеры Python
Примеры W3. CSS
Примеры Bootstrap
Примеры PHP
Примеры Java
Примеры XML
Примеры jQuery


FORUM |
О

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

Copyright 1999-2022 Refsnes Data. Все права защищены.
W3Schools работает на основе W3.CSS.

SQL | Соединение (внутреннее, левое, правое и полное соединение)

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

  • INNER JOIN
  • LEFT JOIN
  • RIGHT JOIN
  • FULL JOIN

Рассмотрим две таблицы ниже: 

Student

 

StudentCourse  

Самым простым соединением является INNER JOIN.

A. INNER JOIN

Ключевое слово INNER JOIN выбирает все строки из обеих таблиц, если выполняется условие. Это ключевое слово создаст набор результатов, объединив все строки из обеих таблиц, где выполняется условие, т. е. значение общего поля будет одинаковым.

Синтаксис

 ВЫБЕРИТЕ таблица1.столбец1,таблица1.столбец2,таблица2.столбец1,....
ИЗ таблицы1
ВНУТРЕННЕЕ СОЕДИНЕНИЕ таблица2
ON table1.matching_column = table2.matching_column;


  таблица1  : Первая таблица.
  таблица2  : Вторая таблица
  match_column  : Столбец, общий для обеих таблиц. 

Примечание : Мы также можем написать JOIN вместо INNER JOIN. СОЕДИНЕНИЕ такое же, как ВНУТРЕННЕЕ СОЕДИНЕНИЕ.

Примеры запросов (INNER JOIN)

Этот запрос покажет имена и возраст студентов, зачисленных на разные курсы.

 ВЫБЕРИТЕ StudentCourse. COURSE_ID, Student.NAME, Student.AGE FROM Student
ВНУТРЕННЕЕ СОЕДИНЕНИЕ
ON Student.ROLL_NO = StudentCourse.ROLL_NO; 

Выходные данные :  

B. LEFT JOIN

Это объединение возвращает все строки таблицы с левой стороны объединения и сопоставляет строки таблицы с правой стороны объединения. Для строк, для которых нет соответствующей строки с правой стороны, результирующий набор будет содержать ноль . ЛЕВОЕ СОЕДИНЕНИЕ также известно как ЛЕВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ.

Синтаксис:  

 SELECT table1.column1,table1.column2,table2.column1,....
ИЗ таблицы1
ЛЕВОЕ СОЕДИНЕНИЕ таблица2
ON table1.matching_column = table2.matching_column;


таблица1: первая таблица.
таблица2: вторая таблица
Matching_column: столбец, общий для обеих таблиц. 

Примечание : Мы также можем использовать LEFT OUTER JOIN вместо LEFT JOIN, оба они одинаковы.

Примеры запросов (LEFT JOIN)

 ВЫБЕРИТЕ Student. NAME,StudentCourse.COURSE_ID
ОТ Студент
LEFT JOIN
ON StudentCourse.ROLL_NO = Student.ROLL_NO; 

Выход

C. ПРАВОЕ СОЕДИНЕНИЕ

ПРАВОЕ СОЕДИНЕНИЕ аналогично ЛЕВОМУ СОЕДИНЕНИЮ. Это объединение возвращает все строки таблицы с правой стороны объединения и совпадающие строки для таблицы с левой стороны объединения. Для строк, для которых нет соответствующей строки слева, набор результатов будет содержать ноль . ПРАВОЕ СОЕДИНЕНИЕ также известно как ПРАВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ.

Синтаксис:  

 SELECT table1.column1,table1.column2,table2.column1,....
ИЗ таблицы1
ПРАВОЕ СОЕДИНЕНИЕ таблица2
ON table1.matching_column = table2.matching_column;


таблица1: первая таблица.
таблица2: вторая таблица
Matching_column: столбец, общий для обеих таблиц. 

Примечание : мы также можем использовать RIGHT OUTER JOIN вместо RIGHT JOIN, оба они одинаковы.

 

Примеры запросов (ПРАВОЕ СОЕДИНЕНИЕ) :

 ВЫБЕРИТЕ Student.NAME,StudentCourse.COURSE_ID
ОТ Студент
ПРАВО ПРИСОЕДИНЯЙСЯ
ON StudentCourse.ROLL_NO = Student.ROLL_NO; 

Выходные данные:  

D. ПОЛНОЕ СОЕДИНЕНИЕ

ПОЛНОЕ СОЕДИНЕНИЕ создает результирующий набор, объединяя результаты левого и правого соединения. Набор результатов будет содержать все строки из обеих таблиц. Для строк, для которых нет соответствия, результирующий набор будет содержать NULL значения.

Синтаксис:   

 SELECT table1.column1,table1.column2,table2.column1,....
ИЗ таблицы1
ПОЛНОЕ СОЕДИНЕНИЕ таблица2
ON table1.matching_column = table2.matching_column;


таблица1: первая таблица.
таблица2: вторая таблица
Matching_column: столбец, общий для обеих таблиц. 

Примеры запросов (FULL JOIN)

 SELECT Student. NAME,StudentCourse.COURSE_ID
ОТ Студент
ПОЛНОЕ СОЕДИНЕНИЕ
ON StudentCourse.ROLL_NO = Student.ROLL_NO; 

Output:   

NAME

COURSE_ID

HARSH

1

PRATIK

2

Riyanka

2

Глубоко

3

Saptarhi

.0024

1

DHANRAJ

NULL

ROHIT

NULL

NIRAJ

NULL

NULL

4

NULL

5

NULL

4

0047

СОЕДИНЕНИЕ слева (видео)
СОЕДИНЕНИЕ справа (видео)
Полное СОЕДИНЕНИЕ (видео)
SQL | JOIN (декартово соединение, самосоединение)

Эта статья написана пользователем Harsh Agarwal .

Imacros | Все права защищены © 2021