me@helium пре 8 година
родитељ
комит
4154d5971f
1 измењених фајлова са 76 додато и 0 уклоњено
  1. 76 0
      SQL.md

+ 76 - 0
SQL.md

@@ -362,8 +362,84 @@ SELECT *
         person_id = 1;
 ```
 
+Однако, если мы сделаем запрос для выборки всех людей с их номерами телефонов, мы получим *не всех людей*:
+```mysql
+SELECT * 
+    FROM 
+        person, 
+        person_to_phone, 
+        phone 
+    WHERE 
+        person.id = person_to_phone.person_id AND 
+        person_to_phone.phone_id = phone.id;
+```
+...a только тех, у кого *есть номера телефонов*.
+
 ### Несколько таблиц, `RIGHT` и `LEFT` `JOIN` (`OUTER JOIN`)
+Для решения вышеозначенной проблемы есть запросы `LEFT` и `RIGHT JOIN`:
+```mysql
+SELECT * 
+    FROM 
+        person LEFT JOIN person_to_phone ON (person.id = person_to_phone.person_id) 
+               LEFT JOIN phone ON (person_to_phone.phone_id = phone.id);
+```
+Запрос выше показывает *всех* пользователей, даже тех, у кого телефонов *нет*. Недостающие поля заполняются `NULL`
+```mysql
+SELECT * 
+    FROM 
+        person RIGHT JOIN person_to_phone ON (person.id = person_to_phone.person_id) 
+               RIGHT JOIN phone ON (person_to_phone.phone_id = phone.id);
+```
+Этот запрос, наоборот, показывает все телефоны, один из который не принадлежит никому из пользователей. 
 
 ### `GROUP BY` и агрегация
+Нередко возникает задача, когда требуется не выводить все присоединенные записи, а произвести над ними определенные действия и вывести один результат
+для каждой "родительской" записи. Например, подсчитаем количество телефонов у каждого пользователя
+
+```mysql
+SELECT
+        person.id, 
+        person.surname, 
+        count(phone.id) 
+    FROM 
+        person 
+            LEFT JOIN person_to_phone ON (person.id = person_to_phone.person_id) 
+            LEFT JOIN phone ON (person_to_phone.phone_id = phone.id) 
+    GROUP BY 
+        person.id;
+```
+
+Так же мы можем получить все номера телефонов в удобном для `explode` виде:
+
+```mysql
+SELECT 
+        person.id, 
+        person.surname, 
+        COUNT(phone.id), 
+        GROUP_CONCAT(phone.phone) 
+    FROM 
+        person 
+            LEFT JOIN person_to_phone ON (person.id = person_to_phone.person_id) 
+            LEFT JOIN phone ON (person_to_phone.phone_id = phone.id) 
+    GROUP BY 
+        person.id;
+```
+
+Или подсчитать средний возраст пользователей тех или иных типов телефонов:
+
+```mysql
+SELECT 
+        phone.phone_type, 
+        AVG(TIMESTAMPDIFF(YEAR, person.date_of_birth, CURDATE())) 
+    FROM 
+        phone 
+            LEFT JOIN person_to_phone ON (phone.id = person_to_phone.phone_id) 
+            LEFT JOIN person ON (person_to_phone.person_id = person.id) 
+    GROUP BY 
+        phone_type;
+```
+
+Для понимания, как именно работает `GROUP BY`, попробуйте его убрать и отсортировать выборку по полю, которое было в GROUP BY. Таким образом вы увидите
+*все* записи сгруппированными благодаря сортировке. СУБД работает схожим образом.
 
 ### `AS` и древовидные структуры данных в реляционных СУБД.