Ответы пользователя по тегу MySQL
  • Как работает GROUP BY?

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

    Например, пишу я такой SELECT и все нормально
    SELECT Trip.plane, Trip.id


    Ну да, тебе нужны отдельные самолёты, соответственно никакие группы не нужны. GROUP BY не требуется.

    Но при таком мне выдает ошибку
    SELECT Trip.plane, COUNT(Trip.plane) planes

    А вот теперь ты хочешь, поделив все имеющиеся самолёты на группы, собрав в каждую группу самолёты одного типа, посчитать в каждой группе количество самолётов. И для того, чтобы указать, по какому признаку нужно делить на группы, требуется GROUP BY.
    Ответ написан
    2 комментария
  • Откуда берется /*!40001 SQL_NO_CACHE */ в запросе при создании дампа?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Отвечу всё же на заданный вопрос:
    Откуда это берется вообще? /*!40001 SQL_NO_CACHE */ и как это убрать?

    Это - комментарий с фрагментом запроса, специфичным для MySQL.

    Помещается в тело запроса (в т.ч. в дамп) для того, чтобы запрос, использующий какую-либо специфичную для MySQL конструкцию, мог быть выполнен в другом SQL-диалекте без внесения изменений в текст запроса. Т.е. MySQL обрабатывает содержимое такого комментария так, словно этот фрагмент не закомментирован, тогда как другие СУБД проигнорируют этот фрагмент как комментарий.

    Опциональное пятизначное число указывает минимальную версию MySQL, начиная с которой содержимое комментария должно обрабатываться (в показанном фрагменте - это версия 4.00.01), на более младшей версии комментарий останется комментарием. При его отсутствии (используется только /*!) - код из комментария обрабатывается любой версией.

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

    @Akina
    Сетевой и системный админ, SQL-программист.
    В голове идея создать varchar ячейку и в неё через запятую всё записывать.

    С точки зрения работы с СУБД хранение массива данных в виде CSV-значения - крайне неудачный вариант. И весьма проблемный в обработке. Впрочем, если речь идёт о достаточно статичном массиве данных в сотню записей - вариант допустимый.

    Нормализованная структура, удобная в обработке, может выглядеть, например, так (само собой, это только кусок для хранения слов и фраз):
    CREATE TABLE words (
        word_id INT AUTO_INCREMENT PRIMARY KEY,
        word VARCHAR(255) UNIQUE NOT NULL
    );
    
    CREATE TABLE phrase (
        phrase_id INT NOT NULL,
        FOREIGN KEY (phrase_id) REFERENCES phrases (phrase_id),
        word_id INT NOT NULL,
        FOREIGN KEY (word_id) REFERENCES words (word_id),
        word_position INT,
        PRIMARY KEY (phrase_id, word_position)
    );
    Ответ написан
  • Экспорт данных из QUIK по ODBC. Как налету преобразовывать VARCHAR-поля в правильные (DATE, DECIMAL, ENUM)?

    @Akina
    Сетевой и системный админ, SQL-программист.
    В тексте запроса ЛЮБЫЕ данные представлены как их строковые представления. Да что там - сам SQL-запрос есть строковый литерал.

    Поэтому следует озаботиться исключительно правильным представлением. Форматом. Если данные - число, то десятичным разделителем должна быть точка. Если это дата или строка - должны присутствовать обрамляющие кавычки, причём дата должна быть в формате, понятном текущей СУБД (предпочтительно YYYY-MM-DD - этот формат понимают все СУБД), а в строке должны быть экранированы все символы, являющиеся служебными. И т.п.

    Если выгруженные данные не соответствуют этому формату, то в запросе на добавление можно использовать не напрямую значение (и потом маяться дурью в процедуре/триггере), а, используя встроенные функции, преобразовать данные к правильному типу. Например, если в поле надо вставить число, а в выгрузке использована запятая в качестве разделителя, это будет
    INSERT ... VALUES ( ... , CAST(REPLACE(@value, ',', '.') AS DOUBLE), ...
    Ответ написан
    Комментировать
  • Как связать много сущностей к одной в результате?

    @Akina
    Сетевой и системный админ, SQL-программист.
    SELECT for_output
    FROM ( SELECT name AS film_name, name AS for_output
           FROM films
         UNION ALL
           SELECT films.name, comments.comment
           FROM films 
           JOIN comments USING (film_id) ) total
    ORDER BY film_name, film_name <> for_output
    Ответ написан
    Комментировать
  • Почему долгий запрос delete к таблице сильно тормозит запросы insert к другим таблицам?

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

    Организуйте удаление пакетами. Скажем, по 10к записей.
    CREATE PROCEDURE delete_rows()
    BEGIN
        SELECT @@autocommit INTO @autocommit;
        SET SESSION autocommit = ON;
        REPEAT
            DELETE FROM bigtable WHERE state=2 LIMIT 10000;
            SELECT SLEEP(1) INTO @tmp;
        UNTIL NOT ROW_COUNT() END REPEAT;
        SET SESSION autocommit = @autocommit;
    END
    Ответ написан
    Комментировать
  • Как планировать даты по указанному расписанию (из списка времен)?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Упрощённый пример того, как ежедневно в 09:20, 09:40, 11:20 и 11:40 вставлять в таблицу запись с заданными значениями.

    Таблицы:

    1. Значения для вставки
    CREATE TABLE data ( 
        data_id INT AUTO_INCREMENT PRIMARY KEY,
        data_for_insertion VARCHAR(255) );
    INSERT INTO data VALUES (1, 'Новое сообщение по расписанию', DEFAULT);

    2.Расписание.
    CREATE TABLE schedule ( 
        schedule_id INT AUTO_INCREMENT PRIMARY KEY,
        data_id INT,
        FOREIGN KEY (data_id) REFERENCES data (data_id) ON DELETE CASCADE ON UPDATE CASCADE,
        shedule_time TIME );
    INSERT INTO schedule VALUES 
    (NULL, 1, '09:20'), 
    (NULL, 1, '09:40'), 
    (NULL, 1, '11:20'), 
    (NULL, 1, '11:40');

    3. Таблица, куда надо вставлять записи
    CREATE TABLE main ( 
        main_id INT AUTO_INCREMENT PRIMARY KEY,
        inserted_data VARCHAR(255),
        created_as DATETIME DEFAULT CURRENT_TIMESTAMP );

    Процедура, которая будет вставлять данные
    CREATE EVENT schedule
    ON SCHEDULE EVERY 1 MINUTE
    DO
        INSERT INTO main (inserted_data)
        SELECT data.data_for_insertion
        FROM data
        JOIN schedule USING (data_id)
        WHERE schedule_time > CURRENT_TIME - INTERVAL 1 MINUTE
          AND schedule_time <= CURRENT_TIME;

    Всё. Осталось только разрешить использование Event Scheduler и запустить его.

    Теперь только знай себе в своей программе на PHP правь данные в таблицах 1 и 2. Причём в любое время... В части выполнения нужного действия в нужное время MySQL всё будет делать сам, и никакого PHP ему не требуется.
    Ответ написан
    Комментировать
  • Как составить запрос к MYSQL?

    @Akina
    Сетевой и системный админ, SQL-программист.
    SELECT UserID, t1.CountMessage-t2.CountMessage
    FROM daily_exp_snapshots t1
    JOIN daily_exp_snapshots t2 USING (UserID)
    WHERE t1.date_added >= CURRENT_DATE
      AND t1.date_added < CURRENT_DATE + INTERVAL 1 DAY
      AND t2.date_added >= CURRENT_DATE - INTERVAL 1 DAY
      AND t2.date_added < CURRENT_DATE
    Ответ написан
    Комментировать
  • Как выбрать конкретную строку из Mysql?

    @Akina
    Сетевой и системный админ, SQL-программист.
    SELECT SUBSTRING_INDEX(SUBSTRING(full FROM 30 + LOCATE('https://www.youtube.com/embed/', full)), '"', 1)
    FROM params
    WHERE LOCATE('https://www.youtube.com/embed/', full)
    -- AND id=247397
    Ответ написан
  • Как в одном SQL запросе вывести идентификаторы клиентов, у которых нет счёта?

    @Akina
    Сетевой и системный админ, SQL-программист.
    SELECT client
    FROM ( SELECT DISTINCT client
           FROM Dep
         UNION ALL
           SELECT client_id
           FROM Contact ) total
    GROUP BY 1
    HAVING COUNT(*) = 1
    Ответ написан
    Комментировать
  • Как вывести всех родителей у подкатегории до главной категории?

    @Akina
    Сетевой и системный админ, SQL-программист.
    WITH RECURSIVE
    cte AS ( SELECT *, 1 level
             FROM category 
             WHERE id = $category_id
             UNION ALL
             SELECT cat.*, cte.level + 1
             FROM category cat
             JOIN cte ON cat.id = cte.parent_id )
    SELECT *
    FROM cte
    ORDER BY level;

    Для древних версий:
    SELECT CONCAT_WS('=>', c1.id, c2.id, c3.id, c4.id, c5.id) path
    FROM category c1
    LEFT JOIN category c2 ON c1.parent_id = c2.id
    LEFT JOIN category c3 ON c2.parent_id = c3.id
    LEFT JOIN category c4 ON c3.parent_id = c4.id
    LEFT JOIN category c5 ON c4.parent_id = c5.id
    WHERE c1.id = $category_id

    Ну соответственно подрихтовать до нужного вида выходного набора.
    Ответ написан
    4 комментария
  • Как найти в mysql ряд где значение json массива равно значению?

    @Akina
    Сетевой и системный админ, SQL-программист.
    В качестве демонстрации, что "Сервер умнее, чем вы думаете!":

    SELECT id, CAST(array_test AS CHAR) array_test 
    FROM test
    WHERE JSON_OVERLAPS(array_test, CAST('[2]' AS JSON));


    DEMO fiddle

    PS. Да, там именно запятая. И знак - именно восклицательный.
    Ответ написан
    Комментировать
  • Как побороть ошибку #1032 - Невозможно найти запись?

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

    DEMO

    Походу, это phpmyadmin в очередной раз показал своё свиное рыло...
    Ответ написан
    Комментировать
  • Как правильно составить запрос для поиска по JSON полю в mySql?

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

    SELECT DISTINCT action.*
    FROM action
    CROSS JOIN JSON_TABLE(action.`condition`,
                          '$[*].action' COLUMNS (action INT PATH '$')) jsontable
    WHERE jsontable.action = 6


    https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=c3e97c...
    Ответ написан
    Комментировать
  • Как получить скользящее значение для дискретных данных?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Пример с линейной интерполяцией.

    WITH 
    cte1 AS ( SELECT t1.ts, t1.val,
                     t2.ts ts_before, t2.val val_before,
                     t3.ts ts_after, t3.val val_after
              FROM test t1
              JOIN test t2 ON t1.ts >= TIMESTAMP(t2.ts, @delta)
              JOIN test t3 ON t1.ts <= TIMESTAMP(t3.ts, @delta) ),
    cte2 AS ( SELECT *, 
                     ROW_NUMBER() OVER (PARTITION BY ts ORDER BY ts_before DESC) rn_before, 
                     ROW_NUMBER() OVER (PARTITION BY ts ORDER BY ts_after ASC) rn_after
              FROM cte1 )
    SELECT ts,
           val,
           ts_before,
           val_before,
           ts_after,
           val_after,
           CASE WHEN val_after = val_before
                THEN val_before
                ELSE val_before + (val_after - val_before) / TIMESTAMPDIFF(SECOND, ts_after, ts_before) * TIMESTAMPDIFF(SECOND, ts, TIMESTAMP(ts_before, @delta)) 
                END val_approximated
    FROM cte2 
    WHERE ts > '2021-01-02'
          AND rn_before = 1
          AND rn_after = 1


    DEMO fiddle с некоторыми пояснениями.

    Тормозить, конечно, на большом массиве будет нещадно - так что неплохо бы ещё в первом CTE по всем трём копиям задать вменяемые границы от и до...

    Не имел дела раньше с оконными функциями в MySQL.

    А придётся. И не просто "иметь дело", а хорошо изучить, до полного понимания.
    Ответ написан
    2 комментария
  • Как удалить кортеж из массива по значению кортежа?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Поделить на элементы, отбросить ненужные, собрать обратно:
    WITH cte AS (SELECT 1 id, CAST('[12, 13, {"12": 123} ]' AS JSON) sort)
    SELECT cte.id, JSON_ARRAYAGG(jsontable.element) sort
    FROM cte
    CROSS JOIN JSON_TABLE(cte.sort,
                          '$[*]' COLUMNS (element JSON PATH '$')) jsontable
    WHERE jsontable.element != CAST('{"12": 123}' AS JSON)
    GROUP BY cte.id

    https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=405ff0...

    PS. Сравнение объектов JSON - занятие неблагодарное. В более сложных случаях не пройдёт, даже JSON_OVERLAPS() может не спасти. Возможно, использование строковых функций на строковом представлении JSON более правильное решение.
    Ответ написан
    Комментировать
  • Зачем нужны внешние ключи прописанные в структуре БД (MySQL) - они действительно там нужны?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Любая СУБД имеет достаточно мощную систему контроля целостности и непротиворечивости данных. Эта система работает, используя набор правил контроля, описанных в структуре БД, и жёстко следит за тем, чтобы ни одно из правил не было нарушено.

    Внешний ключ - это как раз такое правило. Сформулировано оно так: в данном поле таблицы не может храниться значение, которое не присутствует в той таблице, на которую ссылается внешний ключ (rонечно, в зависимости от конкретного текста ссылки внешнего ключа и самого поля тут возможны варианты - например, в этом поле может храниться не только значение, присутствующее в ссылочной таблице, но и NULL). И, имея такое правило, СУБД ни при каких условиях не позволит его нарушить. Любая попытка вставить запись со значением, которого нет в ссылочной таблице, приведёт к ошибке. Любая попытка изменить существующее значение на такое, которого "там" нет - приведёт к ошибке. То же касается и "второй" стороны, СУБД не позволит изменить значение в ссылочной таблице или удалить его (потому что записи в нашей таблице при этом "потеряют" ссылку) - такая попытка корректировки приведёт к ошибке.
    Ответ написан
    2 комментария
  • Как синхронизировать две mysql базы?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Если оба MySQL-сервера взаимно доступны, то для решения задачи можно использовать FEDERATED Storage Engine.

    На " другом сервере, где вертится аналитика самописная", перезапускаете MySQL, включив FEDERATED Engine. Далее создаёте подключение (CREATE SERVER), создаёте копию удалённой таблицы на этом сервере - и просто копируете из неё записи за последний месяц. Либо без сервера - прямо при создании таблицы указываете параметры подключения.
    Ответ написан
  • Для чего нужно вводить Имя хоста в учетную запись пользователя mysql?

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

    Имя пользователя - задаётся пользователем при подключении. Хост (имя либо адрес) определяется сервером MySQL. самостоятельно, и на этот процесс пользователь почти не имеет возможности повлиять. Объединение этих двух частей и даст полное имя, которое будет использоваться для определения привилегий.

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

    Подробно всё это объясняется в документации в разделе Access Control and Account Management.
    Ответ написан
    Комментировать
  • Как вывести последние сообщение?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Если ориентироваться на пример, а не на описание задания, то
    WITH
    cte AS ( SELECT *, 
                    ROW_NUMBER() OVER (PARTITION BY sender, receiver ORDER BY created_at DESC) rn
             FROM message )
    SELECT u1.username sendername,
           u2.username receivername,
           cte.text_message,
           cte.created_at
    FROM cte 
    JOIN users u1 ON cte.sender = u1.id
    JOIN users u2 ON cte.receiver = u2.id
    WHERE cte.rn = 1

    https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=a7a647...
    Ответ написан
    1 комментарий