Народна самодіяльність
Народна самодіяльність # 151; зв'язку таблиць в MySQL
Чотири причини, чому не треба братися за написання великого додатка заради навчання мови
Спочатку я припускав зробити випуск "Народної самодіяльності" зі збіркою помилок, допущених в основному мною :). Дещо я збирав з статей про традиційні помилки і т.п. Але життя виявляється куди цікавіше! Пишу про чергову самодіяльність прямо по гарячих слідах.
Отже, один чоловік, назвемо його Вася, запитує Громадськість форуму про MySQL.
В .: Не зовсім зрозуміло як створити зв'язок між таблицями, щоб в поле першої автоматично вставлялися дані другої (есно вибірково і есно по ВД).
Варівант типу SELECT db.user, db.delete_priv, user.user, user.delete_priv FROM db, user WHERE db.user = user.user не зовсім підходить, так як зв'язком це можна назвати з великою натяжкою.
O .: Чесно кажучи, не розумію, чому цей зв'язок тобі не підходить? Чим цей зв'язок натягнута?
В .: Ну не подобається мені зв'язок, заснована на синтаксисі запитів. хотілося б чогось більш суттєвого, інакше я взагалі не бачу сенсу в ключах і індексах.
O .: Більш істотне - ти маєш на увазі графічний інтерфейс як в MS Access?
На жаль, сам Access працює точно так само # 151; досить натиснути кнопочку "SQL", і ви побачите ці зв'язки "з великою натяжкою".
В .: Просто мені простіше програмно все це робити, благо таблиці невеликі. Раз в самому MySQL це не працює.
O .: Через вкладені цикли, рекурсії? Скажи навіщо тоді тобі взагалі база даних і таблиці?
В .: Ніяких вкладених циклів і рекурсій # 151; Новомосковський н-е колмчество масивів і з ними вже працюю. А робити зв'язок на основі селекта # 151; не зовсім те що мені потрібно.
O .: Правильно. бережи все в файлик, тоді взагалі питань не буде.
Загалом, вважаю своїм обов'язком розкласти по поличках зв'язку таблиць.
The FOREIGN KEY, CHECK, and REFERENCES clauses do not actually do anything. The syntax for them is provided only for compatibility, to make it easier to port code from other SQL servers and to run applications that create tables with references. See section 5.4 Functionality Missing from MySQL.
Зв'язок без великої натяжки
Взагалі, ніякої натяжки в описі зв'язків в запиті не було і немає - споконвіку БД працювали саме так. Access зі стрілками і формопостроітелямі з'явився набагато пізніше.
Як робити неправильно
Наприклад, ось так:
З запиту отримані імена рубрик та записані в масив # 36; rub.
Тепер вибираються новини, і замість обраного номера рубрики вставляємо відповідний елемент масиву рубрик.
Насправді, можна позбавити себе від необхідності тягти крізь всю програму цей масив # 36; rub (а якщо у нас до рубрик звертаються функції - що, через GLOBAL брати?), Від можливості помилитися з # 36; rub [# 36; row [ "rub"]] - якщо на сторінці кілька подібних запитів, то зробити опечатку де-небудь легко.
Крім того, під масив # 36; rub потрібно певний обсяг пам'яті (а якщо рубрик багато?). У третій версії PHP такий скрипт буде виконуватися довше, ніж при використанні об'єднань таблиць, тому що він інтерпретує програму через підрядник при виконанні (на відміну від 4-го, який компілює програму і тільки потім виконує).
У наведеному вище прикладі можна застосувати об'єднання таблиць і позбутися від описаних недоліків.
Отже, тут краще використовувати запит "SELECT sites.id, url, sites.name as sitename, rubs.name as rubsname, rubs.id as rub_id FROM sites, rubs WHERE sites.rub = rubs.id". Виходить, що ми маємо готовий масив, піклуємося про виведення тільки його елементів і пишемо менше коду.
Синтаксис об'єднань таблиць
Просте з'єднання - INNER JOIN:
SELECT
SELECT
SELECT
якщо таблиці об'єднуються по полю field1.
У такому поєднанні вибираються тільки ті рядки таблиць, які відповідають умові об'єднання - рівність значень полів. Якщо для рядка table1 немає відповідного рядка з table2, рядок не потрапляє в підсумок запиту. Якщо ж треба підрахувати кількість сайтів в рубриці (продовжую приклад з каталогом), такий запит не зовсім підходить - в списку з'являться тільки рубрики, в яких є сайти. Для подібної операції потрібно використовувати LEFT JOIN.
SELECT
SELECT
якщо таблиці об'єднуються по полю field1.
При цьому відповідного рядка в table2 може і не бути, тоді в полях з table2 ми отримаємо NULL, а якщо це групова операція, як у випадку з кількістю сайтів в рубриці, тоді в поле буде 0:
SELECT rubs.id, name, COUNT (sites.id) AS sites FROM rubs LEFT JOIN sites ON rubs.id = sites.rub GROUP BY rubs.id
Зауважте: поля id є в обох таблицях, тому в їх позначенні треба використовувати ім'я таблиці. До речі, якщо при об'єднанні не використовуються групові операції, все одно краще міняти ім'я поля оператором AS, щоб не виникало плутанини.
> Об'єднання таблиць моторошно гальмувало
для швидкого об'єднання на полях по яких об'єднують потрібні індекси. EXPLAIN SELECT вам вірний друг і товариш. І ще запити можна оптимізувати, почитайте розділ мана "5.2.6 How MySQL Optimises LEFT JOIN and RIGHT JOIN". Ще, можливо, якщо є інші більш вузькі умови відбору WHERE - поставити їх на перше місце а потім JOIN.
Ніколи не повірю що програмно на клієнті ви зробите об'єднання краще (ефективна) ніж це зробить СУБД.