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

    @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
    Ответ написан
    Комментировать
  • Как составить запрос к 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 комментарий
  • Проблема с regexp на mysql 8.0.26?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Согласно MySQL 5.7 Reference Manual / ... / Regular Exp...

    [[:<:]], [[:>:]]

    These markers stand for word boundaries.


    Согласно MySQL 8.0 Reference Manual / ... / Regular Exp...

    The Spencer library supports word-beginning and word-end boundary markers ([[:<:]] and [[:>:]] notation). ICU does not. For ICU, you can use \b to match word boundaries; double the backslash because MySQL interprets it as the escape character within strings.


    Так что подход правильный.

    Но Вы не учитываете, что слэш надо квотить как для PHP, так и для MySQL. Т.е. их должно быть не два, а четыре.
    Ответ написан
    Комментировать
  • SQL запрос как создать 9999 записей с итерацией чисел?

    @Akina
    Сетевой и системный админ, SQL-программист.
    1. Вот оно надо, каждый раз заботиться об установлении значений полей DATE_CREATE/DATE_UPDATE?

    ALTER TABLE tablename
    MODIFY COLUMN date_create TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    MODIFY COLUMN date_update TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;

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

    2. Для выполнения операции используем рекурсивный CTE (помним, что поля DATE_CREATE/DATE_UPDATE сами заботятся о правильном значении, как и автоинкрементный первичный ключ):

    INSERT INTO tablename (active, user_id, value)
    WITH RECURSIVE
    cte AS ( SELECT 1 num
             UNION ALL
             SELECT num + 1 FROM cte WHERE num < 9999 )
    SELECT 1, 1, num
    FROM cte;


    Возможно, предварительно надо установить достаточное значение для сессионной переменной:SET SESSION cte_max_recursion_depth = 10000;

    Если версия MySQL старая и не понимает CTE, то

    INSERT INTO tablename (active, user_id, value)
    SELECT 1, 1, 1 + t1.num + t2.num * 10 + t3.num * 100 + t4.num * 1000 AS value
    FROM       (SELECT 0 num UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t1
    CROSS JOIN (SELECT 0 num UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t2
    CROSS JOIN (SELECT 0 num UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t3
    CROSS JOIN (SELECT 0 num UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t4;
    HAVING value <= 9999;
    Ответ написан
    1 комментарий
  • Как правильно спроектировать связь БД между двумя товарами?

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

    CREATE TABLE groups_of_goods (
        group_id BIGINT UNSIGNED NOT NULL,
        product_id BIGINT UNSIGNED NOT NULL,
        PRIMARY KEY (group_id, product_id),
        FOREIGN KEY fk_product (product_id) REFERENCES product (product_id)
    );


    Соответственно если твои труселя входят в одну группу и ссылаются друг на друга, то в таблице будут 2 записи - (123, 10) и (123, 15).

    Кстати, такая схема обеспечивает и принцип "вассал моего вассала ...". Т.е. "пиджак малиновый" может ссылаться на "брюки малиновые" (через группу 456) и "пиджак в полоску" (через группу 789), но при этом последние два друг на друга ссылаться не будут, ибо разные группы.
    Ответ написан
    2 комментария
  • Какой должен быть тип строки в БД для номера телефона, состоящего из одних цифр?

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

    Если так, то предлагаю с самим полем ничего не делать, пусть себе будет текстовое и со всякой фигнёй. А для использования создать ещё одно, вычисляемое, поле, в которое класть очищенное и приведённое к числовому значение.

    Т.е. если сейчас имеется
    CREATE TABLE users (
        ...
        phone VARCHAR(255),
        ....
    );

    то выполняем
    ALTER TABLE users ALGORITHM = INPLACE
        ADD COLUMN phone_num BIGINT UNSIGNED AS (REGEXP_REPLACE(phone, '[^0-9], ''')) VIRTUAL,
        INDEX idx_phone_num (phone_num);


    Что это даёт?

    Выражение вычисляемого поля чистит строковое значение от всего, что не цифра, после чего значение преобразуется в тип данных поля, т.е. BIGINT UNSIGNED. Отлично, число получено.

    Поле объявлено как VIRTUAL. Это означает, что его значение не хранится в таблице, а вычисляется каждый раз, когда оно потребуется. Но мы создаём по этому полю индекс. Соответственно сервер может не вычислять значение, а извлечь его из индекса. Ещё лучше, если это поле будет включено в композитные индексы вместо поля phone - тогда вероятность, что сервер будет извлекать значение из индекса, увеличится.

    Конечно, можно было бы сделать поле STORED и не морочиться с индексом. Но тогда процесс изменения структуры таблицы будет достаточно длительным, потому что такая операция не может быть INPLACE и требует COPY. Впрочем, это может оказаться более подходящим в определённых условиях.

    Да, следует помнить, что в это поле нельзя записывать значения ни при INSERT, ни при UPDATE - такая операция приведёт к ошибке. Так что про запросы без указания списка полей придётся забыть... ну и SELECT * - тоже забыть.
    Ответ написан
    Комментировать
  • Как правильно сделать Mysql "точный" like запрос?

    @Akina
    Сетевой и системный админ, SQL-программист.
    1. Использовать не LIKE, а функции поиска подстроки (INSTR или LOCATE)
    2. Задать требуемый collation (вплоть до BINARY)
    Ответ написан
    Комментировать