Основы SQL. Часть 1.

Сообщения
496
Реакции
618
Помог
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 (это максимально облегчённый инструмент администрирования, поддерживающий все популярные СУБД) выглядит так

b4.png

Колонки правильно называются "Поля", в дальнейшем я использую именно это выражение.
Итак, какие у нас поля?
  1. id. Это номер игрока в базе. Идентификатор. Когда новый игрок заносится в базу, ему присваивается некий уникальный id. id идут друг за другом по порядку и не дублируются. В базе нет двух одинаковых id. Если мы только что поставили AES и на сервер зашёл игрок Вовочка, то его id = 1. Затем пришёл Петя. его id = 2. Потом Вася, id = 3. А что если Петя вышел, а через 10 минут снова зашёл? Его id будет 2 или 4? Правильный ответ - 2. Новые id добавляются когда к нам заходит новый игрок. Если же заходит старый, то база просто находит его id из списка. Такое поле ещё называют Первичный ключ или Primary Key. Теоретически у нас могут быть одинаковые id, но подобные ситуации связаны с глюками, ошибками проектирования базы либо неполадками в работе плагинов, что выходит за рамки статьи.
  2. name. Ник игрока, под которым он последний раз заходи в игру.
  3. steamid. Его SteamID. Как правило именно по этому параметру база определяет кто есть кто. Таким образом смена игроком SteamID ведёт к тому, что база его не находит и весь накопленный опыт "теряется".
  4. ip. Последний ip, под которым игрок заходит на сервер.
  5. exp. Опыт.
  6. bonus_count. Количество бонусов
  7. last_update. Последнее обновление. Иными словами, когда игрок последний раз заработал опыт или зашёл на сервер.
Пора учиться писать запросы.

Чтение данных, формирование выборок


Ниже под спойлерами краткий обзор основных операторов с примерами.
SELECT позволяет выбрать данные и просто на них посмотреть. Не будет ничего записано, удалено либо изменено
Синтаксис в общем виде: SELECT <поле> FROM <таблица>

SELECT id FROM aes_test вернёт
b2.png
Полей может быть сколько угодно
SELECT id, id, name, id FROM aes_test
b3.png

Если хотим посмотреть на все поля, то вместо перечисления можно использовать символ *
SELECT * FROM aes_test
b4.png
Ограничивает выводимое число результатов.
Синтакис: SELECT <поле> FROM <таблица> LIMIT число

SELECT * FROM aes_test LIMIT 5
b5.png
Позволяет выбрать строки по каким-либо параметрам.
Синтаксис SELECT <поле> FROM <таблица> WHERE <условие>

Например, нам надо найти имя игрока, зная его steamid. Конечно для 10 записей может просмотреть всё вручную, но в реальных таблицах число строк доходит до 1-2 миллионов.
SELECT name FROM aes_test WHERE steamid = 'STEAM:0:0:1314847400'
b1.png
Синтаксис: Синтаксис SELECT <поле> FROM <таблица> WHERE <условие1> AND <условие2>.....

Бывают ситуации когда 1 параметра недостаточно и мы ищем по совпадению нескольких. Допустим, не знаем steamid игрока, зато известно что у него 6 опыта.
SELECT * FROM aes_test WHERE exp = 6
b6.png

Но таких двое. Уточняем параметры поиска. Нам говорят, что у товарища 3 бонуса. Используем оператор AND.
SELECT * FROM aes_test WHERE exp = 6 AND bonus_count = 3
b7.png
Обратите внимание, что должны совпасть ВСЕ условия. Если хотя бы одно не подходит, то запрос ничего не вернёт.

Может быть такое: известно что у игрока ЛИБО более 900 опыта ЛИБО меньше 100. То есть ищем до 100 и от 900.
SELECT * FROM aes_test WHERE exp > 900 OR exp < 100
b8.png

Противоположный результат достигается использованием BETWEEN..AND. BETWEEN..AND осуществляет поиск в промежутке между 2 значениями.
Найдём между 100 и 900.
SELECT * FROM aes_test WHERE exp BETWEEN 100 AND 900
b9.png
Сортирует результат по определённому полю. Можно в сторону увеличения (ASC) либо уменьшения (DESC).
Синтаксис: SELECT <поле> FROM <таблица> ORDER BY <поле><команда>

SELECT * FROM aes_test ORDER BY id DESC LIMIT 4
b10.png
COUNT подсчитывает число записей(строк).
Синтаксис: SELECT COUNT(<поле>) FROM <таблица>
SELECT COUNT(*) FROM aes_test WHERE last_update > '2018-03-10 19:50:00' AND exp > 1
b13.png
Нам выдало количество строк, по которым последнее посещение больше чем 2018-03-10 19:50:00 и опыта больше 1.
А что это за игроки? Просто убираем COUNT и смотрим подробности.
SELECT * FROM aes_test WHERE last_update > '2018-03-10 19:50:00' AND exp > 1
b14.png

DISTINCT удаляет точные дубликаты и может содержать только одно поле.
Синтаксис: SELECT DISTINCT <поле> FROM <таблица>

SELECT DISTINCT last_update FROM aes_test
b15.png
GROUP BY - Группировка. Обычно используется при вычислении сгруппированных по какому-либо признаку значений либо удаления дублей.
Синтаксис: SELECT <поле> FROM <таблица> GROUP BY <поле>

SELECT * FROM aes_test WHERE exp < 600 GROUP BY exp
b11.png
Изначально было 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
b16.png
Двоих нету. Первый зашёл в 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 - максимальное значение

Синтаксис: SELECT SUM(<поле>) FROM <таблица>

SELECT SUM(exp) FROM aes_test
b12.png
Подсчитали сумму опыта у всех игроков.
Довольно часто эти операторы идут рядом с GROUP BY.
Давайте подсчитаем сумму опыта у игроков с одинаковым числом бонусов
SELECT SUM(exp),bonus_count FROM aes_test GROUP BY bonus_count
w1.png

А если без GROUP BY?
Раньше запросы наподобие SELECT SUM(exp),bonus_count FROM aes_test выдавали ошибку. SQL принудительно требовал вставить GROUP BY. Современная реализация иная, будет подсчитана сумма опыта по всем строкам и рядом выдана первая строка с бонусами.
w2.png
LIKE используется для поиска значений по шаблону. Ищет записи, которые удовлетворяют определённым условиям.
Синтаксис: SELECT <поле> FROM <таблица> WHERE <поле> LIKE <шаблон>

Пример: SELECT * FROM aes_test WHERE steamid LIKE 'STEAM_0:0:1314847400'
w3.png

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


%​



Строка любой длины​



Пример 1​



_​



Любой одиночный символ​



Пример 2​

Пример1: SELECT * FROM aes_test WHERE name LIKE 'A-Team%'













w4.png
Поиск ищет имена, начинающиеся на A-Team

Пример2: SELECT * FROM aes_test WHERE name LIKE '_'
w5.png
Ищем имена, состоящие из одного символа. Любого. Нижних подчёркиваний можно делать сколько угодно и в любых местах.
SELECT * FROM aes_test WHERE name LIKE '__u_'
w6.png


СОЗДАНИЕ ТАБЛИЦЫ

Таблица делается при помощи оператора CREATE TABLE. В общем виде синтаксис таков:

SQL:
                CREATE TABLE  <условия><имя таблицы> (
                    <имя поля 1> <тип поля 1> <дополнительные параметры к полю 1>.
                    <имя поля N> <тип поля N> <дополнительные параметры к полю N>.
                    <особые параметры>
                );
Этот запрос создаёт таблицу для AES

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`)
                );
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 'такой-то' ".

Типы данных 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');
Обратите внимание, что имена, даты, значения со знаками препинания следует указывать в кавычках. В противном случае строка может не вставиться или вставится с некорректными значениями.
w10.png
Ок, а что если мы хотим записать в строку не всё, а только 2 значения? Например, имя и steamid
В этом случае надо перечислить поля, в которые пойдёт запись.
Синтаксис: INSERT <таблица>(<поле 1>,<поле 2>...<поле N>) VALUES (<значение поля 1>,<значение поля 2> ... <значение поля N>);

INSERT aes_test(name,staemid) VALUES ('krot','STEAM_0:0:6201077304');
w11.png
Обратите внимание, что мы вставляли вроде как 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%'
z1.png

ИЗМЕНЕНИЕ СТРУКТУРЫ ТАБЛИЦЫ

Добавление новых полей, удаление существующих, изменение типов и.т.д. осуществляет оператор ALTER TABLE.
Добавления поля: ALTER TABLE <таблица> ADD <имя поля> <тип поля>

Добавим некое числовое поле, заполним нулями и выведем результат. Допустим, мы там в будущем будем хранить число монет каждого игрока.
ALTER TABLE aes_test ADD Coins INT DEFAULT '0'

SELECT * FROM aes_test
z2.png

Изменение типа поля: ALTER TABLE <таблица> CHANGE COLUMN <имя поля> < новое имя поля> <тип поля>
Изменим название поля Coins на Coins2 и тип на VARCHAR(20). Значение NULL запретим.
Выведем результат.
ALTER TABLE aes_test CHANGE COLUMN Coins CoinsNew VARCHAR(20) NOT NULL

Структура таблицы после выполнения
z3.png


УДАЛЕНИЕ ДАННЫХ

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
f1.png

Итог удаления
f2.png

Пропал игрок с 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.
 
Последнее редактирование модератором:
Сообщения
496
Реакции
618
Помог
16 раз(а)
Перенесено в общий раздел.
 
Сообщения
2,143
Реакции
1,223
Помог
44 раз(а)
Годнота подъехала.
59994a114137215dfec95373.png
 
Сообщения
496
Реакции
618
Помог
16 раз(а)
Gudaus, итог удаления картинки нет
У меня есть)
Но при этом частенько пропадают другие картинки. После F5 появляются, и сам форум не всегда быстро грузится. Бывает такое, когда картинок много. А я их напихал.
 
Сообщения
51
Реакции
-24
Обратите внимание, если вы хотите заключить сделку с этим пользователем, он заблокирован
Я бы записал для начала так
SQL:
CREATE TABLE IF NOT EXISTS `aes_test` (
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
    `name` varchar(32) NOT NULL,
    `steamid` varchar(30) NOT NULL UNIQUE,
    `ip` varchar(16) NOT NULL,
    `exp` float NOT NULL DEFAULT '0.0',
    `bonus_count` int(11) unsigned NOT NULL DEFAULT '0',
    `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
 
Последнее редактирование модератором:
Сообщения
496
Реакции
618
Помог
16 раз(а)
Я брал для примера таблицу, создаваемую Сониксом. От себя ни слова.
И не уверен, что DEFAULT CHARSET=utf8 тут к месту. А что если моя кодировка в Web'е иная?
Очень многие сидят на ANSI и 1250-1251.

`id` int(11) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY, равнозначно

`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),


Это как INNER JOIN. который заменяется WHERE. Можно так, можно иначе.
И `id` int(11) не unsignet. Он signet.
 
Последнее редактирование модератором:
Сообщения
51
Реакции
-24
Обратите внимание, если вы хотите заключить сделку с этим пользователем, он заблокирован
поставь CHARSET=твоя кодировка
UNSIGNED задает, что будет создано поле для хранения без знаковых чисел (больших или равных 0).
id юзера не может быть меньше 0

INT

Диапазон от -2 147 483 648 до 2 147 483 647
при флаге UNSIGNED мы получим id int 4294967294, а без UNSIGNED 2 147 483 647
 
Последнее редактирование модератором:
Сообщения
496
Реакции
618
Помог
16 раз(а)
Alfistik, дада. Перепутал под ночь signed и unsigned)
Да, там unsigned. Мне почему-то показалось, что со знаком UNSIGNED. Он-то без.

CHARSET=твоя кодировка никто ставить не будет, вот в чём дело. Лучше её жёстко не задавать. Мы же ориентируемся на среднего человека.
 
Сообщения
51
Реакции
-24
Обратите внимание, если вы хотите заключить сделку с этим пользователем, он заблокирован
Alfistik, дада. Перепутал под ночь signed и unsigned)
Да, там unsigned. Мне почему-то показалось, что со знаком UNSIGNED.

CHARSET=твоя кодировка никто ставить не будет, вот в чём дело. Лучше её жёстко не задавать. Мы же ориентируемся на среднего человека.
Если кодировку не задавать потом проблемы будут с русским языком
 
Сообщения
496
Реакции
618
Помог
16 раз(а)
Проблемы будут при несовпадении кодировок с поддержкой языка.
Мой amxbans latin-1
 
Сообщения
51
Реакции
-24
Обратите внимание, если вы хотите заключить сделку с этим пользователем, он заблокирован
Скажу даже больше, это кс - можете не думать. По фигу с UNSIGNED или без
Gudaus, при latin если я не ошибаюсь русские символы не будут отображаться
 
Последнее редактирование модератором:
Сообщения
579
Реакции
338
Предупреждения
1
Помог
9 раз(а)
Познавательная статья! Давно хотел изучить sql:good2:
 
Сообщения
496
Реакции
618
Помог
16 раз(а)
Alfistik, отображение сделать можно. Просто тогда есть другая беда - mysql не различает регистр у русских букв. Но прочитать запись может.
Ещё часто пишут в win-1251.
В целом тема подлая у кодировок и типов, я её до 2 части статьи не хочу поднимать.
 
Сообщения
957
Реакции
1,184
Помог
52 раз(а)
Gudaus, latin была ранее вынужденная мера для отображения кириллицы, записанной в бд из амх 182 и ниже. Т. к. не было в них поддержки юникода русского. В 183 полная поддержка символов, включая кириллицу, поэтому желательно использовать UTF-8 кодировку. 1251 кодировка - пережиток прошлого, раньше даже html на ней верстали (начало 2000х), сейчас все полностью переведено на юникод.
 
Сообщения
51
Реакции
-24
Обратите внимание, если вы хотите заключить сделку с этим пользователем, он заблокирован
Sonyx, это все уже отжило если брать не 2000'е, только pdo класс годен для работы с базой данных в 2к18 году если за веб обвязку что то брать
 
Сообщения
957
Реакции
1,184
Помог
52 раз(а)
Sonyx, это все уже отжило если брать не 2000'е, только pdo класс годен для работы с базой данных в 2к18 году если за веб обвязку что то брать
причем тут pdo и кодировка соединения?)) Тут идет обсуждение самого SQL, а не пхп-методологий
 
Сообщения
2,713
Реакции
2,995
Помог
59 раз(а)
SELECT COUNT(*) FROM aes_test WHERE last_update > '2018-03-10 19:50:00' AND exp > 1
разве, поле last_update не является строкой? А это стоит уточнить, при инициализации базы данных.
В итоге, как осуществится выборка, если по идее MySQL не понимает: СТРОКА_1 больше СТРОКА_2?
Осуществит нормально, ибо поле last_update имеет объявление такого вида:
SQL:
last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
UPD: ага, не дочитал, есть и об этом. :good2:
 
Последнее редактирование:

Пользователи, просматривающие эту тему

Сейчас на форуме нет ни одного пользователя.
Сверху Снизу