Участник
Пользователь
- Сообщения
- 496
- Реакции
- 621
- Помог
- 16 раз(а)
Если Вы, уважаемый читатель, держали сервер, то скорее всего слышали такое выражение как "база данных". И даже заполняли данные от неё в настройках бансистемы/army ranks/различных модов. Логин, пароль, имя, адрес и.т.п.
Что это такое интуитивно понятно из названия - некое место вне сервера, где хранятся данные. Огромный массив информации, содержащий нужные сведения в табличном виде.
В определённое время сервер запрашивает базу, там ему посылает ответ. Или же сервер записывает в базу свежие данные. Рассмотрим на примере AES. Игрок заходит на сервер, а вся инфа по моду о нём лежит в базе. Сервер не знает, сколько у игрока бонусов, какое звание. Он посылает к базе запрос "ко мне ломится человек с таким-то SteamID, что это за один?" База отвечает "Да это же старый знакомый! 15000 опыта и 20 бонусов". Игрок заходит и сервер ему говорит "привет, Вася! Вот твой опыт, звания и бонусы."
Базы данных нужны чтобы:
1) Не перегружать сервер. Процессор сейчас стоит хороших денег.
2) Ценные данные не зависели от сервера. Представим, что сервер перезагрузился и весь ваш опыт пропал. Или хостинг задурил. Или Вы случайно удалили что-то нужное.
3) Быстро работать с большими массивами данных. Вот представим, что за полгода сервер посетило 300 000 разных игроков. Мы каждого записали. Заходит кто-то из них поиграть. Что надо сделать? Надо быстро о нём найти информацию: кто это, не в бане ли, сколько опыта и.т.п.
4) Централизованного хранения информации из разных источников. Например, общего бан-листа и статы для нескольких игровых серверов.
База сделает это быстрее за счёт структуры и специального языка для работы с данными - SQL.
Программист видит базу и управляет ею при помощи специального инструмента под общим названием СУБД(Система Управления Базой Данных). HLDS работает с СУБД под названием MySQL.
Зачем нам знать SQL? Ну живёт база сама по себе - и ради бога.
Можно и не знать, спору нет. Но иногда нам надо подредактировать опыт игрока, разбанить побыстрее, удалить какую-то таблицу в базе, что-то оптимизировать, собрать статистику. Например, неужели неинтересно узнать сколько людей имеют больше 100 опыта и последний раз заходили хотя бы позавчера? Там подсчитаем примерное число постоянных игроков.
Статья называется чересчур громко, признаю. Ну что за основы за такой объём текста? Тем не менее я попытаюсь рассказать самое важное, среднему админу вполне хватит. Если же Вы, читатель, хотите ознакомиться с SQL поглубже, рекомендую труд Мартина Грабера "Введение в SQL".
База данных AES(на примере AES 0.5.7, Sonyx fork) предельно проста. Всего лишь одна маленькая табличка. В ней несколько колонок и много-много строк.
Для учебных целей мною создана таблица aes_test с 10 записями. В Adminer (это максимально облегчённый инструмент администрирования, поддерживающий все популярные СУБД) выглядит так
Колонки правильно называются "Поля", в дальнейшем я использую именно это выражение.
Итак, какие у нас поля?
Ниже под спойлерами краткий обзор основных операторов с примерами.
Таблица делается при помощи оператора CREATE TABLE. В общем виде синтаксис таков:
Этот запрос создаёт таблицу для AES
IF NOT EXISTS - условие.
id, name, steamid, ip, exp, bonus_count, last_update - поля.
int(11), varchar(32), varchar(30), varchar(16), float, timestamp - типы полей. Ниже приведу самые распространённые.
NOT NULL, AUTO_INCREMENT, DEFAULT,CURRENT_TIMESTAMP - дополнительные параметры полей.
PRIMARY KEY, INDEX - особые параметры.
Разберём по порядку.
CREATE TABLE создаёт таблицу.
IF NOT EXISTS указывает, что таблица будет создаваться в том случае, если не создана ранее. Можно условие не указывать, но тогда при повторном выполнении запроса выйдет ошибка (1050): Table 'aes_test' already exists.
NOT NULL - значение этого поля не может быть равным NULL.
AUTO_INCREMENT - с каждой новой записью значение поля увеличивается на 1.
DEFAULT '0.0' устанавливает значение по умолчанию. При создании новой записи в этом поле будет стоять не пустота, а число 0.0
PRIMARY KEY (`id`), - поле id будет первичным ключом. Именно по этой причине его сделали автоинкрементным(`id` int(11) NOT NULL AUTO_INCREMENT), таким методом каждая новая запись становится уникальной. Нет в таблице 2 одинаковых id.
CURRENT_TIMESTAMP - текущее время.
INDEX (`steamid`) - поле steamid индексируется, что увеличивают скорость поиска именно по этому полю. У вас, читатель, статистика скорее всего ведётся по steamid и типичные обращения сервера к базе имеют вид "SELECT * FROM aes_test WHERE STEAMID IS 'такой-то' ".
INSERT INTO или просто INSERT (INTO можно опустить) вносит запись.
Синтаксис:
Добавим нового игрока в таблицу
Обратите внимание, что имена, даты, значения со знаками препинания следует указывать в кавычках. В противном случае строка может не вставиться или вставится с некорректными значениями.
Ок, а что если мы хотим записать в строку не всё, а только 2 значения? Например, имя и steamid
В этом случае надо перечислить поля, в которые пойдёт запись.
Синтаксис:
Обратите внимание, что мы вставляли вроде как 2 значения, а внеслось всё кроме ip. Как так?
Благодаря структуре таблицы.
Поле id автоинкрементное. Запись добавили и оно автоматом внесло значение.
`id` int(11) NOT NULL AUTO_INCREMENT
У полей exp, bonus_count значения по умолчанию тоже проставлены. Нули.
`exp` float NOT NULL DEFAULT '0.0',
`bonus_count` int(11) NOT NULL DEFAULT '0',
last_update берёт текущую дату и время.
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
А вот ip не имеет значения по умолчанию, посему остался пустым.
Как вы думаете, читатель, что будет если я попытаюсь внести запись с уже существующим id?
Запрос вернёт ошибку
(1062): Duplicate entry '12' for key 'PRIMARY'
Всё из-за директивы PRIMARY KEY (`id`),
Первичный ключ ВСЕГДА УНИКАЛЕН. Используется для придания строке уникальности. Обычно по первичным ключам таблицы связываются друг с другом, ведётся поиск, сопоставления. Конечно если таблица одна то можно обойтись и без него, но это уже дурной тон и плохой задел на будущее.
Вносить правки позволяет UPDATE.
Синтаксис:
Прибавим игрокам клана "A-Team | " по 10 бонусов
Что в итоге получилось?
Добавление новых полей, удаление существующих, изменение типов и.т.д. осуществляет оператор ALTER TABLE.
Добавления поля:
Добавим некое числовое поле, заполним нулями и выведем результат. Допустим, мы там в будущем будем хранить число монет каждого игрока.
Изменение типа поля:
Изменим название поля Coins на Coins2 и тип на VARCHAR(20). Значение NULL запретим.
Выведем результат.
Структура таблицы после выполнения
Удалим все записи, где опыта меньше чем 10000, но больше чем 5000.
Это была запись
Итог удаления
Пропал игрок с id=11
Часто нужно удалить таблицу. Достаточно одной команды
2) У кого из игроков имеется префикс noob в нике?
3) Сколько игроков заходило последний раз больше 1 дня назад и имеет 0 опыта? То есть сколько ко мне зашло на сервер и сразу вышло. Отсортировать по дате захода. Сегодняшний день я в расчёт не беру, мало ли человек как раз сейчас играет.
4) Сколько опыта в среднем у постояльцев?
5) Есть ли в базе совпадения по ip? Если есть, то по каким игрокам и сколько?
6) Топ-10 игроков по числу бонусов.
7) Сколько опыта приходится на 1 бонус у топ-20 игроков по бонусам?
8) Добавить всем игрокам, у которых менее 1000 опыта, по 10 бонусов
9) Переименовать игроков с именами из 4 букв на "Dude"
10) Переделать клан-тэг 'A-Team | 'на 'B-Team | '
11) Удалить игроков с 0 опытом
12) Добавить своего кореша Васю(STEAMID = 'STEAM_0:0:2678275312'), дать 50000 опыта и 200 бонусов.
На этом всё. К сожалению, многое пришлось опустить, так как невозможно в 2 словах рассказать рассказать в пределах обзора основных команд. За бортом остались даты, приведение типов, работа с несколькими таблицами, особое значение NULL и многое другое. Всё это потихоньку дополню позже, ибо среднестатистическому владельцу сервера вполне достаточно написанного.
В планах - часть 2. JOIN(inner/outer), DATA, CAST.
Конструктивная критика приветствуется.
Все права на статью принадлежат Dev-CS.ru TEAM. При копировании материала активная ссылка обязательна.
Основы SQL Часть 2.
Основы SQL Часть 3.
Что это такое интуитивно понятно из названия - некое место вне сервера, где хранятся данные. Огромный массив информации, содержащий нужные сведения в табличном виде.
В определённое время сервер запрашивает базу, там ему посылает ответ. Или же сервер записывает в базу свежие данные. Рассмотрим на примере AES. Игрок заходит на сервер, а вся инфа по моду о нём лежит в базе. Сервер не знает, сколько у игрока бонусов, какое звание. Он посылает к базе запрос "ко мне ломится человек с таким-то SteamID, что это за один?" База отвечает "Да это же старый знакомый! 15000 опыта и 20 бонусов". Игрок заходит и сервер ему говорит "привет, Вася! Вот твой опыт, звания и бонусы."
Базы данных нужны чтобы:
1) Не перегружать сервер. Процессор сейчас стоит хороших денег.
2) Ценные данные не зависели от сервера. Представим, что сервер перезагрузился и весь ваш опыт пропал. Или хостинг задурил. Или Вы случайно удалили что-то нужное.
3) Быстро работать с большими массивами данных. Вот представим, что за полгода сервер посетило 300 000 разных игроков. Мы каждого записали. Заходит кто-то из них поиграть. Что надо сделать? Надо быстро о нём найти информацию: кто это, не в бане ли, сколько опыта и.т.п.
4) Централизованного хранения информации из разных источников. Например, общего бан-листа и статы для нескольких игровых серверов.
База сделает это быстрее за счёт структуры и специального языка для работы с данными - SQL.
Программист видит базу и управляет ею при помощи специального инструмента под общим названием СУБД(Система Управления Базой Данных). HLDS работает с СУБД под названием MySQL.
Зачем нам знать SQL? Ну живёт база сама по себе - и ради бога.
Можно и не знать, спору нет. Но иногда нам надо подредактировать опыт игрока, разбанить побыстрее, удалить какую-то таблицу в базе, что-то оптимизировать, собрать статистику. Например, неужели неинтересно узнать сколько людей имеют больше 100 опыта и последний раз заходили хотя бы позавчера? Там подсчитаем примерное число постоянных игроков.
Статья называется чересчур громко, признаю. Ну что за основы за такой объём текста? Тем не менее я попытаюсь рассказать самое важное, среднему админу вполне хватит. Если же Вы, читатель, хотите ознакомиться с SQL поглубже, рекомендую труд Мартина Грабера "Введение в SQL".
Работа с одной таблицей
База данных AES(на примере AES 0.5.7, Sonyx fork) предельно проста. Всего лишь одна маленькая табличка. В ней несколько колонок и много-много строк.
Для учебных целей мною создана таблица aes_test с 10 записями. В Adminer (это максимально облегчённый инструмент администрирования, поддерживающий все популярные СУБД) выглядит так
Колонки правильно называются "Поля", в дальнейшем я использую именно это выражение.
Итак, какие у нас поля?
- id. Это номер игрока в базе. Идентификатор. Когда новый игрок заносится в базу, ему присваивается некий уникальный id. id идут друг за другом по порядку и не дублируются. В базе нет двух одинаковых id. Если мы только что поставили AES и на сервер зашёл игрок Вовочка, то его id = 1. Затем пришёл Петя. его id = 2. Потом Вася, id = 3. А что если Петя вышел, а через 10 минут снова зашёл? Его id будет 2 или 4? Правильный ответ - 2. Новые id добавляются когда к нам заходит новый игрок. Если же заходит старый, то база просто находит его id из списка. Такое поле ещё называют Первичный ключ или Primary Key. Теоретически у нас могут быть одинаковые id, но подобные ситуации связаны с глюками, ошибками проектирования базы либо неполадками в работе плагинов, что выходит за рамки статьи.
- name. Ник игрока, под которым он последний раз заходи в игру.
- steamid. Его SteamID. Как правило именно по этому параметру база определяет кто есть кто. Таким образом смена игроком SteamID ведёт к тому, что база его не находит и весь накопленный опыт "теряется".
- ip. Последний ip, под которым игрок заходит на сервер.
- exp. Опыт.
- bonus_count. Количество бонусов
- last_update. Последнее обновление. Иными словами, когда игрок последний раз заработал опыт или зашёл на сервер.
Чтение данных, формирование выборок
Ниже под спойлерами краткий обзор основных операторов с примерами.
SELECT позволяет выбрать данные и просто на них посмотреть. Не будет ничего записано, удалено либо изменено
Синтаксис в общем виде:
Полей может быть сколько угодно
Если хотим посмотреть на все поля, то вместо перечисления можно использовать символ *
Синтаксис в общем виде:
SELECT <поле> FROM <таблица>
SELECT id FROM aes_test
вернётПолей может быть сколько угодно
SELECT id, id, name, id FROM aes_test
Если хотим посмотреть на все поля, то вместо перечисления можно использовать символ *
SELECT * FROM aes_test
Позволяет выбрать строки по каким-либо параметрам.
Например, нам надо найти имя игрока, зная его steamid. Конечно для 10 записей может просмотреть всё вручную, но в реальных таблицах число строк доходит до 1-2 миллионов.
Синтаксис SELECT <поле> FROM <таблица> WHERE <условие>
Например, нам надо найти имя игрока, зная его steamid. Конечно для 10 записей может просмотреть всё вручную, но в реальных таблицах число строк доходит до 1-2 миллионов.
SELECT name FROM aes_test WHERE steamid = 'STEAM:0:0:1314847400'
Синтаксис:
Бывают ситуации когда 1 параметра недостаточно и мы ищем по совпадению нескольких. Допустим, не знаем steamid игрока, зато известно что у него 6 опыта.
Но таких двое. Уточняем параметры поиска. Нам говорят, что у товарища 3 бонуса. Используем оператор AND.
Обратите внимание, что должны совпасть ВСЕ условия. Если хотя бы одно не подходит, то запрос ничего не вернёт.
Может быть такое: известно что у игрока ЛИБО более 900 опыта ЛИБО меньше 100. То есть ищем до 100 и от 900.
Противоположный результат достигается использованием BETWEEN..AND. BETWEEN..AND осуществляет поиск в промежутке между 2 значениями.
Найдём между 100 и 900.
Синтаксис SELECT <поле> FROM <таблица> WHERE <условие1> AND <условие2>.....
Бывают ситуации когда 1 параметра недостаточно и мы ищем по совпадению нескольких. Допустим, не знаем steamid игрока, зато известно что у него 6 опыта.
SELECT * FROM aes_test WHERE exp = 6
Но таких двое. Уточняем параметры поиска. Нам говорят, что у товарища 3 бонуса. Используем оператор AND.
SELECT * FROM aes_test WHERE exp = 6 AND bonus_count = 3
Обратите внимание, что должны совпасть ВСЕ условия. Если хотя бы одно не подходит, то запрос ничего не вернёт.
Может быть такое: известно что у игрока ЛИБО более 900 опыта ЛИБО меньше 100. То есть ищем до 100 и от 900.
SELECT * FROM aes_test WHERE exp > 900 OR exp < 100
Противоположный результат достигается использованием BETWEEN..AND. BETWEEN..AND осуществляет поиск в промежутке между 2 значениями.
Найдём между 100 и 900.
SELECT * FROM aes_test WHERE exp BETWEEN 100 AND 900
COUNT подсчитывает число записей(строк).
Синтаксис:
Нам выдало количество строк, по которым последнее посещение больше чем 2018-03-10 19:50:00 и опыта больше 1.
А что это за игроки? Просто убираем COUNT и смотрим подробности.
DISTINCT удаляет точные дубликаты и может содержать только одно поле.
Синтаксис:
Синтаксис:
SELECT COUNT(<поле>) FROM <таблица>
SELECT COUNT(*) FROM aes_test WHERE last_update > '2018-03-10 19:50:00' AND exp > 1
Нам выдало количество строк, по которым последнее посещение больше чем 2018-03-10 19:50:00 и опыта больше 1.
А что это за игроки? Просто убираем COUNT и смотрим подробности.
SELECT * FROM aes_test WHERE last_update > '2018-03-10 19:50:00' AND exp > 1
DISTINCT удаляет точные дубликаты и может содержать только одно поле.
Синтаксис:
SELECT DISTINCT <поле> FROM <таблица>
SELECT DISTINCT last_update FROM aes_test
GROUP BY - Группировка. Обычно используется при вычислении сгруппированных по какому-либо признаку значений либо удаления дублей.
Синтаксис:
Изначально было 2 значения с exp=6, осталось одно. GROUP BY оставляет самое первое, остальное откинет. Обратите внимание на отличие от DISTINCT! У GROUP BY может быть много аргументов и GROUP BY работает с любым числом полей.
Пока что всё просто. Взяли параметр, отсеяли при помощи WHERE и сделали ему GROUP BY.
А что если надо наоборот? Мы СПЕРВА хотим сгруппировать, а ПОТОМ отсеять по сгруппированному полю? WHERE так не умеет.
Вот меня интересует статистика одновременных заходов на сервер. Если в одно время зашло 2 или более игрока - нужно видеть, а если в одно время зашёл только 1 игрок - не нужны в статистике.
Надо сперва сгруппировать строки с одинаковыми датами, подсчитать число строк по каждой дате и потом уже убрать все числа, равные 1.
Здесь поможет HAVING.
Синтаксис:
SELECT last_update, COUNT(last_update) FROM aes_test GROUP BY last_update HAVING COUNT(last_update)>1
Двоих нету. Первый зашёл в 2018-03-10 19:51:52, другой в 2018-03-10 19:50:51. Они не попали, так как зашли одни. А остальные 8 завалились толпой.
WHERE - предусловие. Сперва выполняется WHERE, затем GROUP BY.
HAVING - постусловие. Сперва выполняется GROUP BY, затем HAVING
Синтаксис:
SELECT <поле> FROM <таблица> GROUP BY <поле>
SELECT * FROM aes_test WHERE exp < 600 GROUP BY exp
Изначально было 2 значения с exp=6, осталось одно. GROUP BY оставляет самое первое, остальное откинет. Обратите внимание на отличие от DISTINCT! У GROUP BY может быть много аргументов и GROUP BY работает с любым числом полей.
Пока что всё просто. Взяли параметр, отсеяли при помощи WHERE и сделали ему GROUP BY.
А что если надо наоборот? Мы СПЕРВА хотим сгруппировать, а ПОТОМ отсеять по сгруппированному полю? WHERE так не умеет.
Вот меня интересует статистика одновременных заходов на сервер. Если в одно время зашло 2 или более игрока - нужно видеть, а если в одно время зашёл только 1 игрок - не нужны в статистике.
Надо сперва сгруппировать строки с одинаковыми датами, подсчитать число строк по каждой дате и потом уже убрать все числа, равные 1.
Здесь поможет HAVING.
Синтаксис:
SELECT <поле><поле> FROM <таблица> GROUP BY <поле> HAVING<поле>
SELECT last_update, COUNT(last_update) FROM aes_test GROUP BY last_update HAVING COUNT(last_update)>1
Двоих нету. Первый зашёл в 2018-03-10 19:51:52, другой в 2018-03-10 19:50:51. Они не попали, так как зашли одни. А остальные 8 завалились толпой.
WHERE - предусловие. Сперва выполняется WHERE, затем GROUP BY.
HAVING - постусловие. Сперва выполняется GROUP BY, затем HAVING
SUM - сумма
AVG - среднее значение
MIN - минимальное значение
MAX - максимальное значение
Синтаксис:
Подсчитали сумму опыта у всех игроков.
Довольно часто эти операторы идут рядом с GROUP BY.
Давайте подсчитаем сумму опыта у игроков с одинаковым числом бонусов
А если без GROUP BY?
Раньше запросы наподобие
AVG - среднее значение
MIN - минимальное значение
MAX - максимальное значение
Синтаксис:
SELECT SUM(<поле>) FROM <таблица>
SELECT SUM(exp) FROM aes_test
Подсчитали сумму опыта у всех игроков.
Довольно часто эти операторы идут рядом с GROUP BY.
Давайте подсчитаем сумму опыта у игроков с одинаковым числом бонусов
SELECT SUM(exp),bonus_count FROM aes_test GROUP BY bonus_count
А если без GROUP BY?
Раньше запросы наподобие
SELECT SUM(exp),bonus_count FROM aes_test
выдавали ошибку. SQL принудительно требовал вставить GROUP BY. Современная реализация иная, будет подсчитана сумма опыта по всем строкам и рядом выдана первая строка с бонусами.LIKE используется для поиска значений по шаблону. Ищет записи, которые удовлетворяют определённым условиям.
Синтаксис:
Пример:
Чаще встречаются ситуации когда мы хотим что-то найти по шаблону(например, игроков из одного клана) или просто не зная точной инфы(знаем кусок ника, но не помним как точно пишется).
Для этого придумали шаблоны.
Пример1:
Поиск ищет имена, начинающиеся на A-Team
Пример2:
Ищем имена, состоящие из одного символа. Любого. Нижних подчёркиваний можно делать сколько угодно и в любых местах.
Синтаксис:
SELECT <поле> FROM <таблица> WHERE <поле> LIKE <шаблон>
Пример:
SELECT * FROM aes_test WHERE steamid LIKE 'STEAM_0:0:1314847400'
Чаще встречаются ситуации когда мы хотим что-то найти по шаблону(например, игроков из одного клана) или просто не зная точной инфы(знаем кусок ника, но не помним как точно пишется).
Для этого придумали шаблоны.
% | Строка любой длины | Пример 1 |
_ | Любой одиночный символ | Пример 2 |
SELECT * FROM aes_test WHERE name LIKE 'A-Team%'
Поиск ищет имена, начинающиеся на A-Team
Пример2:
SELECT * FROM aes_test WHERE name LIKE '_'
Ищем имена, состоящие из одного символа. Любого. Нижних подчёркиваний можно делать сколько угодно и в любых местах.
SELECT * FROM aes_test WHERE name LIKE '__u_'
СОЗДАНИЕ ТАБЛИЦЫ
Таблица делается при помощи оператора CREATE TABLE. В общем виде синтаксис таков:
SQL:
CREATE TABLE <условия><имя таблицы> (
<имя поля 1> <тип поля 1> <дополнительные параметры к полю 1>.
<имя поля N> <тип поля N> <дополнительные параметры к полю N>.
<особые параметры>
);
SQL:
CREATE TABLE IF NOT EXISTS `aes_test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`steamid` varchar(30) NOT NULL,
`ip` varchar(16) NOT NULL,
`exp` float NOT NULL DEFAULT '0.0',
`bonus_count` int(11) NOT NULL DEFAULT '0',
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX (`steamid`)
);
id, name, steamid, ip, exp, bonus_count, last_update - поля.
int(11), varchar(32), varchar(30), varchar(16), float, timestamp - типы полей. Ниже приведу самые распространённые.
NOT NULL, AUTO_INCREMENT, DEFAULT,CURRENT_TIMESTAMP - дополнительные параметры полей.
PRIMARY KEY, INDEX - особые параметры.
Разберём по порядку.
CREATE TABLE создаёт таблицу.
IF NOT EXISTS указывает, что таблица будет создаваться в том случае, если не создана ранее. Можно условие не указывать, но тогда при повторном выполнении запроса выйдет ошибка (1050): Table 'aes_test' already exists.
NOT NULL - значение этого поля не может быть равным NULL.
AUTO_INCREMENT - с каждой новой записью значение поля увеличивается на 1.
DEFAULT '0.0' устанавливает значение по умолчанию. При создании новой записи в этом поле будет стоять не пустота, а число 0.0
PRIMARY KEY (`id`), - поле id будет первичным ключом. Именно по этой причине его сделали автоинкрементным(`id` int(11) NOT NULL AUTO_INCREMENT), таким методом каждая новая запись становится уникальной. Нет в таблице 2 одинаковых id.
CURRENT_TIMESTAMP - текущее время.
INDEX (`steamid`) - поле steamid индексируется, что увеличивают скорость поиска именно по этому полю. У вас, читатель, статистика скорее всего ведётся по steamid и типичные обращения сервера к базе имеют вид "SELECT * FROM aes_test WHERE STEAMID IS 'такой-то' ".
Типы данных MySQL
Тип | Расшифровка | Диапазон значений |
TINYINT | Очень малое целое число | [0 ; 255] если число без знака. [-128 ; 127] если число со знаком |
SMALLINT | Малое целое число | [0;65535] если число без знака. [-32768 ; 32767] если число со знаком |
MEDIUMINT | Среднее целое число | [0 ; 16777215] если число без знака. [-8388608 ; 8388607] если число со знаком |
INT или INTEGER | Целое число | [0 ; 4294967295] если число без знака. [-2147483648 ; 2147483647] если число со знаком |
BIGINT | Большое целое число | [0 ; 18446744073709551615] если число без знака. [-9223372036854775808;9223372036854775807] если число со знаком |
FLOAT | Малое число с плавающей точкой. Не может быть числом без знака(UNSIGNED). | [–3.402823466E+38 ; –1.175494351E-38], 0 , [1.175494351E-38 ; 3.402823466E+38] |
DOUBLE, DOUBLE PRECISION, REAL | Число с плавающей запятой. Не может быть числом без знака(UNSIGNED) | [-1.7976931348623157E+308 ; -2.2250738585072014E-308], 0, [2.2250738585072014E-308 ; 1.7976931348623157E+308] |
DECIMAL, NUMERIC | Распакованное число с плавающей запятой | Число хранится в виде строки, используя один символ для каждой цифры. Символы десятичной запятой и отрицательного числа ("-") не учитывается в длину. Диапазон значений такой же, как для DOUBLE |
DATE | Дата. Формат «YYYY-MM-DD» (ГГГГ-ММ-ДД). | [«1000-01-01» ; «9999-12-31»]. |
DATETIME | Дата и время. Формат «YYYY-MM-DD HH:MM:SS» (ГГГГ-ММ-ДД ЧЧ-ММ-СС) | [«1000-01-01 00:00:00» ; «9999-12-31 23:59:59»] |
TIMESTAMP | Дата и время | |
TIME | Время. Формат «HH:MM:SS» | [-838:59:59 ; 838:59:59] |
YEAR | Год в 2-х или 4-х цифровом виде (4 цифры по умолчанию). Формат «YYYY» или «YY» | Если вы используете 4 цифры, то допустимые значения [1901 ; 2155] и 0000. Если 2 цифры, то [70 ; 69] (1970-2069) |
CHAR | Строка фиксированной длины, которая справа дополняется пробелами до указанной длины | Диапазон длины от 1 до 255 символов. Завершающие пробелы удаляются, когда значение извлекается. Значения CHAR сортируются и сравниваются без учета регистра в зависимости от кодировки по умолчанию, если не установлен флаг BINARY. |
VARCHAR | Строка переменной длины. Примечание: конечные пробелы удаляются при сохранении. | Диапазон длины от 1 до 255 символов. Значения VARCHAR сортируются и сравниваются без учета регистра, если не установлен флаг BINARY. |
TINYBLOB, TINYTEXT | BLOB или ТЕХТ с максимальной длиной 255 символов. | |
BLOB, TEXT | BLOB или ТЕХТ с максимальной длиной 65535 символов. | |
MEDIUMBLOB, MEDIUMTEXT | BLOB или ТЕХТ с максимальной длиной 16777215 символов. | |
LONGBLOB, LONGTEXT | BLOB или ТЕХТ с максимальной длиной 4294967295 символов. | |
ENUM | Перечисление | Строка-объект, которая может принимать только одно значение из списка либо NULL. ENUM максимум может иметь 65535 различных значений. |
SET | Набор | Строка-объект, которая может принимать ноль и более значений из списка. SET может иметь максимум 64 варианта значений. |
ВНЕСЕНИЕ ДАННЫХ В ТАБЛИЦУ
INSERT INTO или просто INSERT (INTO можно опустить) вносит запись.
Синтаксис:
INSERT <таблица> VALUES (<значение1>,<значение 2> ...);
Добавим нового игрока в таблицу
INSERT aes_test VALUES (11,'Индржих','STEAM_5:0:2051075304','195.54.137.90',5600,18,'2018-03-15 11:34:06');
Обратите внимание, что имена, даты, значения со знаками препинания следует указывать в кавычках. В противном случае строка может не вставиться или вставится с некорректными значениями.
Ок, а что если мы хотим записать в строку не всё, а только 2 значения? Например, имя и steamid
В этом случае надо перечислить поля, в которые пойдёт запись.
Синтаксис:
INSERT <таблица>(<поле 1>,<поле 2>...<поле N>) VALUES (<значение поля 1>,<значение поля 2> ... <значение поля N>);
INSERT aes_test(name,staemid) VALUES ('krot','STEAM_0:0:6201077304');
Обратите внимание, что мы вставляли вроде как 2 значения, а внеслось всё кроме ip. Как так?
Благодаря структуре таблицы.
Поле id автоинкрементное. Запись добавили и оно автоматом внесло значение.
`id` int(11) NOT NULL AUTO_INCREMENT
У полей exp, bonus_count значения по умолчанию тоже проставлены. Нули.
`exp` float NOT NULL DEFAULT '0.0',
`bonus_count` int(11) NOT NULL DEFAULT '0',
last_update берёт текущую дату и время.
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
А вот ip не имеет значения по умолчанию, посему остался пустым.
Как вы думаете, читатель, что будет если я попытаюсь внести запись с уже существующим id?
INSERT aes_test(id,steamid) VALUES ('12','STEAM_0:0:6201077304');
Запрос вернёт ошибку
(1062): Duplicate entry '12' for key 'PRIMARY'
Всё из-за директивы PRIMARY KEY (`id`),
Первичный ключ ВСЕГДА УНИКАЛЕН. Используется для придания строке уникальности. Обычно по первичным ключам таблицы связываются друг с другом, ведётся поиск, сопоставления. Конечно если таблица одна то можно обойтись и без него, но это уже дурной тон и плохой задел на будущее.
ИЗМЕНЕНИЕ ДАННЫХ
Вносить правки позволяет UPDATE.
Синтаксис:
UPDATE <таблица> SET <выражение> WHERE <условие>;
Прибавим игрокам клана "A-Team | " по 10 бонусов
UPDATE aes_test SET bonus_count = bonus_count + 10 WHERE name LIKE 'A-Team%'
Что в итоге получилось?
SELECT * FROM aes_test WHERE name LIKE 'A-Team%'
ИЗМЕНЕНИЕ СТРУКТУРЫ ТАБЛИЦЫ
Добавление новых полей, удаление существующих, изменение типов и.т.д. осуществляет оператор ALTER TABLE.
Добавления поля:
ALTER TABLE <таблица> ADD <имя поля> <тип поля>
Добавим некое числовое поле, заполним нулями и выведем результат. Допустим, мы там в будущем будем хранить число монет каждого игрока.
ALTER TABLE aes_test ADD Coins INT DEFAULT '0'
SELECT * FROM aes_test
Изменение типа поля:
ALTER TABLE <таблица> CHANGE COLUMN <имя поля> < новое имя поля> <тип поля>
Изменим название поля Coins на Coins2 и тип на VARCHAR(20). Значение NULL запретим.
Выведем результат.
ALTER TABLE aes_test CHANGE COLUMN Coins CoinsNew VARCHAR(20) NOT NULL
Структура таблицы после выполнения
УДАЛЕНИЕ ДАННЫХ
DELETE FROM <таблица> WHERE <условие>
удалит строки по заданными условиям.Удалим все записи, где опыта меньше чем 10000, но больше чем 5000.
DELETE FROM aes_test WHERE exp BETWEEN 5000 AND 10000
Это была запись
SELECT * FROM aes_test WHERE exp BETWEEN 5000 AND 10000
Итог удаления
Пропал игрок с id=11
Часто нужно удалить таблицу. Достаточно одной команды
DROP TABLE <название таблицы>
DROP TABLE aes_test
удалит нашу тестовую таблицу полностью без возможности восстановления.Примеры типичных запросов
1) Сколько у нас игроков заходило хотя бы раз за последнюю неделю и набрало больше 300 опыта? Условно это постояльцы.SELECT COUNT(*) FROM aes_stats WHERE last_update > DATE_ADD(CURDATE(), INTERVAL -7 DAY) AND exp > 300;
2) У кого из игроков имеется префикс noob в нике?
SELECT * FROM aes_stats WHERE name LIKE 'NOOB%'
3) Сколько игроков заходило последний раз больше 1 дня назад и имеет 0 опыта? То есть сколько ко мне зашло на сервер и сразу вышло. Отсортировать по дате захода. Сегодняшний день я в расчёт не беру, мало ли человек как раз сейчас играет.
SELECT * FROM aes_stats WHERE last_update < CURDATE() AND exp = 0 ORDER BY last_update DESC
4) Сколько опыта в среднем у постояльцев?
SELECT AVG(exp) FROM aes_stats WHERE last_update > DATE_ADD(CURDATE(), INTERVAL -7 DAY) AND exp > 300;
5) Есть ли в базе совпадения по ip? Если есть, то по каким игрокам и сколько?
SELECT ip, name, steamid, COUNT(ip) FROM aes_stats GROUP BY ip HAVING COUNT(ip)>1
6) Топ-10 игроков по числу бонусов.
SELECT * FROM aes_stats ORDER BY exp DESC LIMIT 10
7) Сколько опыта приходится на 1 бонус у топ-20 игроков по бонусам?
SELECT exp, bonus_count, exp/bonus_count FROM aes_stats ORDER BY bonus_count DESC LIMIT 20
8) Добавить всем игрокам, у которых менее 1000 опыта, по 10 бонусов
UPDATE aes_test SET bonus_count = bonus_count + 10 WHERE exp < 1000
9) Переименовать игроков с именами из 4 букв на "Dude"
UPDATE aes_test SET name = 'DUDE' WHERE name LIKE '____'
10) Переделать клан-тэг 'A-Team | 'на 'B-Team | '
UPDATE aes_test SET name = 'B_TEAM |' WHERE name LIKE 'A-Team | %'
11) Удалить игроков с 0 опытом
DELETE FROM aes_test WHERE exp = 0
12) Добавить своего кореша Васю(STEAMID = 'STEAM_0:0:2678275312'), дать 50000 опыта и 200 бонусов.
INSERT aes_test(name,exp,bonus_count,steamid) VALUES ('Вася',50000,200,'STEAM_3:0:2030175304')
На этом всё. К сожалению, многое пришлось опустить, так как невозможно в 2 словах рассказать рассказать в пределах обзора основных команд. За бортом остались даты, приведение типов, работа с несколькими таблицами, особое значение NULL и многое другое. Всё это потихоньку дополню позже, ибо среднестатистическому владельцу сервера вполне достаточно написанного.
В планах - часть 2. JOIN(inner/outer), DATA, CAST.
Конструктивная критика приветствуется.
Все права на статью принадлежат Dev-CS.ru TEAM. При копировании материала активная ссылка обязательна.
Основы SQL Часть 2.
Основы SQL Часть 3.
Последнее редактирование модератором: