Ответы пользователя по тегу MySQL
  • Можно ли в хранимых процедурах создать временную функцию?

    @Akina
    Сетевой и системный админ, SQL-программист.
    CREATE FUNCTION не входит в список конструкций, разрешённых к использованию в stored objects (procedures, functions, triggers, event procedures) и prepared statements.

    Ответ: НЕЛЬЗЯ.

    PS. В MySQL нет временных функций, все функции - статические. Встроенные, регистрируемые либо хранимые.
    Ответ написан
    1 комментарий
  • PHP не создаёт запись MySQL, ошибки не выводит, что делать?

    @Akina
    Сетевой и системный админ, SQL-программист.
    No index used in query/prepared statement ...

    что это означает?

    Это означает, что, по мнению PHP/mysqli, нет подходящего индекса для обработки запроса, сервер будет шерстить всю таблицу, что неэффективно. В общем, он просто старается сделать тебя счастливым (твоё мнение при этом никого не интересует).
    Возможные решения:
    1. Создать индекс users (username)
    2. Изменить настройки mysqli_report() (см. ответ SagePtr)

    без неё обойтись нельзя, т.к. одинаковые ники будут вызывать ошибки в некоторых уголках сайта
    что делать?

    Тогда альтернатив вообще нет.

    Создать уникальный индекс users (username).

    После этого код с проверкой на существование можно смело выбросить (дубликат в принципе не будет записываться сервером). Но обязательно добавить код для обработки ошибки дублирования при добавлении.
    Ответ написан
    Комментировать
  • Как правильно реализовать систему групп у пользователя?

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

    Перевернись, не с той стороны смотришь. Наоборот, юзеру должны отображаться посты только его групп.
    Решается элементарно.
    На текущей структуре это будет

    FROM post
    JOIN user ON user_id = {текущий пользователь} AND FIND_IN_SET(post.group_id, user.group_ids_csv)

    Однако функция в связи - это прощай индексы и здравствуй фуллскан.

    ID username group
    1 admin 1,2,3


    Дурацкая схема хранения.
    Если есть связь M:N, то должна быть связующая таблица (user_id, group_id).
    Ответ написан
  • Как сделать жесткое исключение NOT IN в mysql?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Разумнее использовать WHERE NOT EXIST, который скорее всего будет более эффективен:
    SELECT [DISTINCT] number
    FROM table t1
    WHERE service NOT IN (1,2,3)
      AND NOT EXISTS (
        SELECT NULL
        FROM table t2
        WHERE t1.number = t2.number
          AND t2.service IN (1,2,3)
    )

    Индекс по (number, service) - весьма желателен.

    Если service - целочисленное поле со значениями от единицы и более, то для даных конкретных условий можно построить и более эффективный запрос:
    SELECT number
    FROM test
    GROUP BY number
    HAVING MIN(service) > 3
    Ответ написан
    Комментировать
  • Ошибка #1064. Как объявлять переменные в mysql 8.0?

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

    Есть переменные локальные. Они определяются в рамках блока кода в хранимой конструкции (функция, процедура, триггер и пр.), имеют определённый тип, и существуют только в том блоке, в котором определены. Имя начинается НЕ с символа @.

    Есть переменные, определённые пользователем. Имя начинается с символа @. Не требуют определения, существуют в течение всей сессии.

    В показанном коде - мешанина. Попытка определить пользовательскую переменную, что приводит к ошибке синтаксиса. Показанный код был бы корректен в MS SQL (SQL Server), но не в MySQL.

    В общем, собак - убрать. Всех.
    Ответ написан
  • Как вернуть опредленное значение, если запрос выдает название колонки?

    @Akina
    Сетевой и системный админ, SQL-программист.
    SELECT COALESCE( 
        (
            SELECT busy FROM `all_reservs` WHERE dates ='27.06.22' AND number='22' LIMIT 1
        ), 
        'no'
    ) AS busy;

    Если запрос вернёт запись (с одним полем), скаляризация преобразует её в значение, и COALESCE вернёт это значение.
    Если запрос не вернёт запись, скаляризация вернёт NULL, и COALESCE вернёт 'no'.
    LIMIT страхует от возврата более чем одной записи. По-хорошему ещё надо добавить ORDER BY.
    Ответ написан
    1 комментарий
  • Как сделать ORDER BY совместно с GROUP BY в MySQL?

    @Akina
    Сетевой и системный админ, SQL-программист.
    SELECT t1.*
    FROM table AS t1
    NATURAL JOIN (
        SELECT user_id, MAX(timestamp) AS timestamp
        FROM table AS t2
        GROUP BY 1
    ) AS t3


    Если вдруг для юзера время может иметь дубликаты - будут выведены все соотв. записи.
    Ответ написан
    Комментировать
  • MSSQL and mysql в чем отличие?

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

    Не надо путать причину и следствие. Причина - это что ты ни хрена не понимаешь. А следствие - оно тебе кажется убожеством.
    offtop
    В скобках отмечу, что если ты не только ни хрена не понимаешь, но и жалуешься на это, и считаешь это достаточным обоснованием того, чтобы назвать убожеством - то ты и не хочешь понимать, и не пытаешься понять. В смысле не пытаешься по-настоящему, прочтение пары страниц из мануала под этот термин не проходит.


    отличаются ли запросы sql MSSQL от Mysql

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

    возможно ли сменить БД без нарушения функциональности софта.

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

    @Akina
    Сетевой и системный админ, SQL-программист.
    SELECT ..
    FROM ..
    GROUP BY (unixtime_column MOD 60*60*24) DIV 60*60
    Ответ написан
    8 комментариев
  • Как связать таблицу с собой?

    @Akina
    Сетевой и системный админ, SQL-программист.
    SELECT t1.id, COALESCE(t1.f2, t2.f2) f2, t1.f3       
    FROM test t1
    LEFT JOIN test t2 ON t2.id = t1.f1

    Если пустые ячейки - не NULL, а пустая строка, то COALESCE(NULLIF(t1.f2, ''), t2.f2).
    Ответ написан
    Комментировать
  • 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 комментария
  • Как найти строку по значению и изменить соседнее значение?

    @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...
    Ответ написан
    Комментировать
  • Нужно использовать триггеры или нет??

    @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 комментарий
  • Как отсортировать запрос с 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 комментарий
  • Как выбрать нужные записи из бд?

    @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-программист.
    table1.id = SUBSTRING_INDEX(table2.id, '=', -1)
    Ответ написан
    Комментировать
  • Какую длину может содержать условие выборки по ID?

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

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

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