Страницы

Поиск по вопросам

Показаны сообщения с ярлыком mysql. Показать все сообщения
Показаны сообщения с ярлыком mysql. Показать все сообщения

среда, 15 апреля 2020 г.

Оптимизация php и mysql

#php #оптимизация #mysql

                    
И опять вопросы по работе с mysql и php:
1) Есть два запроса:
mysql_query('select * from `table` where `id`='.$id.' and `user_id`='.$_SESSION['id']);
mysql_query('select * from `table` where `id`='.$id.' and `user_id`='.$_SESSION['id'].'limit
0, 1');

Первичный ключ - id. Имеет ли смысл писать limit 0, 1 в конце запроса или это не
ускорит запрос?
2) В случае уже полученных данных:
$ar = array();
$res = mysql_query('select * from `table` where `id`<30');
while($ar = mysql_fetch_assoc($res)){}

Что лучше использовать: mysql_num_rows($res) или sizeof($ar) ?
3) Зачем нужен mysql_fetch_array, если есть mysql_fetch_assoc и mysql_fetch_row?
По идее, эти две функции по отдельности работают быстрее?
4) При организации, допустим, блогов, разумно ли вынести посты блогов в отдельные
файлы, а комментарии оставить в БД? Просто тогда получается, что при выводе последних
блогов одновременно будет вестись работа как с БД, так и с файлами, что мне не нравится.
Тем более, что анонс все равно придется писать в БД.
5) Определение глобальных переменных в функции - довольно медленная вещь. Можно ли
ускорить работу функции, загнав ссылки на нужные переменные в массив и определив в
функции глобальным только новый массив? То есть, было:
function f() {
    global $ar1, $ar2, $ar3;
}

Стало:
$all = array('ar1' => &$ar1, 'ar2' => &$ar2, 'ar3' => &$ar3);
function f() {
    global $all;
    $ar1 = $all['ar1'];
}

Если целесообразность некоторых вопросов у вас вызвала недоумение, считайте, что
я любитель экономить на спичках.    


Ответы

Ответ 1



1) Имеет смысл сделать так: mysql_query('select * from `table` where `id`='.$_SESSION['id'].' limit 0,1'); Только исключите в запросах *, тогда будет экономия уже не на спичках :) 2) Согласен с @mozzart 3) mysql_fetch_array работает быстрее, чем assoc, т.к. добавляет только индексы в массив. 4) Согласен с @mozzart 5) Скорее вот так быстрее: function (&$ar1, &$ar2, &$ar3) { ... } Пример: class Api { private $db; public function test() { // Этой функции Вы собирались передать get и post $this->db; // объект бд } } или так: class Api extends DB { public function test() { $this->query(); } } class DB { public function query() { ... } }

Ответ 2



1) Смысл есть 2) Если нужно просто получить количество записей, то логичнее и оптимизированней использовать mysql_num_rows, если все записи получены в массив, то тогда конечно - sizeof 3) Не проверял... 4) Если хранение файлов подразумевает организацию кэширование, то тогда да. Грубо говоря, работа с файлами происходит намного быстрее чем с БД 5) Первый вариант быстрее

Параметрическое нахождение ближайшей точки в заданном направлении

#алгоритм #php #mysql

                    
Есть массив точек со случайными координатами.
Выбираем любую из них.
Задача: найти ближайшую к ней точку в заданном направлении.
Например, если речь идет о плоской карте, и надо найти ближайшую точку на востоке,
мы фильтруем угол между северовостоком и юговостоком и ищем точку в нем, тупо сравнивая
расстояния. Для трехмерного пространства все еще хуже. Особенно, если попытаться ввести
систему ранжирования: если есть две точки, одна из них точно на восток, но на X дальше,
а другая - на восток-северовосток под углом a, но чуть ближе, то будет выбрана та,
для которой соблюдается определенное отношение X и a.

Вопрос: 


как поступают умные люди в данной ситуации?

это задача для базы(MYSQL) или PHP?


Код писать не надо: как-нибудь справлюсь. Нужен алгоритм или волшебный пендель.    


Ответы

Ответ 1



SQL: select TOP 1 id from ( select id, my_range_fn( dir_x, dir_y, dir_z, x0, y0, z0, x, y, z ) as range from Points p ) where range < 0 order by range desc Пример ранжирующей функции ( JS ): //2D карта на JS //Север - 2, Запад - 4, Юг - 6, Восток - 0 //Рассматриваем попадание в угол в +- 45 градусов от направления function my_range_fn( dir, x0, y0, x, y ){ var dy = y - y0, dx = x - x0, rast = Math.sqrt( dx * dx + dy * dy ), my_dir = Math.PI * ( ( dy > 0 ) ? 1 : 0 ) - Math.acos( dx / rast ), my_dir = ( my_dir < 0 ) ? Math.PI * 2 + my_dir : my_dir, dir = Math.PI * dir / 4; delta = Math.abs( my_dir - dir ); return ( ( delta < Math.PI/4 ) ? -1 : 1 ) * rast - 2 *delta; } Используется коэф. 2 на разность желаемого направления и полученного Примерно означает что при (x0, y0) = (0, 0) и направлении Сервер, выберет (0,5) вместо (2,4)

Ответ 2



Можно и с помощью MySQL. Если рассматривать вариант плоской сетки координат с точкой отсчета в центре, то северо-восток - это верхний правый квадрат. То-есть ограничения в запросе по х > 0 и у < 0 с учетом точки отсчета. Расчет расстояния по теореме Пифагора. Убывающая сортировка по расстоянию. Лимит 1 на вывод. На выходе ближайшая точка в заданном квадрате.

Ответ 3



Для начала выберем систему координат с центром в первой точке Особенность задачи - в наличии ограничений на угол (|fi|<45), что наталкивает на мысли о полярной системе координат и уравнениях вида r=R(cos(fi)-cos(pi/4)). При этом в качестве критерия оптимальности напрашивается параметр уравнения R = r/(cos(fi)-sqrt(2)/2) = r^2/(x-r*sqrt(2)/2) с размерностью расстояния. И тогда останется главное - правильно учесть ограничения.

понедельник, 13 апреля 2020 г.

Проблема с MySQL в OS X 10.8: Access denied for user 'root'@'localhost'

#macos #mac #mysql

                    
Создаю рабочее окружении на OS X 10.8 Mountain Lion, сконфигурировал Apache2, подгрузил
PHP, скачал и установил все компоненты MySQL. Делаю все по инструкциям и в какой-то
момент появляется проблема, а именно возникает на стадии создания пароля для root.
Ввожу команду в терминале, как и говорят в инструкции (заменяя на свой пароль, в
одинарных ковычках).
/usr/local/mysql/bin/mysqladmin -u root password 'yourpasswordhere'


/usr/local/mysql/bin/mysqladmin:
connect to server at 'localhost'
failed error: 'Access denied for user
'root'@'localhost' (using password:
NO)'

И что же делать? Помогите, пожалуйста.
P.S. Уверен, что моя проблема уже всплывала, но она не гуглится в силу того, что
OS X не так популярна, как Windows. Да и все, что я нагуглил относится уже к более
поздним стадиям работы с MySQL.    


Ответы

Ответ 1



вводите /usr/local/mysql/bin/mysqladmin -u root -p И это все. Пароль спросит позже

Оператор сравнения NOT IN

#php #mysql

                    
Допутим я хочу вывести новости из БД но не учитывая определенных пользователей. Пример:
SELECT news FROM posts WHERE id NOT IN (4,6,7...6000);

Вот в чем заключается вопрос, какова максимальная длинна выражения в скобках?
и как это будет сказываться на производительности БД?
P.S. пример выдуманный, и новости нужных пользователей я знаю как по другому вывести,
мне нужно понять все насчет оператора     


Ответы

Ответ 1



Длина выражения в скобках не имеет значения. Имеет значение длина запроса в целом. Длина запроса задается настройкой max_allowed_packet в конфиге.

Не работает Инсерт в БД?

#php #mysql

                    
вот такой простой код! и он не работает..


тип поля в БД "name" varchar(225)
на первый взгляд все верно но скрипт выдает "noo" как индикацию отсутствия результата
не могу разобраться что не так( имя таблицы прописанно верно соединение с БД есть..    


Ответы

Ответ 1



Ошибка у вас в слове VALUES: $result3 = mysql_query("INSERT INTO `coalition` (`name`) VALUES ('$name')");

Ответ 2



Все было просто, у меня в таблице не стояли значения по умолчанию - а оказывается нельзя создавать ноую строку в БД когда значения остаются пустыми" а я в запросе некоторые значения не указывал)

Как сменить настройки my.ini/my.cnf динамически?

#sql #mysql

                    
Привет.
Посмотреть установленные настройки сервера можно командой
SHOW VARIABLES LIKE 'name_variable'

Какой командой можно сменить значение установленных переменных в файле my.ini?
Какой уровень привилегий позволяет это сделать?
Когда настройка вступить в силу(после перезапуска сервера или нет)?
Как создать свою глобальную переменную?
 SET uoi=90;

ERROR 1193 (HY000): Unknown system variable 'uoi'    


Ответы

Ответ 1



Сменить значение серверной переменной можно при помощи оператора SET, который вы привели в вопросе. Существует несколько вариантов его использования: SET GLOBAL init_connect='SET autocommit=0'; или SET @@init_connect='SET autocommit=0'; или SET init_connect='SET autocommit=0'; Не все пользователи могут изменять серверные переменные, нужно обладать привилегией SUPER, чтобы сервер позволил это сделать. Не все переменные можно изменять на лету при помощи SET. Уточнять список изменяемых переменных можно в документации. Если переменная обозначена как Dynamic - она может быть изменена при помощи SET, если в поле Dynamic стоит No - изменять ее можно либо на уровне конфигурационного файла, либо вообще нельзя (в последнем случае потребуется перезапуск сервера, или обновление данных конфигурационного файла). Создать собственную серверную переменную не получится - эти переменные отражение состояния сервера - придется программировать и пересобирать MySQL, чтобы ввести собственную серверную переменную. Однако, можно создать пользовательскую сессионную переменную. Такие переменные, в отличие от системных начинаются не с двух @@, а с одной. Для этого нужно либо воспользоваться оператором SET SET @uoi = 90; SELECT @uoi; +------+ | @uoi | +------+ | 90 | +------+ Либо задать ее в составе другого запроса, например, SELECT SELECT @oui := 100; Обратите внимание, что без оператора SET для присвоения значения переменной используется оператор :=, а не =.

Устранение излишних запросов на сайте

#php #оптимизация #mysql

                    
Приветствую
if(!isset($_SESSION['zapros'])){
    //тут у нас запрос к базе, который возвращает массив $massiv;
    $_SESSION['zapros'] = $massiv;
}

Знаю, так делать неправильно, совать в сессию все запросы. Но в силу того, что 'мне
хватает' - использую. Вопрос прост, как на сайте организовать уменьшение запросов от
одного пользователя? Мой способ, из эры динозавров - сунуть в сессию. Но правильно
ли это? Есть модная штука memcache, но никто не объяснит чем оно лучше той же сессии..
вот допустим у сессии лимит 128мб на всех пользователей (зависит от хостинга), а у
мем кэша есть недостатки?
Поможете разобраться?
p.s. да, знаю можно вообще заранее подготовленные данные из файла читать. меня интересует
чисто кэширование запросов    


Ответы

Ответ 1



Memcache >>>>>>>>>>>>> сессия. Как можно догадаться, мемкэш держит все в памяти, а сессия сохраняется на диск - скорости будут просто несопоставимы. Тем более, не будете же вы для каждого пользователя писать список десяти последних новостей, например? Ну и первое, что вас должно было смутить: сессия - это штука, созданная исключительно для работы с пользователем. По-хорошему кэширование должно быть встроено уже на уровне дб или модели, когда опциональным аргументом метода указывается, что запрос может быть закеширован.

Ответ 2



По-умолчанию MySQL умело кеширует на своей стороне запросы, если скорость с сервером MySQL высокая, то этого обычно достаточно. Если же нужно кешировать на стороне PHP, то лучше всего использовать хорошие ORM к примеру Doctrine.

суббота, 11 апреля 2020 г.

Почему не работает запрос?

#search #mysql

                    
Запрос не выдает результата, хотя в таблице он точно есть. Сам запрос:
SELECT * FROM `tasks`
WHERE MATCH (`description`) AGAINST (?)
ORDER BY MATCH (`description`) AGAINST (?)
DESC

где ? строка поиска.
Эмуляция на SQL Fiddle.    


Ответы

Ответ 1



Вопрос решил, установкой IN BOOLEAN MODE SELECT * FROM `tasks` WHERE MATCH (`description`) AGAINST (? IN BOOLEAN MODE) ORDER BY MATCH (`description`) AGAINST (? IN BOOLEAN MODE) DESC

Схема БД для учета проведенных конференций

#mysql #база_данных #проектирование

                    
Проектирую бд для системы учета проведения НИРС в ВУЗах.

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

К примеру у меня есть 1 человек, который создает приказ (Подтверждающий) и 2 человека
которые утверждают (Удтверждающие), тогда в таблице Приказы будет 2 записи, в которых
будут повторяться поля Тема приказа, Номер приказа, Дата приказа, Код подтверждения,
и будут отличаться в 2 записях только поле Код утдверждения.

Как можно перестроить схему, чтобы избавиться от этого изьяна, или есть возможность
хранить в поле таблицы массив данных(что врядли)?


    


Ответы

Ответ 1



будет происходить избыточность данных да, при описанной схеме работы факт и момент подписания (а в идеале — и отзыва) подписи следует фиксировать в отдельной таблице, связанной с таблицей приказов и таблицей(-ами) полномочий. но если все приказы соответствуют шаблону «три подписи», то, вероятно, проще будет добавить в таблицу приказов три соответствующих поля, содержащих либо null, либо id подписавшего/утвердившего. а в принципе, вопросы «оцифровывания» документооборота вообще, и фиксации подписаний-утверждений-согласований-отклонений в частности — тема достаточно обширная. в наиболее полном варианте, например, обязательно следует учитывать тот факт, что полномочия подписания предоставляются лишь на время. т.е. начинать надо с грамотной постановки задачи, в которой чётко определить, насколько «оцифрованный» документооборот будет упрощён относительно реального.

Время проведенное на сайте

#php #mysql

                    
Здравствуйте. 
Хочу сделать чтоб пользователь мог видеть сколько времени всего он провел на сайте
в онлайн. Но для того чтоб его вывести его нужно записать в базу. Как делать запросы
в базу я знаю, только вот не пойму как его записывать в базу.. чтоли при каждом обновлении
страницы пользователям запись делать, или как?
Буду благодарен за помощь.
    


Ответы

Ответ 1



Тут есть 2 варианта 1) Время проведённое с момента авторизации на сайте 2) Общее время проведённое на сайте В первом случае, записываем время авторизации в сессию в формате mktime и высчитываем время Второй вариант описан выше

Ответ 2



Для начала определитесь, что значит "время, проведенное на сайте". Если это время между загрузкой и выгрузкой страницы, то просто скриптом на сайте делаете так: onload - записали текущее время-дату onunload - отослали на сервер разницу между текущим время-датой и начальным, в секундах, допустим. Плюс ID пользователя. На стороне сервера по ID пользователя суммируем все цифры. Но что делать, если время, пока страница открыта в фоновой вкладке и забыта, не хочется считать? Или если сайт открыт в трех вкладках - пользователь в три раза больше проводит там времени? В общем, начните с определения, с ТЗ для самого себя, и ответ придет.

Ответ 3



Если нужно проверять раз в 5 минут, то будет проще делать все это средствами jquery setInterval(function(){ // такой простой код только для примера $.get('/updateTime.php?user=USER_ID') }, 60000 * 5) Такой асинхронный вариант немного лучше чем каждый раз при обновлении страницы писать в базу. Плюс к тому пользователю не придется обновлять страницы, если он находится на сайте - например медленно читает длинную статью.

четверг, 9 апреля 2020 г.

MySQL ORDER BY приближенное значение

#php #mysql

                    
Доброго времени суток!
Сразу приведу пример чтобы было понятно.
На сайте стандартный поиск сортирует по title (названию новости).
У нас есть например 2 новости "семь" и "восемь"
и если ввести "семь" то выведет в первую очередь "восемь", т.к. у нас сортировка
по алфавиту.
Как написать поиск более точный?
PHP
    


Ответы

Ответ 1



Если конкретно надо вот прям сначала те которые начинаются, а потом которые только содержат, то WHERE title LIKE 'семь%' ORDER BY title UNION SELECT ... WHERE title LIKE '%семь%' ORDER BY title Но вообще то что тебе нужно называется полнотекстовый поиск.

Ответ 2



попробуйте так SELECT title, CONCAT(' ', title) as title_ext FROM table WHERE title like '%семь%' ORDER BY CONCAT(' ', title)

Как осуществить поиск похожего текста в MySQL?

#mysql #база_данных #текст #выборка

                    
Дано: таблица с полями id и txt, где txt - небольшая статья, пост или комментарий,
содержащий HTML, примерный объем записи - 2-10 кб, всего записей 100к-1млн.

Нужно извлечь группы записей, в которых текст приблизительно похож, т.е. совпадать
процентов на 80-90, т.к. идентично равных строк в БД нет.

Позволяют ли существующие механизмы БД осуществить такую выборку, и как это сделать?

UPD: (очень близко) есть ли аналог пхп-шного similar_text() в mysql? Скорость выполнения
запроса не имеет значение.
    


Ответы

Ответ 1



Как было сказано выше, можно попробовать расстояние Левенштейна. Еще один пример реализации для mysql тут: http://www.artfulsoftware.com/infotree/qrytip.php?id=552 Можно сделать адаптированный вариант с этого примера: CREATE FUNCTION levenshtein( s1 text, s2 text ) RETURNS INT DETERMINISTIC BEGIN DECLARE s1_len, s2_len, i, j, c, c_temp, cost INT; DECLARE s1_char CHAR; -- max strlen=255 DECLARE cv0, cv1 VARBINARY(10240); SET s1_len = CHAR_LENGTH(s1), s2_len = CHAR_LENGTH(s2), cv1 = 0x00, j = 1, i = 1, c = 0; IF s1 = s2 THEN RETURN 0; ELSEIF s1_len = 0 THEN RETURN s2_len; ELSEIF s2_len = 0 THEN RETURN s1_len; ELSE WHILE j <= s2_len DO SET cv1 = CONCAT(cv1, UNHEX(HEX(j))), j = j + 1; END WHILE; WHILE i <= s1_len DO SET s1_char = SUBSTRING(s1, i, 1), c = i, cv0 = UNHEX(HEX(i)), j = 1; WHILE j <= s2_len DO SET c = c + 1; IF s1_char = SUBSTRING(s2, j, 1) THEN SET cost = 0; ELSE SET cost = 1; END IF; SET c_temp = CONV(HEX(SUBSTRING(cv1, j, 1)), 16, 10) + cost; IF c > c_temp THEN SET c = c_temp; END IF; SET c_temp = CONV(HEX(SUBSTRING(cv1, j+1, 1)), 16, 10) + 1; IF c > c_temp THEN SET c = c_temp; END IF; SET cv0 = CONCAT(cv0, UNHEX(HEX(c))), j = j + 1; END WHILE; SET cv1 = cv0, i = i + 1; END WHILE; END IF; RETURN c; END; CREATE FUNCTION levenshtein_ratio( s1 text, s2 text ) RETURNS INT DETERMINISTIC BEGIN DECLARE s1_len, s2_len, max_len INT; SET s1_len = LENGTH(s1), s2_len = LENGTH(s2); IF s1_len > s2_len THEN SET max_len = s1_len; ELSE SET max_len = s2_len; END IF; RETURN ROUND((1 - LEVENSHTEIN(s1, s2) / max_len) * 100); END; Выбрать попарно похожие строки так: select t1.id, t1.txt, t2.id, t2.txt from table1 t1 join table2 t2 on t2.id <> t1.id and levenshtein_ratio(t1.txt, t2.txt) > 80 Как разбить результат выборки на группы, придется подумать. По работе, если кратко, то алгоритм считает количество замен/добавлений символов в текст, чтобы получить полностью схожие записи. Но главная проблема - алгоритм осуществляет посимволный перебор, что является довольно затратным. А теперь если учесть, что длина текста 2-10 кб и до 1 млн. записей, то база будет просто умирать от такой "аналитики" (а не забывайте, что главная задача базы - осуществлять хранение и доступ к данным, но никак не реализовывать сложные вычислительные алгоритмы). Поэтому я бы рекомендовал, пока не поздно, подумать над тем, чтобы вынести реализацию за пределы базы. Можно найти множество "быстрых" реализации вычисления расстояния Левенштейна практически на всех языках. При реализации предложил бы делать какую-то предварительную фильтрацию, например по длине текста, т.е. если длина не совпадает на 80%, то сравнение даже не проводить, т.к. даже на производительных машинах сравнение таких объемов текста уже будет заниматься ощутимое время.

Ответ 2



Вы можете решить данную задачу с помощью использования хранимых процедур. Например так: CREATE PROCEDURE dbo.spSimil_FirstNameLastName @str1 nvarchar(max), @threshold float AS SET NOCOUNT ON SELECT * FROM (SELECT dbo.fnSimil(@str1, Person.Person.FirstName + N' ' + Person.Person.LastName) AS Simil, * FROM Person.Person) AS T WHERE T.Simil >= @threshold ORDER BY T.Simil DESC; Процедура вызывается следующим образом: EXEC dbo.spSimil_FirstNameLastName N'John Adams', 0.75 Подробнее можно узнать тут: http://www.accessmvp.com/tomvanstiphout/simil.htm Для решения вашей задачи можно попробовать прибегнуть к расстояние Левенштейна: ссылка на реализацию для mysql: https://github.com/ifsnop/damlev

Стоит ли использовать спецсимволы в названиях таблиц/столбцов?

#mysql

                    
В мануале MySQL.Ru указано, что можно называть таблицы и столбцы с применением различных
символов (в более ранних версиях _, $). Стоит ли пользоваться или ограничиваться _?
    


Ответы

Ответ 1



Такие вещи должны оговариваться в "стандарте кодирования" конкретной команды разработчиков. Что для одних норма, то другим кошмар. Важно чтобы в одном проекте не было разнообразия в этом плане. В тех местах, где мне приходилось работать, для имен MySQL было принято ограничиваться нижним регистром латиницы + цифры и подчеркивание, snake-синтаксис. Вот примеры толковых соглашений об именах: http://anandarajpandey.com/2015/05/10/mysql-naming-coding-conventions-tips-on-mysql-database/ https://raw.githubusercontent.com/treffynnon/sqlstyle.guide/gh-pages/_includes/sqlstyle.guide.md

Ответ 2



Рекомендую использовать: нижний регистр, буквы, цифры и знак подчеркивания. Это наиболее часто встречающийся вариант в популярных FW. Для сообщества PHP+MySQL, имхо, уже стандарт. Чем меньше нестандартных решений, тем гибче и безопасней.

GROUP BY без групповых функций в MySQL

#mysql #sql #group_by

                    
Какую информацию выдаёт MySQL, если делать GROUP BY без групповых функций?

например:

id|name|count|date
-------------------------
1 | aa |  1  |null
1 | bb |null |2007-12-12
1 |null|  2  |2015-10-12


GROUP BY id

будет здесь какая-нибудь закономерность в выдаче в полях name, count и date или туда
попадают случайные значения из выборки?

P.S. тот же PostgreSQL просто выдаст ошибку.
    


Ответы

Ответ 1



При исполнении запроса есть некий порядок обработки строк. Заданный либо разработчиком, либо на усмотрение оптимизатора. Так вот будет выдана строка, которая была обработана первой в группе. Следующий запрос: SELECT * FROM( SELECT * FROM( SELECT 1 id, 1 OrderBy, 10 value UNION ALL SELECT 1 id, 2 OrderBy, 20 value UNION ALL SELECT 1 id, 3 OrderBy, 30 value )T ORDER BY OrderBy )T GROUP BY id Вернёт: id OrderBy value 1 1 10 Однако такой запрос: SELECT * FROM( SELECT * FROM( SELECT 1 id, 1 OrderBy, 10 value UNION ALL SELECT 1 id, 2 OrderBy, 20 value UNION ALL SELECT 1 id, 3 OrderBy, 30 value )T ORDER BY OrderBy DESC )T GROUP BY id Вернёт уже: id OrderBy value 3 3 30 Но, повторюсь, сортировку может выбрать оптимизатор какую угодно, поэтому в общем случае, предсказать какую строку "выберет" оптимизатор невозможно. Т.е. да, теоретически, если задать уникальную сортировку, можно использовать данную особенность MySQL осознанно. Но на свой страх и риск. Поскольку данное поведение не описано в документации и может измениться в будущих версиях MySQL сервера.

Ответ 2



Ответ из комментариев Будет выдана случайная строка, если быть совсем точном, то строка, которая будет отобрана, конечно, не случайна. Однако, ввиду того, что по мере внесения изменений в таблицу, будут выдаваться разные строки, то для «простого пользователя» это будет выглядеть именно как «случайно выбранная строка». Это не типичное поведение для СУБД, так ведет себя пожалуй только MySQL. PostgreSql, MS Sql и Oracle выдадут ошибку потому, что это противоречит стандарту SQL. В MySql же (если не задавать специальных параметров) в данном случае используется некий расширенный стандарт, который позволяет так делать. Считается, что если указанная колонка не перечислена в GROUP BY, то все ее значения в пределах группы одинаковы и поэтому не важно из какой именно строки оно будет возвращено.

Как в PHPMyAdmin посмотреть триггеры в MySQL?

#php #mysql #sql #phpmyadmin

                    
Как в PHPMyAdmin посмотреть триггеры в MySQL? Не могу найти этот раздел, есть раздел
процедуры, но там написано "у вас нет прав для создания процедур" . Я свой триггер
загрузил через SQL консоль в PHPMyAdmin, и он работает, но как его найти не знаю. 
    


Ответы

Ответ 1



Заходите в БД и в верхней панели наводите курсор на "Ещё":

арифметические операции разных типов в mysql

#mysql

                    
Почему mysql возвращает странный результат:
'0.02' + 0.1 = 0.12000000000000001
    


Ответы

Ответ 1



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

суббота, 4 апреля 2020 г.

Выбор случайного значения в базе данных

#php #mysql #sql

                    
В общем есть база вида id | group | user

Надо выбрать 1 случайную строку из 100 которая содержит group = "vip" , а user =
"". И записать в user этой строки например 'что-то'. Как это сделать?

UPD: Запрос в ответе не работает, выдает ошибку 1064, вот таблица, может что-то там
поправить (ошибка у key).



    


Ответы

Ответ 1



Самый простой вариант, это извлечь случайный идентификатор из этих таблиц SELECT id FROM tbl WHERE group = "vip" AND user = "" ORDER BY RAND() LIMIT 1 Далее полученный таким образом идентификатор использовать для UPDATE-запроса UPDATE tbl SET user = 'что-то' WHERE id = 3432 Будьте осторожны с ORDER BY RAND() на гигантских таблицах, так как это полный скан таблицы. Если есть возможность вычислить случайный идентификатор другим способом - хорошо бы им воспользоваться (однако, для этого нужно больше информации о проекте).

четверг, 2 апреля 2020 г.

Как хранить смайлики в MySQL?

#mysql #python #python_3x #mysqlconnector #pymysql

                    
При попытке загрузить смайлик в БД, пишет: "1366 (HY000): Incorrect string value:
'\xF0\x9F\x98\x89' for column 'last_name' at row 1"

Нашел вариант про utf8mb4. Перевел сервер,БД,таблицы и поля в utf8mb4, все равно ошибка.

Если в Python при соед. указываю charset = utf8mb4, то получаю ошибку: "1273 (HY000):
Unknown collation: 'utf8mb4_0900_ai_ci'".

Нашел единственный вариант, который сработал это в Python указать: 

cursor.execute('SET NAMES utf8mb4')
cursor.execute("SET CHARACTER SET utf8mb4")
cursor.execute("SET character_set_connection=utf8mb4")


Тогда всё работает. Но тут неудобно везде писать эти три строки, возможно ли их как-то
прописать в настройках mysql?

Уже на самом деле запутался...
P.S.
Версия сервера: 5.7.21-0ubuntu0.16.04.1 
    


Ответы

Ответ 1



Оказалось, что... Python3 mysql.connector версии 8.0.6 не поддерживает utf8mb4. Переустановил на » mysql.connector.version '2.1.7' - работает.

Ошибка Ansible: “ERROR! 'mysql_user' is not a valid attribute for a Play”

#mysql #python #linux #ansible #yaml

                    
Хост машина с Ansible 2.3.1.0 - Ubuntu 17.04, клиентская нода - Centos 7(LXC). 
Побродив в гугле на гитхабе в поисках проблемы, опробовал несколько вариантов решения
проблемы: установки пакетов MySQL-python,python-mysqldb и прочие, в т.ч и для версии
3.4. Что странно, так это то, что через плейбук я смог выполнить mysql_secure_installation
пошагово, а простого пользователя добавить не могу, когда казалось бы через ту же либо
mysql-python будет работать.
При выполнении плейбука вида:

---
- hosts: lxc01
 become: yes
 tasks:
 name: add mysql user
 mysql_user:
 name: bob
 password: 12345
 priv: '*.*:ALL, GRANT'


Получаю:

ERROR! 'mysql_user' is not a valid attribute for a Play

The error appears to have been in '/home/sat/jedi/mysq.yml': line 2, 
column 3, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

---
- hosts: trapeznikov-lxc01
  ^ here


библиотеки требуемые для выполнения этой операции, указанные в офф документации Ansible
установлены, дальше даже пробовал модули через pip устанавливать и на хосте и на клиенте,
все равно 0 толку.
Может проще кормить в импорт .sql файлы с запросами?
Кто подскажет, что не так делаю?
    


Ответы

Ответ 1



Возможно, что вы не понимаете синтаксис yaml? Предполагаю, что вы хотели написать что-то типа: --- - name: add mysql users hosts: lxc01 become: yes tasks: - name: add mysql user1 mysql_user: name: bob1 password: 12345 priv: '*.*:ALL, GRANT' - name: add mysql user2 mysql_user: name: bob2 password: 12345 priv: '*.*:ALL, GRANT' Простой пример в документации можно посмотреть здесь: Playbook Language Example

вторник, 31 марта 2020 г.

MySQL Подсчёт уникального количества дней в таблице с диапазонами дат

#mysql #sql



Пытаюсь найти решение для одной задачки: есть таблица, содержащая Имя, дату начала
интервала и дату конца интервала.
Суть в том, что у человека с одним и тем же именем - может быть несколько записей,
в которых даты могут пересекаться (собственно фото)



Нужно найти для каждого человека (в данном случае для одного Петрова) количество
уникальных дней за все даты. То есть не учитывать наложение дат...

Если суммарное количество дней найти по всем записям элементарно - например

   SELECT `people_id`, SUM(DATEDIFF(end_date, `start_date`)) AS wd 
FROM test_days GROUP BY people_id


Или

SELECT SUM(days) total 
FROM 
(
    SELECT datediff(`end_date`, `start_date`) days FROM test_days
) AS get_days


то как исключить наложения я не додумался. 

Если есть добрые люди - поделитесь идеей, пожалуйста.

Сам код таблицы

CREATE TABLE `test_days` (
  `people_id` varchar(100) DEFAULT NULL,
  `start_date` date DEFAULT NULL,
  `end_date` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO `test_days` (`people_id`, `start_date`, `end_date`) VALUES
('Петров', '2018-06-05', '2018-06-09'),
('Петров', '2018-05-01', '2018-05-19'),
('Петров', '2018-05-06', '2018-05-19'),
('Петров', '2018-05-03', '2018-05-23');

    


Ответы

Ответ 1



Думаю сначала придется размножить записи, что бы каждая дата из интервала стала отдельной строкой. После чего посчитать уникальные записи. Для размножения записей удобно пользоваться опорной таблицей с порядковыми номерами от 0 до максимальной длины интервалов, которые могут встретиться. Например создадим такую таблицу: create table seqnum(X int not null); -- Первые 8 записей insert into seqnum values(0),(1),(2),(3),(4),(5),(6),(7); -- И еще 512 insert into seqnum select s1.x*64+s2.x*8+s3.x+8 from seqnum s1, seqnum s2, seqnum s3; А теперь можем размножать и считать уникальные: select d.people_id, count(distinct d.start_date + interval s.x day) days from test_days d, seqnum s where s.x<=DATEDIFF(end_date, start_date) group by d.people_id Пример на sqlfiddle.com

Ответ 2



Если кому интересно - примерно такая идея получилась: Словесное описание алгоритма действий: 1) Для каждого пользователя объединяем все маленькие пересекающие между собой интервалы в сплошные не пересекающиеся между собой "мегаинтервалы" 2) Для каждого пользователя определяем длительность каждого полученного "мегаинтервала" 3) Для каждого пользователя определяем сумму длительностей всех "мегаинтервалов"Этот вариант предложили на sql форуме select people_id , sum(days) as days from (-- Список длительностей "монолитных" периодов в разрезе пользователя: select all_start_date.people_id , datediff(min(all_end_date.end_date), all_start_date.start_date) as days from (-- Начальные точки "монолитных" периодов select start_date , s1.people_id from test_days s1 where not exists ( select null from test_days s2 where s2.start_date < s1.start_date and s2.end_date >= s1.start_date and s1.people_id = s2.people_id ) ) all_start_date, (-- Конечные точки "монолитных" периодов select end_date , s1.people_id from test_days s1 where not exists ( select null from test_days s2 where s2.end_date > s1.end_date and s2.start_date <= s1.end_date and s1.people_id = s2.people_id ) ) all_end_date where all_start_date.people_id = all_end_date.people_id and all_start_date.start_date <= all_end_date.end_date group by all_start_date.people_id, all_start_date.start_date ) v group by people_id order by people_id И, моя беродехрень, в виде функции. Не самый изящный вариант, не самый рациональный и крутой, но зато вот такой: Вызов функции в запросе: SELECT `people_id`, p2(`people_id`) FROM test_days GROUP BY `people_id` И. непосредственно, сама функция: -- -- Функции -- CREATE DEFINER=`root`@`%` FUNCTION `p2` (`name` VARCHAR(255)) RETURNS INT(10) BEGIN DECLARE d1 date; DECLARE d2 date; DECLARE prev_d1 date; DECLARE prev_d2 date; DECLARE done INT DEFAULT 0; DECLARE summ_days INT DEFAULT 0; DEClARE cur CURSOR FOR SELECT start_date, end_date FROM test_days WHERE people_id = name ORDER BY start_date ; DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; OPEN cur; SET summ_days:=0; FETCH cur INTO prev_d1,prev_d2; SET summ_days = DATEDIFF(prev_d2, prev_d1) + 1; REPEAT FETCH cur INTO d1,d2; IF NOT done THEN IF d1 > prev_d2 THEN SET summ_days = summ_days + DATEDIFF(d2, d1) + 1; SET prev_d1 = d1; SET prev_d2 = d2; ELSE IF d2 > prev_d2 AND d1 <= prev_d2 THEN SET summ_days = summ_days + DATEDIFF(d2, prev_d2); SET prev_d2 = d2; END IF; END IF; END IF; UNTIL done END REPEAT; CLOSE cur; RETURN summ_days; END$$ DELIMITER ; -- --------------------------------------------------------