Задать вопрос
  • Как правильно реализовать систему групп у пользователя?

    @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.

    В общем, собак - убрать. Всех.
    Ответ написан
  • Триггер UPDATE с условием?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Пример
    CREATE FUNCTION fn_test() 
    RETURNS TRIGGER
    AS $fn_test$
    BEGIN
        IF OLD.val1 <> NEW.val1 THEN   -- задать условие
            NEW.id := NEW.id * 10;     -- выполнить действие
        END IF;
        RETURN NEW;
    END;
    $fn_test$ LANGUAGE plpgsql;

    CREATE TRIGGER tr_test
    BEFORE UPDATE ON test
    FOR EACH ROW
    EXECUTE FUNCTION fn_test();

    DEMO

    Или так:
    CREATE FUNCTION fn_test() 
    RETURNS TRIGGER
    AS $fn_test$
    BEGIN
        NEW.id := NEW.id * 10;     -- выполнить действие
        RETURN NEW;
    END;
    $fn_test$ LANGUAGE plpgsql;

    CREATE TRIGGER tr_test
    BEFORE UPDATE ON test
    FOR EACH ROW
    WHEN (OLD.val1 <> NEW.val1)   -- задать условие
    EXECUTE FUNCTION fn_test();

    DEMO
    Ответ написан
    2 комментария
  • Как посчитать количество сотрудников в штате за каждый месяц в каждом году?

    @Akina
    Сетевой и системный админ, SQL-программист.
    WITH RECURSIVE
    cte AS ( SELECT CAST(DATE_FORMAT(@range_from, '%Y-%m-01') AS DATE) month_start,
                    LAST_DAY(@range_from) month_end
             UNION ALL
             SELECT month_start + INTERVAL 1 MONTH,
                    LAST_DAY(month_start + INTERVAL 1 MONTH)
             FROM cte
             WHERE month_start < DATE_FORMAT(@range_till, '%Y-%m-01')
    )
    SELECT cte.month_start, COUNT(employee.id) employees_amount
    FROM cte
    LEFT JOIN employee ON employee.date_employment <= cte.month_end
                      AND (    employee.date_dismissal >= cte.month_start
                            OR employee.date_dismissal IS NULL )
    GROUP BY 1;

    https://dbfiddle.uk/?rdbms=mariadb_10.4&fiddle=8be...
    Ответ написан
    4 комментария
  • Чем отечественным заменить Mikrotik?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Официальный сайт реестра российской радиоэлектронной продукции (РРПО) — https://gisp.gov.ru/documents/10546664/

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

    @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-программист.
    Покупаешь ещё один роутер (конечно, уж не совсем дерьмо). Каскадишь. Батя прячется за ним (у него двойной NAT, "две защиты за те же деньги", ибо второй роутер ты покупаешь на свои) и не даёт тебе пароля, а ты сидишь только за первым, и если твой комп поимеют, то до батиного не доберутся.
    Ответ написан
    6 комментариев
  • Разграничить по подсетям и VLAN?

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

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

    @Akina
    Сетевой и системный админ, SQL-программист.
    Пример реализации "влоб" (синтаксис MySQL).

    Структура:
    CREATE TABLE test ( word0 VARCHAR(255),
                        word1 VARCHAR(255),
                        word2 VARCHAR(255),
                        word3 VARCHAR(255)
    );


    Запрос:
    WITH 
    cte1 AS (
        SELECT *, ROW_NUMBER() OVER () identity
        FROM test
    ),
    cte2 AS (
        SELECT word0 word, identity FROM cte1 UNION ALL
        SELECT word1 word, identity FROM cte1 UNION ALL
        SELECT word2 word, identity FROM cte1 UNION ALL
        SELECT word3 word, identity FROM cte1 
    )
    SELECT LEAST(t1.word, t2.word), GREATEST(t1.word, t2.word), COUNT(DISTINCT identity)
    FROM cte2 t1
    JOIN cte2 t2 USING( identity )
    WHERE t1.word > t2.word
    GROUP BY 1, 2;

    DEMO fiddle

    Но надо чётко понимать что на заявленных объёмах запрос умрёт навсегда, вместе с сервером.

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

    @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).
    Ответ написан
    Комментировать
  • Как создать тригер для дефолтного значения?

    @Akina
    Сетевой и системный админ, SQL-программист.
    CREATE TABLE trs (
        wallet_id INT, 
        amount DECIMAL(12, 2), 
        hash BYTEA GENERATED ALWAYS AS (sha256((wallet_id + amount) :: TEXT :: BYTEA)) STORED
    )

    из конкатенированный строки wallet_id + hash

    Вообще-то оба поля чисельные - какая в пень конкатенация-то? Но если их надо преобразовать в строку и конкатенировать, то
    CREATE TABLE trs (
        wallet_id INT, 
        amount DECIMAL(12, 2), 
        hash BYTEA GENERATED ALWAYS AS (sha256((wallet_id :: TEXT || amount :: TEXT) :: BYTEA)) STORED
    )
    Ответ написан
    1 комментарий
  • Rак записать id в Postgres?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Использовать надо INSERT .. SELECT
    WITH cte_id  AS (
        INSERT INTO words (name_word, discription_word) 
        VALUES ('cool', 'круто') 
        RETURNING Id
    )
    INSERT INTO users_words (users_id, words_id, status_learn_word)
    SELECT 649651821, id , 0
    FROM cte_id;
    Ответ написан
    Комментировать
  • 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 комментариев