Ответы пользователя по тегу MySQL
  • Как выполнить обновление поля последней датой по связанным таблицам?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Шаблон:

    UPDATE main_table
    JOIN ( SELECT id, MAX(created_at) AS created_at
           FROM ( SELECT id, created_at from slave1
                  UNION ALL
                  SELECT id, created_at from slave2
                  UNION ALL
                  ...
                  UNION ALL
                  SELECT id, created_at from slaveN             
                  ) AS alldates
           GROUP BY id
           ) AS maxdate USING (id)
    SET main_table.created_at = maxdate.created_at
    Ответ написан
    Комментировать
  • Как правильно сделать скрипт для крона?

    @Akina
    Сетевой и системный админ, SQL-программист.
    А к какой заднице тут вообще CRON прислонился?

    Если же имеется в виду, что указанным запросом надо удалять записи регулярно - то CRON для решения такой задачи просто нафиг не нужен..

    Using the Event Scheduler

    PS. И в запросе следует избавиться от WHERE IN и переписать его на обычный JOIN.
    Ответ написан
    Комментировать
  • Как исправить ошибку с бд?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Представим, что проблему сохранения вы как-то решили... А что вы намерены делать с сохранённым значением?

    Вариант 1 - всегда только извлекать весь массив целиком, в том виде, в каком он сохранялся. Никаких извлечений части массива, никаких по нему поисков, сортировок и прочего. Тогда преобразуйте массив во вменяемый сериализованный формат и сохраняйте в поле БД. Виктор Кожухарь в своём ответе разобрал этот вариант.

    Вариант 2 - возможна какая-то обработка. Извлечение части массива по какому-то критерию (порядковый номер, соответствие шаблону и пр.), поиск в массиве по заданному критерию, сортировка самого массива либо массивов по какому-то критерию.. Тогда однозначно делите массив на отдельные элементы и сохраняйте их по одному (конечно, соответствующим образом должна измениться структура БД). Делить можно и на стороне PHP (как показывает Евгений в своём ответе), и в запросе на запись на стороне MySQL. Первое, как я понимаю, вам проще сделать, но правильно - второй вариант.
    Ответ написан
    Комментировать
  • Выбор максимального значения за период и timestamp этого значения. Ошибка sql_mode=only_full_group_by?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Ну типа так:
    SELECT DISTINCT
           MAX(player_count) OVER () AS players_max, 
           FIRST_VALUE(`timestamp`) OVER (ORDER BY player_count DESC) AS players_max_timestamp
    FROM steam_stats 
    WHERE `timestamp` >= '2024-07-01' AND `timestamp` < '2024-08-01'

    Если максимальное значение player_count встречается более чем один раз, то будет выведен случайный timestamp из возможных. Если нужен определённый (например, самый последний из них), расширьте выражение сортировки в определении окна.
    Ответ написан
    1 комментарий
  • Как найти минимальное свободное значение в диапазоне?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Предполагая, что тип данных поля - DECIMAL(xx, 3):
    SELECT MIN(value) + 0.001
    FROM test t1
    WHERE NOT EXISTS (
      SELECT NULL
      FROM test t2
      WHERE t1.value = t2.value - 0.001
      );


    https://dbfiddle.uk/9Yyi-pol

    PS. Возвращаемое значение не может быть меньше минимального из уже имеющихся в таблице.
    Ответ написан
  • Как хранить списки в бд?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Вложенные списки организуют классическую связь 1:N (одному блоку данных соответствует несколько записей из списка).
    Если эти строки списка как-то обрабатываются (поиск, фильтрация и пр.), то наиболее разумна схема с 2 таблицами и внешним ключом.
    Если же списки только сохраняются и извлекаются, без вообще какой-либо обработки, то можно использовать предложенную mxelgin схему с хранением всего списка в одном поле TEXT либо JSON в сериализованном виде.
    Ответ написан
    Комментировать
  • Как залить большой файл sql в базу?

    @Akina
    Сетевой и системный админ, SQL-программист.
    захожу через putty по SSH и гружу по
    mysql -u****** -p****** ******* < *******.sql

    Напрасно.
    Загрузи CLI, а уж потом в нём грузи дамп командой SOURCE.
    Во-первых, не будет тайм-аута, интерактивно клиент, в отличие от безынтерфейсного, не воспринимается как померший, ибо постоянно льёт в выходной поток. Во-вторых, будешь видеть диагностику загрузки (особенно если запустишь CLI с ключом --tee).
    Ответ написан
    Комментировать
  • Как объединить разные таблицы с разными столбцами?

    @Akina
    Сетевой и системный админ, SQL-программист.
    (SELECT DISTINCT name AS zagolovok FROM sotrudniki ORDER BY 1 LIMIT 2147483647)
    UNION ALL
    (SELECT DISTINCT nazvanie FROM transport ORDER BY 1 LIMIT 2147483647)


    Если поля name/nazvaine объявлены как уникальные - убрать DISTINCT.

    fiddle
    Ответ написан
  • Какую кодировку выбрать для бд чтобы хранить фото?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Не надо хранить бинарные файлы в БД.

    В дополнение ко всему сказанному - в MySQL извлечение сохранённых бинарных файлов именно в виде файлов, а не массива байтов, тоже занятие нетривиальное. Выполняется по одному, запросом SELECT INTO DUMPFILE, да ещё и отдельно от остальных полей записи.
    Ответ написан
    Комментировать
  • Обновление таблицы в бд данными, которые когда-то были, но теперь отсутствуют - как?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Есть товары, которые прилетают по API, их заношу в бд, но иногда часть товаров отсутствует в API и в бд нужно обнулить остатки.

    Элементарно.

    То, что приходит по API, нужно не пихать сразу в рабочую таблицу, а сохранить во временную таблицу. А потом обновить рабочую таблицу, используя полученные данные как источник данных. Потребуется два запроса - первый обновит записи о товарах, имеющихся в пришедшем списке, и добавит новые (INSERT .. SELECT .. ODKU), второй поставит требуемую пометку в нужном поле (UPDATE .. FROM .. LEFT JOIN .. WHERE .. IS NULL).

    Альтернативный вариант - добавить в таблицу (если не имеется, что было бы весьма странно для описываемой системы) поле штампа времени обновления записи (updated_at). Перед обновлением по данным API зафиксировать время начала процесса (получить запросом с сервера MySQL), после чего вторым запросом поставить соотв. пометку в те записи, где этот штамп времени ранее запомненного.
    Ответ написан
  • Проблема миграции базы данных с mysql 8 на mariaDB 10?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Проблема миграции базы данных с mysql 8 на mariaDB 10?

    Проблемы ОБЯЗАНЫ БЫТЬ. MySQL и MariaDB расфоркнулись достаточно давно, изменения и дополнения в синтаксисе они не синхронизируют, так что неудивительно, что чем дальше, тем меньше они совместимы. И соответственно всё меньше шансов. что дамп одной СУБД беспроблемно натянется на другую.

    Такой перенос надо делать руками.

    1. Выгружаем дамп структуры (без данных) из MySQL.
    2. Экспортируем данные из MySQL-таблиц в CSV.
    3. Правим дамп структуры руками, приводим к требованиям синтаксиса MariaDB.
    4. Загружаем структуру в MariaDB, убеждаемся, что работает. Дропаем.
    5. Делим дамп на 2 части - в одной только таблицы (и другие критично необходимые для создания таблиц объекты), в другой всё остальное (индексы, представления, триггеры-функции и прочая тряхомудия).
    6. Грузим первую часть дампа структуры.
    7. Импортируем данные из CSV в таблицы MariaDB.
    8. Грузим вторую часть дампа структуры.
    Ответ написан
  • В чем нарушение синтаксиса в данном запросе? Как его исправить?

    @Akina
    Сетевой и системный админ, SQL-программист.
    дана вот такая задача
    "Добавить отзыв с рейтингом 5 на жилье, находящиеся по адресу "11218, Friel Place, New York", от имени "George Clooney""

    Это должно быть вот так:
    INSERT INTO Reviews (user_id, reservation_id, rating)
    SELECT Users.id, Rooms.id, 5
    FROM Users
    CROSS JOIN Rooms
    WHERE users.name = 'George Clooney'
      AND Rooms.address = '11218, Friel Place, New York';

    А за каким рожном тут таблица Reservations, я вообще не понял. Задание про необходимость резервирования этого жилья за этим юзером не говорит ничего - то есть такого резервирования может и не быть.
    Ответ написан
    2 комментария
  • MySQL Command Line закрывается после ввода пароля?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Запустите ярлык на CLI из окна CMD и смотрите сообщения. Больше всего похоже на сбой аутентификации.
    Ответ написан
    2 комментария
  • Объясните CASE WHEN THEN?

    @Akina
    Сетевой и системный админ, SQL-программист.
    ...
    SET view = CASE ad_id WHEN 34 THEN 0
                          WHEN 35 THEN 1 
                          WHEN 36 THEN 2
                          END,
        amount = CASE WHEN ad_id = 36 
                      THEN 466
                      ELSE amount
                      END
    WHERE ad_id  IN (34, 35, 36);
    Ответ написан
    3 комментария
  • Как вставить данные сразу в 2 объединенные таблицы?

    @Akina
    Сетевой и системный админ, SQL-программист.
    в какой таблице будет храниться набор необходимых полей для вставки неизвестно

    Бред сивой кобылы (извиняюсь). Структура (точные имена полей, и в какой таблице какое поле) обязана быть заранее известна. Даже если используется псевдодинамическая структура на базе EAV или иным способом организованная.

    у меня есть 2 таблицы или допустим будет 3 ... Я хочу при выполнении insert into или update использовать эти таблицы

    MySQL не реализует одновременную вставку в более чем одну таблицу. А также не реализует использование запроса на вставку в CTE. Напрямую задача не решается.

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

    Возможная (но нерекомендуемая) реализация - триггер на базовой таблице и передача параметров для подчинённых таблиц через определённые пользователем переменные.
    Ответ написан
    Комментировать
  • Как перенести большую базу на другой сервер без простоев?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Рабочий ли вариант если просто через rsync передать всю папку /var/lib/mysql?

    Просто перенос файлов рабочей БД окончится тем, что файлы есть, а базы нет, потому что неоткуда взяться метаданным в системной базе данных. Вернее, всё ещё забавнее - базы вроде бы и нет (USE приводит к ошибке "БД не существует"), но её нельзя создать, потому что она есть. И то же самое с таблицами (SELECT/DROP/прочее нельзя, потому что таблицы нет, CREATE нельзя, потому что она есть).

    Метод сработает, если переносить все БД сразу, включая служебные. Но требуется точное соответствие исходной и конечной конфигураций - начиная с версии и сборки MySQL и кончая именами каталогов и именами/паролями учётных записей в операционной системе. Плюс перегенерация и переподключение сертификатов.

    Еще вариант с репликацией, но насколько я понял всё равно базу нужно блокировать на момент дампа, а это тоже какое-то время

    Решений без блокирования практически не существует. Нет, можно наколхозить реальное решение, которое обойдётся вообще без остановки, я даже представляю как именно (FEDERATED ENGINE + triggers), но подробно рассказывать не буду - для её реализации нужны достаточная квалификация и опыт, на одних советах шанс на удачу невелик, скорее всё поломается.

    Есть вполне себе документированные способы: Copying MySQL Databases to Another Machine. Особенно последний из описанных. Он предполагает минимальное время простоя при использовании штатных средств.
    Ответ написан
    Комментировать
  • Как вывести записи по ближайшей дате сгруппированные по категориям в MySQL 5.7?

    @Akina
    Сетевой и системный админ, SQL-программист.
    На версии 8+ как-то так:
    WITH cte AS (
        SELECT `events`.`id`,
               `events`.`date_public`,
    	   `event_categories`.`id` as `cat_id`,
    	   `event_categories`.`title` as `cat_title`
    	   ROW_NUMBER() OVER (PARTITION BY `event_categories`.`id` ORDER BY `events`.`date_public` ASC) rn
        FROM `events`
        INNER JOIN `event_category_joins` ON `events`.`id` = `event_category_joins`.`event_id` 
        INNER JOIN `event_categories` ON `event_categories`.`id` = `event_category_joins`.`event_category_id` 
        WHERE `events`.`date_public` >= '2024-04-05 19:00:00'
    --    WHERE `events`.`date_public` >= CURRENT_DATE
        )
    SELECT id, date_public, cat_id, cat_title
    FROM cte
    WHERE rn = 1;
    Ответ написан
    1 комментарий
  • Как кучу файлов с дампами таблиц соединить в один?

    @Akina
    Сетевой и системный админ, SQL-программист.
    type X:\sql_files_folder\*.sql | Z:\mysql_bin_folder\mysql -D database_name -u account_name -p

    И молись, чтобы в файлах не было синтаксических ошибок...
    Ответ написан
    Комментировать
  • Что такое кластерный индекс в mysql?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Кластерный индекс... это на самом деле понятие крайне виртуальное.

    Что такое обычный некластерный индекс? берём выражение индекса, считаем его значение для каждой записи, сортируем и пишем на диск. Получаем отдельную структуру, в которой выражение индекса сортировано. Когда потребуется искать заданное значение этого выражения, мы вместо просмотра от записи к записи сразу половинным делением быстренько найдём нужное значение, возьмём из него уникальный идентификатор записи, и обратимся за записью. Если в таблице 1000 записей, то для поиска заданного значения без индекса нам в среднем пришлось бы просмотреть 500 записей, а с индексом - всего 10.

    Теперь что такое кластерный индекс... сначала почти то же. Берём выражение индекса, считаем его значение для каждой записи, сортируем и... а вот теперь не записываем по порядку эти значения с номерами соответствующих записей в отдельную структуру, а сами записи располагаем в этом порядке. Теперь, когда потребуется искать заданное значение этого выражения, мы вместо просмотра от записи к записи, как это было, когда записи не сортированы, сразу половинным делением быстренько найдём нужное значение. Но нам уже не надо получать номер записи и обращаться за ней - мы нашли саму нужную запись.

    В MySQL (точнее, в используемом по умолчанию движке InnoDB) первичный индекс, во-первых, существует ВСЕГДА, во-вторых, определяется так (в статье, на которую дали ссылку, имеются неточности в пункте 2):
    1. Если первичный ключ задан явно, то его выражение является также и выражением кластерного индекса. Или иначе - первичный ключ и есть кластерный индекс.
    2. Если первичный ключ явно не задан, но в таблице имеется индекс, отвечающий всем следующим требованиям:
      • является уникальным
      • не является функциональным, в т.ч. не использует в выражении вычисляемые поля
      • не использует в выражении поля, которые определены как допускающие значение NULL

      то именно такой индекс используется в качестве первичного. А если таких индексов несколько, то используется первый по тексту запроса на создание таблицы
    3. Если не имеется ни того, ни другого - генерируется синтетический скрытый 6-байтовый номер записи, который и используется как первичный ключ. Следует отметить, что штатных способов доступа к этому значению не существует.


    Выглядит так, как будто это просто физическая сортировка данных по индексируемому полю.

    Фактически - именно так.

    Создаётся ли отдельная таблица или просто упорядочивается хранение существующих данных?

    Не создаётся. Но при изменении первичного индекса таблица полностью пересоздаётся с новым физическим порядком записей.

    Если данные упорядочиваются этим индексом, допустим по ID, то почему при select без сортировки данные могут возвращаться в произвольном порядке, а не отсортированные по ID по-умолчанию?

    Если не задан явно ORDER BY, сервер имеет право вернуть записи в любом порядке, как ему удобнее. В большинстве случаев, но не всегда, он будет возвращать записи в порядке чтения с диска...

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

    ===

    PS. Кстати, правило выбора индекса, который будет использоваться в качестве кластерного, имеет неприятный побочный эффект. Если у некоторых полей, входящих в какие-то индексы, изменяется свойство NULLability, то это может привести к изменению того, какой из имеющихся индексов станет использоваться в качестве первичного по пункту 2. В результате мы получим невозможность использования INSTANT / INPLACE методов, и будет использован длинный COPY. Впрочем, ситуация такая крайне редка.
    Ответ написан
    2 комментария
  • Как оптимизировать запрос через Sqlalchemy?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Если отформатировать запрос, чтобы было видно, что происходит, получим следующее:

    SELECT coalesce(A.id, :coalesce_1) AS card_id, 
           coalesce(A.serial_number, :coalesce_2) AS card_number, 
           coalesce(B.name, :coalesce_3) AS prj_name, 
           coalesce(C.name, :coalesce_4) AS client_name, 
           coalesce(A.user_name, :coalesce_5) AS card_owner_name, 
           coalesce(A.user_phone_number, :coalesce_6) AS card_owner_phone_number, 
           coalesce(A.balance_current, :coalesce_7) AS current_balance, 
           coalesce(A.balance_bonus, :coalesce_8) AS bonus_balance, 
           coalesce(A.active, :coalesce_9) AS card_status, 
           coalesce(D.name, :coalesce_10) AS tariff_plan_name, 
           NULL AS anon_1 
    FROM cashless_card 
    JOIN company ON cashless_card.company_id = company.id 
    JOIN voc ON cashless_card.voc_id = voc.id 
    LEFT OUTER JOIN tariff_plan ON cashless_card.tariff_plan = tariff_plan.id 
    WHERE cashless_card.company_id IN (__[POSTCOMPILE_company_id_1])

    Почти очевидно, что в таблицах company, voc и tariff_plan поле по имени id - это первичный ключ... но хотелось бы подтверждения.

    Впрочем, видно, что для оптимизации запроса в таблице cashless_card крайне желательно наличие индекса (company_id). Следует также проверить эффективность индекса (company_id, voc_id, tariff_plan), и аналогичного с переставленными местами последними 2 полями (первым ставить то, которое более селективно).

    Кроме того, эффективность запроса сильно зависит от количества идентификаторов в списке, который передаётся в условие WHERE cashless_card.company_id IN (__[POSTCOMPILE_company_id_1]). Если их более десятка, есть смысл преобразовать этот список в набор данных (синтетическая UNION-таблица) и использовать как ещё один источник данных запроса.

    Ну и надо понимать, что наличие LIMIT/OFFSET только замедляет выполнение запроса. Причём чем больше OFFSET, тем сильнее это замедление.
    Ответ написан
    6 комментариев