Основы SQL на примере задачи

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

Постановка задачи


Дана база данных, в ней 3 таблицы следующего вида:




table1: user_id (INT(5), PRIMARY KEY), username (VARCHAR(50), INDEX)
table2: phone_id (INT(5), PRIMARY KEY), user_id (INT(5), INDEX), phone_number (INT(10), INDEX)
table3: room_id (INT(5), PRIMARY KEY), phone_id (INT(5), INDEX), room_number(INT(4) INDEX)

Необходимо выбрать номер комнаты в которой сидит пользователь с ником qux…

Подготовка данных для задачи


Для создания баз данных и таблиц используются операторы CREATE DATABASE и CREATE TABLE, соответственно (для удаления DROP DATABASE и DROP TABLE). В конце каждой команды ставится точка с запятой (;). Сначала создадим базу с именем article:

CREATE DATABASE IF NOT EXISTS article;

Мы используем ключевые слова IF NOT EXISTS для того, чтобы не возникала ошибка, если указанная база данных или таблица уже существует (в дальнейшем IF NOT EXISTS для простоты будем опускать).
Теперь необходимо создать таблицы:

CREATE TABLE `table1` (`user_id` INT(5) NOT NULL AUTO_INCREMENT, `username` VARCHAR(50), PRIMARY KEY(`user_id`), INDEX(`username`));
CREATE TABLE `table2` (`phone_id` INT(5) NOT NULL AUTO_INCREMENT, `user_id` INT(5) NOT NULL, phone_number INT(10) NOT NULL, PRIMARY KEY (`phone_id`), INDEX(`user_id`, `phone_number`));
CREATE TABLE `table3` (`room_id` INT(5) NOT NULL AUTO_INCREMENT, `phone_id` INT(5) NOT NULL, `room_number` INT(4) NOT NULL, PRIMARY KEY(`room_id`), INDEX(`phone_id`, `room_number`));

Разберём эти команды по порядку. После CREATE TABLE указывается имя таблицы, далее в скобках следуют имена полей с типами и атрибутами, перечисленные через запятую и указания ключей. Первой командой мы создаём таблицу с именем table1 и полями user_id, username. Поле user_id имеет целочисленный тип (INT) и длину 5-ть знаков, не может равняться нулю и обладает атрибутом auto_increment (при создании каждой записи, значение в этом поле создаётся автоматически и увеличивается на единицу), к тому же оно является первичным ключём. [ Первичный ключ (primary key) представляет собой один из примеров уникальных индексов и применяется для уникальной идентификации записей таблицы. Никакие из двух записей таблицы не могут иметь одинаковых значений первичного ключа. ] Поле username имеет символьный тип (длина 255 символов) и является индексом. Вторая и третья команды аналогичны первой.

Для проверки какие таблицы есть у Вас в базе можно использовать команду:

SHOW TABLES; 

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

INSERT INTO table1 (username) VALUE ('foo'); 

В поле user_id мы ничего не добавляем так как оно автоматически создаётся при каждом INSERT`е (вспоминаем про магический атрибут auto_increment). После названия таблицы в скобках (далее будем называть эти скобки кортежём) указывается список полей, которым мы будем присваивать значения. После VALUE указываются сами значения. Они должны стоять на соответствующих позициях в кортеже.
Такими же командами добавляем пользователей bar, baz, qux.
Для проверки используем команду:

[1]
SELECT * FROM table1; 

Саму команду SELECT мы рассмотрим подробнее позже.
Далее заполним таблицы table2 и table3.

[2]
INSERT INTO table2 (user_id, phone_number) VALUE ('2','200'); 

Здесь полю user_id присваивается значение 2, а полю phone_number — 200. Если поменять местами названия полей или значения в кортежах, то результат измениться. Например:

[3]
INSERT INTO table2 (user_id, phone_number) VALUE ('200','2'); 

Теперь полю user_id присваивается значение 200, а phone_number – 2.
Предположим, мы ошиблись при добавлении значений (использовали команду [3] вместо [2]), не надо рваться удалять таблицу или всю базу — значение можно изменить с помощью оператора UPDATE.

UPDATE table2 SET user_id='2', phone_number='200' WHERE phone_id='1';

После SET мы указываем поля, значения которых необходимо изменить, и соответственно новые значения через знак равно. Оператор WHERE мы видим впервые. Он необходимо для наложения ограничений на запрос. В данном случае изменения будут применяться не ко всем строкам таблицы, а только к тем у которых значение поля phone_id равно '1'.
Остальные данные добавляются по аналогии (что добавлять можно посмотреть вверху страницы).

Решение


Базу данных и таблицы мы создали. Теперь можно заняться решением самой задачи. Выборка в базе данных производится с помощью оператора SELECT, с которым мы немного знакомы по команде [1]. Рассмотрим его подробнее. В общем виде он выглядит так:
SELECT названия_полей FROM названия_таблиц WHERE условие [ORDER BY, LIMIT]
Где ORDER BY и LIMIT дополнительные опции.
Попробуем применить его. Выберем все значения поля username из таблицы table1.

SELECT username FROM table1;

и отсортируем их

SELECT username FROM table1 ORDER BY username;

Как видно, ORDER BY используется для сортировки по одному из полей, указанных после оператора SELECT. По умолчанию делается возрастающая сортировка, если хотим использовать сортировку в обратном порядке то после поля необходимо добавить DESC:

SELECT username FROM table1 ORDER BY username DESC;

Так как нам нужны все значения, то оператор WHERE можно не использовать. Ещё один пример: выбираем значения полей phone_id и user_id из таблицы table2, где phone_number равен '200'.

SELECT phone_id, user_id FROM table2 WHERE phone_number=200;
SELECT phone_id, user_id FROM table2 WHERE phone_number=200 LIMIT 1, 3;

LIMIT выводит строки в указанном диапазоне (нижняя граница не включается). Если первый аргумент не указан, то он считается равным 0.

Как мы можем видить, все три наши таблицы связаны. table1 и table2 через поле user_id, а table2 и table3 через phone_id. Для того, чтобы связать их в одно целое по указанным столбцам, необходимо воспользоваться оператором JOIN. JOIN, в переводе на великий и могучий, означает «объединять», то есть собирать из нескольких кусочков единое целое. В базе данных MySQL такими «кусочками» служат поля таблиц, которые можно объединять при выборке. Объединения позволяют извлекать данные из нескольких таблиц за один запрос. В зависимости от требований к результату, MySQL позволяет производить три разных типа объединения:
1. INNER JOIN (CROSS JOIN) — внутреннее (перекрёстное) объединение
2. LEFT JOIN — левостороннее внешнее объединение
3. RIGHT JOIN — правостороннее внешнее объединение

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

[4]
SELECT table3.room_number FROM table1 INNER JOIN table2 USING(user_id) INNER JOIN table3 USING(phone_id) WHERE table1.username = 'qux'; 

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

SELECT table3.room_number FROM table1 INNER JOIN table2 ON table1.user_id = table2.user_id INNER JOIN table3 ON table2.phone_id = table3.phone_id WHERE table1.username = 'qux';

LEFT/RIGHT JOIN позволяют извлекать данные из таблицы, дополняя их по возможности данными из другой таблицы. Чтобы показать разницу с INNER JOIN нам сначала необходимо будет добавить ещё одно поле в таблицу table1.

INSERT INTO table1 (username) VALUE ('quuz');

А теперь используем команду [4], только заменим INNER JOIN на LEFT JOIN, а qux на quuz:

SELECT table3.room_number FROM table1 LEFT JOIN table2 USING(user_id) LEFT JOIN table3 USING(phone_id) WHERE table1.username = 'quuz';

Мы получим следующий результат:


Новый пользователь получил user_id=5. Это значение отсутствует в других таблицах, поэтому в результате мы получили NULL. При INNER JOIN результат был бы пустой, так как выводятся только значения, которые есть во всех таблицах. Здесь же таблицы table1 и table2 дополняются значением из table3, даже если его и нет.

Аппендикс


Ниже приводятся примеры команд с небольшими пояснениями:

Удалить строку с user_id равным 1 из таблицы table1:
DELETE FROM table1 WHERE user_id = 1; 

Переименовываем таблицу table1 в nya:
RENAME TABLE table1 TO nya; 

Переименовать поле user_id в id (таблица table1):
ALTER TABLE table1 CHANGE user_id id INT; 

Меняем тип и атрибут поля phone_number:
ALTER TABLE table2 MODIFY phone_number VARCHAR(100) NOT NULL; 

Просмотр описания таблицы table1:
DESCRIBE table1; 

Добавляем поле abra типа DATE:
ALTER TABLE table3 ADD abra  DATE; 

Выбираем из table3 все значения поля room_id, для которых room_number начинается с цифры 3 (% означает любое количество любых символов; like проверяет совпадение символьной строки с заданным шаблоном):
SELECT room_id FROM table3 WHERE room_number LIKE '3%';


P.S.


1. Часть материала про join`ы взята из статьи MySQL немного о JOIN'ах.
2. Задача встретилась на одном из собеседований, которые я проходил. Она достаточно синтетическая, но хорошо подходит для описания материала.
3. Описания конструкций операторов намеренно упрощены для более лёгкого восприятия новичками. Для всех остальных есть Справочное руководство по MySQL
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 42

    +9
    а) это совсем уже азы, которые тысячу раз переписанные
    б) неправильная у вас связка: комната и человек — это атомарные сущности (в примере). телефоны уникальны и закрепляются за комнатой и человеком, поэтому именно таблица телефонов должна содержать айдишники человека и комнаты. phoneid излишнее, так как номер телефона и без того уникален.
      +1
      Ну, теоретически наверное телефон может быть параллельным или просто «висеть» на нескольких людях (и у человека может быть несколько номеров, например городской + внутренний + мобильный и т.д.). Тогда получаем вообще M:N связь с промежуточной таблицей, на которой и тренируем навыки JOIN'инга.

      В остальном согласен, унылая статья получилась
        +4
        Для тех, кто знаком с SQL хотя бы поверхностно, статья кажется унылой. Но судя по тому, что статью добавляют в избранное, то такие статьи «для начинающих» кому-то интересны. Может пора открыть на хабре блог «Для новичков»? Наверняка ведь есть темы, в которых и Вы новичок.
          0
          а вот это очень хорошая задумка. с таким рейтингом хабра можно было бы получать большинство переходов по нубовым статьям именно на хабр
            +1
            Предлагаете туда постить все, что уже есть в мануалах?
              +1
              Редкий новичок читает мануалы. Увы, но мало у кого сейчас есть рефлекс «Не знаешь — погугли» =(
                +1
                Тем более, зачем статья на Хабре, если гуглить не умеешь? Или надо время от времени одно и то же постить, чтобы новички обнаружили статью в списке новых и наконец-то прочитали?
                  0
                  мануалы хороши их коментами (как пример тот же пхп или мускуль) ибо мануал реальными примерами убог
                  0
                  Не обязательно. Например, человек не знаком с Java Script, но очень хочет с ним познакомиться. Лично у меня сразу возникает куча вопросов: где посмотреть синтаксис языка, где прочитать про тонкости и нюансы, какую IDE использовать, как отлаживать, какие типичные ошибки совершают новички и как пишут профессионалы, где применим язык и тд и тп. Конечно, можно самому рыть по интернетам (что несомненно очень полезно для новичка), но как сказал чуть выше romy4, благодаря рейтингу Хабра, люди, которые ищут статьи для новичков будут находить их именно на Хабре. А в этих статьях такие же новички или может даже профессионалы будут делиться опытом, а также рассказывать о подводных камнях, плюсах и минусах и так далее.
                    0
                    Вы тут видите тонкости и нюансы? Основы легко гуглятся, это не проблема. Тот же javascript.ru уже содержит все, что нужно.

                    Понимаете, статьи для новичков это полезно, это здорово! Но ведь они должны содержать что-то новое, а не переписанное содержимое мануалов. Иначе в комментах самым полезным будет что-нить типа RTFM
                      0
                      Согласен с Вами. Скорее всего данная статья действительно не претендует на полноценную статью. Но ведь есть статьи, которые достойны прочтения.
                        0
                        ньюансы есть. те же индексы. зачем они, как они и почему о них забывают. в мануалах пока прочитаешь об этом, то будет поздно (для дела поздно). а этому надо изначально обучать
                          0
                          Так напишите об индексах, о производительности и оптимизации! Это будет интересно, полезно. По аналогии с PHP — все норовят описать установку PHP+MySQL+Apache, но никто не стремится рассказать о тонкостях конфигурации, настройках безопасности и т.д.

                          Статья, даже если она для новичков, должна быть актуальной и полезной.
                            0
                            на хабре уже были статьи об индексах, по оптимизации производительности, и повторяться не очень хотелось бы. А вот для нубов слепить годный пример было бы хорошо.
                            только куда постить такой цикл статей? можно было бы рассказать и показать на реальном проекте с нуля.

                              +1
                              Реальный проект новичок не поймёт. В этом вся проблема, поэтому и в институтах до сих пор на первом курсе на синтетических примерах учат. Реальный проект это advanced уровень, по нему нельзя научиться, по нему можно лишь повысить квалификацию.
                              Даже в маленьких проектах используется сложный код.
                                +1
                                поверьте, можно разжевать даже для нубов и сложный проект. надо только время и терпение.
                                0
                                Пишите в SQL или MySQL, это не проблема, ИМХО.
                                  0
                                  про чисто mysql оптимизации я не буду писать, такие статьи есть. об этом много писалось. я говорю про писание проекта с нуля и разжевывание всех мелочей: почему выбрано то, а не другое, и что будет, если поступить так-то.
                        0
                        Вы и правы и нет. Как пример: некоторое время назад присматривал книгу из серии «PHP для чайников», так многие из них, ещё во введении ссылались на примеры с массивами, объектами и прочими прелестями, чего, увы, я не могу назвать «азами для чайников».

                        Вы можете сказать что такого рода книжки — не мануал, но уж поверьте, многие существующие мануалы выглядят ещё сложнее для полных новичков.
                    –1
                    Эти азы конечно переписаны тысячи раз и книжек по sql тоже море. Тут не поспоришь. Но основа статьи была в том, что надо сесть за консоль, открыть эту станицу и начать вбивать код (не зря здесь соотношение код/текст где-то 1/3), что способствует большей усвояемости. Человек во время обучения видит задачу, которую может решить.
                    Ну как я и сказал, пример синтетический. Если приводить реальный, то запрос мог получиться сложнее. На мой взгляд 2 join`а это и так много для человека, который их впервый раз увидел.

                    Мне всегда легче училось на примерах и задачах и не так чтобы они были только в конце главы, а встречались в тексте повсеместно, поэтому решил написать именно в таком стиле.
                      +2
                      Хотя бы учите правильно. Int(5) не означает, что это поле длиной 5 знаков. «Размер» целочисленного поля не влияет на размерность значения, это по сути метаданные.

                      Вообще, если ставите задачу сформировать учебник для начинающих, пишите отдельные подробные статьи по операторам (сперва SELECT, наверное даже в нескольких частях, потом INSERT, UPDATE, DELETE и т.д.). У Вас сейчас в статье полная каша.
                        –1
                        Почему сперва SELECT? Что будет выбирать читатель и откуда? Или к статье прилагать дамп на готовую БД?
                        То что Вы предлагает это обычный учебник, коих много. Как я писал и выше и ниже, цель была не в этом. Подразумевалось что-то вроде «SQL за 30 минут» :D
                        Про Int(5) спасибо, исправлю, видимо где-то неправильно прочитал, да так и осталось в голове.
                        0
                        мануал тоже учит в консоли и тоже примеры там весьма синтетически.

                        вот если учить азам и при этом писать большой проект — это была бы весьма правильная идея.
                        +2
                        Надо уметь читать между строк.
                        Цель поста не научить тому, что есть в любой книге по SQL.
                        Цель — получить инвайт на хабр.

                        P.S. Краткая инструкция:
                        Берём учебник, открываем любую главу — пишем пост на хабр, получаем инвайт.
                          0
                          Спорить не буду. Инвайт тоже хотелось. Но и писать фигню я сюда не собирался. Более того никто не заставлял меня эту статью публиковать после получения инвайта. Так что наезд немного сомнительный.

                          Вот мне по работе вдруг понадобилось узнать основы чего либо (perl, sql, настройки апача или нгинкса). Возникает логичный вопрос. Что делать? Открывать man по апачу или найти готовый конфиг с комментариями и по аналогии быстренько сваять свой. Всегда стоит оценивать время потраченное на обучение и частоту использования полученных знаний.
                            0
                            чёт мне совесть не позволяет так делать. а вот если б был блог «для нубов», я бы с удовольствием туда писал. мой опыт обучения програмингу позволяет хорошо объяснять и делать это на примерах из жизни
                          0
                          У вас нет пользователя с ником quz.
                          Чем хуже/лучше выборка вида
                          select room_number from table3
                          where phone_id in (
                          select phone_id from table2 where user_id in (
                          select user_id from table1 where username = 'quz'))
                            0
                            Да с quz ошибся. Поправил должно было быть qux.
                            Подзапросы аналогичны только INNER JOIN`ам. Т.е. если подзапрос вернёт пустой результат, то и общий результат тоже будет пустым.
                            У mysql есть внутренние механизмы оптимизации join`ов (не совсем честное замечание, так как статья по sql а не СУБД, поэтому всё можем меняться от версии к версии и от ПО к ПО).

                            Ну и не кажется ли Вам что с JOIN`ом запрос читается легче и выглядит короче ;)

                            Ну и всё надо смотреть от ситуации. На такой маленькой таблице скорость не проверить, но если есть желание, можно добавить туда побольше данных и посмотреть что нам скажет explain.
                              0
                              Ещё quuz остался.

                              Не совсем понял про не совсем честное замечание. Если вы про мой пост, то это не замечание а вопрос.

                              Я не так часто сталкиваюсь с такими выборками(может по этому подзапросы для меня проще), потому и спрашиваю разницу.
                                0
                                quuz добавляется в запросе «INSERT INTO table1 (username) VALUE ('quuz');», для того чтобы показать разницу между INNER JOIN и LEFT JOIN.
                                Моё замечание нечестное. Нельзя оперировать понятием производительности отдельно от СУБД, т.е. на разных системах (MySQL, PostgresSQL, Oracle), преимущества по производительности могут колебаться как в одну так и в другую сторону.
                            0
                            Не очень понял смысл поста — почему нельзя взять книжку Грабера «Понимание SQL» и прочитать? Она доступна и в электронном виде, и в виде туалетного формата (бумажной книжки) за совсем недорого…
                            Ну или гуглить по «Краткий курс SQL», википедию глянуть, в конце концов.
                              0
                              В википедии обычно команды даются бес связных примеров.
                              Погуглил. На интуите нужен аккаунт, а он не у всех есть. Другой краткий курс больше чем моя статья и в нём есть вещи, которых я намерено избегал дабы до максимума упростить статью.
                              Про книги отдельный разговор. Попробуйте в гугле вбить «книги по SQL». Какую из всех полученных Вы будете качать? Я вот не знаю. Но за «Понимание SQL» спасибо, почитаю.
                                0
                                Одна из вещей, которая связана с SQL и очень не нравится новичкам, привыкшим к разжевыванию и пошаговому восприятию — то, что его нужно изучать и понимать (грокать :) большими дозами.
                                SQL как пиво — менее полулитра не дают нужных вкусовых ощущений. :)
                                Продолжайте писать статьи, но лучше о чем-нибудь своем, выстраданном. Например, меня в связи с хостингом всегда интересовал вопрос — как управляют нагрузкой на SQL-базу на shared-хостинге.

                                Ведь любой пользователь при небольшом старании может написать запрос,
                                которое будет «лупить» прямые произведения поверх CTE и погонять неоптимальными джойнами, в результате чего резко вырастет потребление ЦПУ или дискового IO или всего вместе. Пользуются ли хостеры какими-нибудь средствами, позволяющими отследить жадных до ЦПУ/ диска пользователей и понизить им приоритет или еще как-то порешать ситуацию?
                              0
                              Уважаемый автор, у меня дежа вю. Второй раз за неделю задаю один и тот же вопрос. Какую цель Вы преследовали при написании этой статьи? Это не руководство для начинающих, потому что не дано даже элементарное понятие, что такое база данных, зачем и когда она нужна. Не дано даже описание синтаксиса основных операторов SQL, просто какие-то частные примеры, причем не слишком показательные
                              И по-существу. А почему у вас в таблицах в роле ключей одни суррогаты? Зачем нужны room_id и phone_id, если в Вашей предметной области не может быть двух одинаковых номеров комнат, а одинаковых номеров телефонов не может быть в природе?
                                0
                                Я уже тут так много отвечал на вопрос зачем, что немного устал. Я честно думал, что статья будет полезной. Комментарии показывают обратное. Могу принести только свои извинения за то, что потратил Ваше время (это искренне, без сарказма). Все замечания приму к сведению и когда буду писать в следующий раз (не обязательно по этой же теме) постараюсь не допускать тех же ошибок.
                                Ещё раз повторюсь, что пример синтетический.
                                  +1
                                  Я искренне верю, что Ваши намерения были благородны. Но статьи такого рода не полезны, а скорее даже вредны для начинающих. Объясню почему. Вы пытаетесь ввести читателя в основы языка запросов к реляционным базам данных, но предварительно не даете ему никакого понимания основ самих БД и сразу переходите к таблицам. В связи с этим у начинающего возникнет совершенно неверное представление о проектировании баз данных как таковом. Это как заставлять ученика сначала написать пару-тройку сочинений, а потом учить правилам русского языка. Вы, например, используете оператор JOIN, но при этом молчите о том, что он из себя представляет (на уровне реляционной алгебры), когда его можно использовать, когда нужно, а когда категорически нельзя. В итоге читатель, начинающий изучение баз данных, возьмет на вооружение так называемый «практический» подход и будет создавать БД без понимания своих действий, по шаблону. Это не говоря уже о том, что в Вашем примере допущены такие ошибки проектирования, как ненужные суррогатные ключи, которые тоже вызывают привыкание у новичков.
                                  Простите, если выразился слишком резко, но подобный подход к изучению и его результаты приходится видеть уж слишком часто.
                                    0
                                    Могу по личному опыты сказать, что в 90% случае «индексов много не бывает». Опыт основан на работе в хостинговой компании и оценке работы запросов клиентов пользующихся виртуальным хостингом.

                                    А теперь представьте что данный ман нужен Вам не для того, чтобы начать писать свой код. Было бы как минимум странно если бы Вы решили что можно полноценно учиться на данный статье. А для того, чтобы понять чужой код, хоть в какой-то мере. Например, Вы администрируете сервер и у Вас включены логи медленных запросов. Вам необходимо понятно в какой базе/таблице/поле находится узкое место (напомню что стандартно в логах медленных запросов пишется только пользователь под которым этот запрос выполнялся, но не пишется база).

                                    Поэтому, как я писал выше AgentSmith`у: «всегда стоит оценивать время потраченное на обучение и частоту использования полученных знаний. „

                                    Но в целом Вы, наверное, правы.
                                      0
                                      Для грамотно построенной базы и корректно составленных запросов такие индексы не нужны. В Вашем примере не нужны уж точно.
                                      И AgentSmith конечно прав, но ключевым моментом является понимание чужого кода. А понять чужой код можно только если понимаешь свой. Я на собственном опыте неоднократно убеждался, что невозможно понять, почему один запрос работает быстро, а другой до китайской пасхи, если не понимаешь, как СУБД манипулирует реляционными данными, т.е. как SQL-запрос превращается в выражение реляционной алгебры.
                                      Поэтому если админ нашел узкое место по логам, лучше ему направить эту проблему к специалисту по БД, а не пытаться понять проблему на основании руководств для начинающих
                                        0
                                        Вы меня не правильно поняли. Я же не говорил исправлять после этого запрос. Я сказал просто найти. Более того, медленные запросы, это просто пример.

                                        С каких пор на shared-хостинге появились грамотные базы, запросы и сайты? Большинство из них на готовых CSM, которые не могут предугадать всех моментов. А часть написана школьником Васей между уроков.

                                        Чтобы читать книги не обязательно знать грамматику. Чтобы понять код не обязательно знать как устроен компилятор.
                                          0
                                          > С каких пор на shared-хостинге появились грамотные базы, запросы и сайты?
                                          Согласен. Я имел ввиду, что не надо подобные примеры «плохого тона» вставлять в обучающие примеры, новички подумают, что так и надо.
                                          Но чтобы читать книгу, обязательно знать грамматику. Для этого русский язык в школьной программе. И чтобы понять код, действительно понять, нужно иметь представление о том, как он будет выполняться. Практика всегда должна основываться на твердом знании теории, таково мое мнение
                                  0
                                  Еще могу добавить, что уж раз у нас поля не field1, field2, то и таблицы можно было осмысленно назвать. Начитается нуб такого, а потом будет делать database1 с таблицами table1, table2 и т.д.
                                    0
                                    Да база в принципе отвратительна. Из определения таблиц даже непонятно, приписан телефон к комнате или к человеку, или он вообще в вакууме висит

                                Only users with full accounts can post comments. Log in, please.