• Mysql, как выполнять события(events) только при условии?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Если просто переписать в соответствии с правильным синтаксисом, и при этом избавиться от ненужного IF, то
    CREATE DEFINER=`sql_test`@`%` EVENT `Маркировка` 
    ON SCHEDULE 
        EVERY 1 HOUR 
        STARTS '2022-05-29 23:15:23' 
    -- ON COMPLETION NOT PRESERVE   -- не имеет смысла для периодической задачи
    -- ENABLE                       -- по умолчанию эвент включен при создании
    DO
    UPDATE `tasks` 
    SET `status` = 4  
    WHERE `status` = 3
      AND EXISTS ( SELECT NULL  
                   FROM `config` 
                   WHERE `name` = 'profile_deleting'
                     AND `value` = 'allowed' );

    Однако логика какая-то странная - обновляются все записи, и при этом проверяется наличие абы какой записи. Хотя разум требует наличия зависимости между обновляемой и проверяемой записями.

    ======

    Впрочем, никто не запрещает сохранить исходный вид:
    CREATE DEFINER=`sql_test`@`%` EVENT `Маркировка` 
    ON SCHEDULE 
        EVERY 1 HOUR 
        STARTS '2022-05-29 23:15:23' 
    -- ON COMPLETION NOT PRESERVE 
    -- ENABLE 
    DO
    BEGIN
      IF (SELECT `value` FROM `config` WHERE `name` = 'profile_deleting') = 'allowed' THEN 
        UPDATE `tasks` SET `status` = 4  WHERE `status` = 3;
      END IF;
    END;

    Но:
    1. при создании такой процедуры придётся переопределять DELIMITER
    2. если подзапрос вернёт более одной записи - это приведёт к ошибке

    Проблему с возвращающим более одной записи подзапросом можно поправить следующим изменением:
    IF 'allowed' IN (SELECT `value` FROM `config` WHERE `name` = 'profile_deleting') THEN
    Ответ написан
    3 комментария
  • В чем ошибка sql-запроса?

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

    Формально запрос содержит несколько ошибок и недочётов.

    • Основная ошибка, вернее, опечатка - это WARCHAR вместо VARCHAR. Она фатальна.
    • Вторая по тяжести ошибка - это использование служебного слова number в качестве имени поля. В части диалектов SQL это слово - зарезервированное, и тогда эта ошибка тоже фатальна.
    • Третье - это скорее не ошибка, а самообман. Речь об указании длины для полей типа INT. В подавляющем большинстве диалектов, где указание длины допускается, оно просто игнорируется, а потому указание просто не имеет смысла. Если для поля number требуется ограничить возможные значения двумя цифрами, разумнее использовать поле типа TINYINT с соответствующим CHECK constraint.
    • Ну и длина поля типа VARCHAR - опять же ограничение в 55 символов разумнее делать с помощью CHECK constraint, а длину поля задавать максимальную, не приводящую к увеличению потребляемого дискового пространства. С учётом того, как хранятся строки переменной длины, VARCHAR(255) в большинстве диалектов будет наилучшим решением.
    Ответ написан
    Комментировать
  • Как найти строку по значению и изменить соседнее значение?

    @Akina
    Сетевой и системный админ, SQL-программист.
    WebDiez
    Затупил.. Нашел вариант..

    Пока надо обновлять для строго одной записи - сойдёт. А вообще
    UPDATE request 
    JOIN ( SELECT MAX(id) id 
           FROM request 
           WHERE user_id IN ( '97'  /* список */ )
         ) subquery USING ( id )
    SET request.message = 'text';
    Ответ написан
    Комментировать
  • Как сделать массовое обновление записей в mysql?

    @Akina
    Сетевой и системный админ, SQL-программист.
    WITH `cte` AS (
        SELECT 123 `id`, 1 `stat` UNION ALL
        SELECT 321     , 2        UNION ALL
     -- ...
        SELECT 456     , 8        UNION ALL
        SELECT 789     , 9
    )
    UPDATE `data`
    JOIN   `cte` USING ( `id` )
    SET `data`.`stat` = `cte`.`stat`;
    Ответ написан
    6 комментариев
  • Как сделать чтобы строка не вставлялась в БД, если не соблюдается формат поля?

    @Akina
    Сетевой и системный админ, SQL-программист.
    ALTER TABLE customer
    ADD CONSTRAINT CHECK(phone REGEXP '^[0-9]{3}-[0-9]{2}-[0-9]{3}$');

    https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=71012d...
    Ответ написан
    Комментировать
  • В чем отличие ACL от Firewall?

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

    Firewall - это программа или комплекс программ, выполняющая фильтрацию на основе правил. В т.ч. на основе ACL.
    ACL - это правило либо блок данных для правила. В т.ч. это может быть и правило для Firewall.
    Ответ написан
    2 комментария
  • Нужно использовать триггеры или нет??

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

    Как я понимаю, мысль твоя бредёт вот в каком направлении: мы выполняем INSERT в основную таблицу, а триггер AFTER INSERT, имеющий доступ к сгенерированному значению автоинкрементного ключа именно свежесозданной записи, создаёт записи в связанных таблицах, используя именно это значение.

    Так вот именно эта мысль - она некорректная. Причём по совершенно элементарной причине. Данные для вставки в связанных таблицах (не поля связи - других полей) триггер тоже должен откуда-то взять. А вот корректно передать их достаточно непросто. Их нельзя вставить в блок данных основной записи - там просто места для этого нет, сервер перед выполнением INSERT проверяет входные данные на соответствие количества значений количеству переданных данных, соответствие типов, непревышение размеров и пр. Значит, данные придётся передавать за пределами запроса. Да, тут есть варианты, типа определённых пользователем переменных, временных таблиц и протчая - но всё это ненадёжно, сложно и совершенно несопровождаемо. Следует ещё учесть то, что триггеры - это конструкция неотключаемая. Либо она выполняется при абсолютно любом INSERT, и тогда есть определённые проблемы (триггер, предназначенный для работы при INSERT .. VALUES с единственным блоком данных, вряд ли корректно обработает вставку нескольких блоков данных, INSERT .. SELECT или LOAD DATA), либо для выполнения запросов на массовое добавление триггер надо удалять и потом пересоздавать - а если это происходит в конкурентной среде?

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

    при регистрации пользователя, я получаю lastInserdId() и добавляю статичные данные для этого пользователя в различные таблицы

    Ненадёжно. Если между вставкой в основную таблицу и получением LAST_INSERT_ID() соединение будет разорвано и затем автоматически восстановлено, то полученное значение будет некорректным (вернее, получите NULL). А свежесозданная запись благополучно "повиснет в воздухе".
    Чисто теоретически, базовая таблица пользователей обязана обеспечивать уникальность записи даже без учёта синтетического первичного ключа (например, поле логина явно должно быть уникальным). А коли так, и с учётом того, что все значения для свежевставленной записи нам известны, можно использовать INSERT INTO slave SELECT 'literal', main.id FROM main WHERE uniquecolumn = 'new value'.

    PS. Не знаю, почему при обучении вставке данных все начинают с INSERT .. VALUES - как по мне, глубоко порочная практика. Сначала надо изучить и досконально освоить INSERT .. SELECT, и только потом упоминать про INSERT .. VALUES как более простой конструкции, применимой в частных случаях.
    Ответ написан
    1 комментарий
  • Возможно ли узнать последнюю дату изменения таблицы mysql?

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

    Решение через INFORMATION_SCHEMA.TABLES.UPDATE_TIME - это плюс-минус лапоть. Для большинства движков - это время обновления файла таблицы в файловой системе, а вовсе даже не время выполнения последней записи по результатам выполнения последнего запроса на изменение данных (да-да, для долгого запроса это будет SYSDATE() последней изменённой записи, а не CURRENT_TIMESTAMP). Да и на дефолтном InnoDB не всё слава богу - кэширование запросто может добавить несколько секунд, а при отключенном file_per_table и на партиционированных таблицах так и вовсе не работает.
    Ответ написан
    1 комментарий
  • Доказано ли, и можно ли сжать произвольные данные до 20 байтов к примеру?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Допустим, существует некий алгоритм, который преобразует последовательность X длины M в последовательность Y, причём существует обратное преобразование. Неважно, что это за алгоритм конкретно - сжатие, создание "зерна" и пр. Но очевидно, что:

    1. Количество вариантов последовательности X составляет K в степени M, где K - размер словаря, т.е. количество возможных различимых значений одного элемента последовательности X. В случае байтовой последовательности это байт, т.е. K=256.

    2. Каждая последовательность X после преобразования даёт последовательность Y, причём две разные последовательности X дают разные последовательности Y.

    Соответственно количество возможных последовательностей Y равно количеству возможных последовательностей X. И соответственно если существует хотя бы одна последовательность Y короче последовательности X, то существует хотя бы одна последовательность Y длиннее последовательности X.

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

    Что же до "зерна", которое разворачивается в гигабайты - во-первых, количество финальных миров определяется количеством значений "зерна", то есть вовсе даже не такое бесконечно большое, как кажется, во-вторых, созданный образ мира содержит значительное число повторяющихся элементов, а создание копий - это немножко не декомпрессия.
    Ответ написан
    Комментировать
  • Как отсортировать запрос с UNION?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Если отформатировать запрос, то он выглядит так:
    SELECT * FROM `rsi` WHERE `tf`='4h'                         UNION 
    SELECT * FROM `rsi` WHERE `tf`='15m'                        UNION 
    SELECT * FROM `rsi` WHERE `tf`='4h'                         UNION 
    SELECT * FROM `rsi` WHERE `situation`='perek' AND `tf`='1d' UNION 
    SELECT * FROM `rsi`                                         UNION 
    
    SELECT * FROM `levels` WHERE `situation`='support' AND `tf`='4h' UNION 
    SELECT * FROM `levels` WHERE `tf`='1h' 
    
    ORDER BY `time` DESC LIMIT 0,20

    Сразу видно, что первые 4 подзапроса можно смело удалить.
    А потом надо смотреть на структуру таблицы rsi, ибо именно из неё будут взяты имена полей объединённого набора записей. Судя по ошибке, там просто нет поля time.
    Ответ написан
    1 комментарий
  • Как сделать SQL выборку по максимальной дате?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Если текущая версия СУБД поддерживает оконные функции - то ROW_NUMBER() в CTE и отбор по rn=1 во внешнем запросе.
    WITH cte AS (
        SELECT *, ROW_NUMBER() OVER (PARTITION BY list_name ORDER BY date DESC) rn
        FROM table
        )
    SELECT *
    FROM cte
    WHERE rn = 1

    Если не поддерживает - агрегирующий подзапрос, который для каждой категории получает максимальную дату, и отбор записей по этим значениям из другой копии таблицы.
    SELECT t1.*
    FROM table t1
    NATURAL JOIN (
        SELECT list_name, MAX(date) date
        FROM table
        GROUP BY 1
        )

    Оба запроса предполагают уникальность (list_name, date).
    Ответ написан
    Комментировать
  • Можно ли в postgres выполнить условную сортировку?

    @Akina
    Сетевой и системный админ, SQL-программист.
    select * 
    from products 
    order by type ASC,
             case WHEN type = 'books' then id      ELSE 0 END desc,
             case WHEN type = "food"  then name    ELSE 0 END asc,
             case WHEN type = "food"  then price   ELSE 0 END desc,
             case WHEN type = "relax" THEN popular ELSE 0 END asc,
             case WHEN type = "relax" THEN id      ELSE 0 END desc
    Ответ написан
    Комментировать
  • Как выбрать нужные записи из бд?

    @Akina
    Сетевой и системный админ, SQL-программист.
    SELECT *
    FROM table
    ORDER BY user_id = @user_id DESC, id DESC LIMIT 1

    Если заданный @user_id есть - вернётся соотв. запись. Если таких записей несколько - вернётся запись из них с максимальным id. Иначе вернётся просто запись с макс. id.

    Если же под "Если есть user_id вернуть запись с user_id" разумеется "ну хоть какой-то, лишь бы не NULL", то
    SELECT *
    FROM table
    ORDER BY user_id IS NULL, id DESC LIMIT 1
    Ответ написан
    Комментировать
  • Как реализовать алгоритм экспайринга элементов в базе данных?

    @Akina
    Сетевой и системный админ, SQL-программист.
    По-моему, ты накрутил сверх меры. Всё решается куда проще.

    Структура таблицы, максимально упрощённая:
    CREATE TABLE tasks (
        id PRIMARY KEY,
        definition,
        performer_id REFERENCES performer (id)
        expired_at DATETIME
    );

    Взятие (параметры - id обработчика и id задачи):
    UPDATE tasks
    SET performer_id = @performer_idб
        expired_at  = NOW() + INTERVAL 'performing time'
    WHERE ( expired_at IS NULL or expired_at < NOW() )
      AND ( id = @task_id )

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

    performing time может либо поставляться снаружи как параметр, либо быть свойством задачи (с соотв. полем в структуре таблицы).
    Ответ написан
    8 комментариев
  • Как сравнить такие столбцы?

    @Akina
    Сетевой и системный админ, SQL-программист.
    table1.id = SUBSTRING_INDEX(table2.id, '=', -1)
    Ответ написан
    Комментировать
  • Как разбить Date и Time в PostgreSQL запросе?

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

    SELECT '2022-04-01 09:23:45'::DATE, '2022-04-01 09:23:45'::TIME
    Ответ написан
    Комментировать
  • Какую длину может содержать условие выборки по ID?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Есть ли ограничение?

    Есть. Ограничение на размер пакета.

    Кроме того, если список ID предварительно скинуть в temporary table primary key (id) engine=memory, то запрос при большом (~ более 10к значений) списке даже с учётом времени на создание и наполнение временной таблицы выполняется быстрее.
    Ответ написан
    Комментировать
  • Плоттер HP DJ T520 после настройки печати по сети (ввод IP-адреса), зависает и моргает экран. По USB работает. Что делать?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Сталкивались. Причём именно с T520.

    Оказалось, проблема в прошивке (точнее, в самой флешке с прошивкой). Образ текущей прошивки сняли без проблем (кстати, рабочая прошивка и её копия - на флешке две копии прошивки, - частично не совпадают), найти типа рабочую прошивку в Инете - тоже без проблем... Но найти комбинацию прошивки и новой флешки, которая бы заработала нормально, нам не удалось (впрочем, врать не буду - не сильно упирались, перепробовали с десяток имевшихся под рукой флешек и угомонились), а стоимость ремонта у фирмачей оказалась неоправданно дорогая (да ещё и "везите к нам, будем смотреть"). Сейчас уже где-то с год работает подключенным к аппаратному сетевому принт-серверу (трёхпортовый старенький D-Link) по USB - по цене решения не сравнить.
    Ответ написан
    1 комментарий
  • Как вывести элемент, если нет связи many to many?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Шаблон при решении такого рода задач следующий:
    SELECT *
    FROM products 
    CROSS JOIN categories
    LEFT JOIN products_category USING (product_id, category_id)

    CROSS JOIN генерирует все возможные комбинации, а потом LEFT JOIN либо присоединяет к комбинации реально существующие данные, либо нет - тогда в соотв. полях одни NULL. Ну а что именно выводить - это уже решается по конкретной задаче.
    Ответ написан
  • Как синхронизировать столбцы в SQL?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Если связь между значениями - статическая, жёсткая и никогда не изменяемая, то используйте вычисляемое поле (generated column). Если значение поля, от которого зависит другое поле - числовое от единицы и далее, можно обойтись одним полем типа ENUM.

    Если же связь более сложная и/или может меняться со временем, то гораздо разумнее не заполнять второе поле в зависимости от первого, а использовать его значение как ссылку (foreign key) в словарную таблицу.

    Крайний случай - использование BEFORE INSERT/UPDATE триггеров.
    Ответ написан
    Комментировать