Задать вопрос
  • Выдача двух IP-адресов одному ПК от одного DHCP-сервера на MikroTik - возможно ли?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Адрес, выдаваемый по DHCP, выдаётся для определённого аппаратного (МАС) адреса.

    Сетевой адаптер (что реальный, что виртуальный) имеет только один МАС - соответственно ему будет выделен только один IP.
    Ответ написан
    1 комментарий
  • Как получить только первые строки из групп строк отсортированной таблицы?

    @Akina
    Сетевой и системный админ, SQL-программист.
    SELECT prices.* 
    FROM prices
    JOIN ( SELECT size, MAX(`date`) AS `date`
           FROM prices 
           WHERE price
    --       AND `date` <= @some_date
           GROUP BY size ) AS last_nonzero_date USING (size, `date`);

    Запрос предполагает, что (size, `date`) - уникально.

    Если для size все цены нулевые (или NULL) - запись для такого размера не будет выведена.

    Если нужно состояние на определённую дату - раскомментировать WHERE.
    Ответ написан
    Комментировать
  • Возможно ли составить такой SQL запрос?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Ничто не мешает использовать оконный вариант агрегатных функций. Кроме слишком старой версии СУБД, не поддерживающей оконные функции, конечно.
    SELECT MIN(`min_price`) OVER () as `min_price`, 
           MAX(`max_price`) OVER () as `max_price`, 
           `item_id` as `id`
    FROM `product_table` 
    WHERE `id` IN (SELECT  тут запрос)

    Получишь все нужные id, и в каждой строке - нужные MIN и MAX.

    ======================


    Akina, да, версия 5.7.21 и она, я так понимаю, не поддерживает оконные функции.


    SELECT t2.min_price, 
           t2.max_price, 
           t1.item_id as id
    FROM product_table t1
    CROSS JOIN ( SELECT MIN(min_price) AS min_price, 
                 MAX(max_price) AS max_price
                 FROM product_table ) t2
    WHERE t1.id IN (SELECT  тут запрос)
    Ответ написан
  • Возможно ли создать отчёт Excel с помощью SQL?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Excel вполне и сам может получить данные с сервера, причём не только из таблиц, но и результат выполнения запросов любой сложности. Так что SQL тут в общем и не нужен - задача вполне решается средствами VBA. Открыл в Excel файл отчёта, жмакнул кнопку обновления данных, подождал - и наслаждайся готовым результатом.
    Ответ написан
    4 комментария
  • Как автоматизировать запуск sql скриптов?

    @Akina
    Сетевой и системный админ, SQL-программист.
    MySQL имеет собственный встроенный планировщик (MySQL 8.0 Reference Manual / Stored Objects / ...), который может делать практически что угодно. Создаёшь Event Procedure, задаёшь периодичность выполнения - остальное сервер сделает сам. Вообще без помощи/управления со стороны.

    Народ обычно любит предлагать внешние планировщики (как правило CRON) - настоятельно не рекомендую, если требующий выполнения код есть чистый SQL. Другое дело когда надо выполнять скрипты на иных языках или внешние приложения - тут да, без крона скорее всего не обойтись. Хотя и тут есть способ - подключить внешний модуль с требуемым функционалом.

    Есть папка, которая хранит в себе sql файлы для создания бд, таблиц в этой бд, импорт данных в эти таблицы.
    Как автоматизировать запуск этих sql скриптов?

    Создание БД, таблица, начальное наполнение - это как бы одноразовое действие. Нафига их шедулить?
    Ответ написан
    3 комментария
  • Как удалить одинаковые записи?

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

    DELETE t1.*
    FROM tablename t1
    JOIN tablename t2 USING (date, user_id)
    WHERE t1.id > t2.id


    а лучше не создавать их

    CREATE UNIQUE INDEX indexname ON tablename (date, user_id)

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

    @Akina
    Сетевой и системный админ, SQL-программист.
    SELECT CASE WHEN sender_id = 1
                THEN receiver_id
                ELSE sender_id 
                END AS buddy
    FROM message
    WHERE 1 IN (sender_id, receiver_id)
    GROUP BY buddy
    ORDER BY MAX(sent_at)


    Ну и соответственно
    SELECT user.username
    FROM user
    JOIN ( SELECT CASE WHEN sender_id = 1
                       THEN receiver_id
                       ELSE sender_id 
                       END AS id,
                  MAX(sent_at) sent_at
           FROM message
           WHERE 1 IN (sender_id, receiver_id)
           GROUP BY 1 ) ids USING (id)
    ORDER BY ids.sent_at
    Ответ написан
    3 комментария
  • Как задать связи разного вида с помощью Foreign key?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Любой внешний ключ (FOREIGN KEY в структуре таблицы) задаёт связь типа 1:N (если локальное выражение внешнего ключа не может быть NULL) либо (0-1):N.

    Задание связи 1:1 (и соответственно (0-1):1) требует дополнительного ограничения уникальности на локальной стороне.

    Задание связи M:N требует дополнительной связующей таблицы.

    В данном случае "задание связи" == "создание правила контроля целостности и непротиворечивости данных, контролируемое на стороне сервера соответствующей подсистемой".
    Ответ написан
    Комментировать
  • Postgre Sql DISTINCT массив с ORDER BY?

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

    Посему используйте поле выходного набора для сортировки.
    SELECT DISTINCT (regexp_split_to_array(commend, E'\\s+'))[:3] AS first_3_words
    FROM orders 
    ORDER BY first_3_words[2];
    Ответ написан
  • Как написать SQL запрос для среза непустых значений?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Общее решение:
    SELECT DISTINCT
           key,
           FIRST_VALUE(value1) OVER (PARTITION BY key 
                                     ORDER BY CASE WHEN value1 IS NULL 
                                                   THEN 1 
                                                   ELSE 0 END, id DESC) AS value1,
           FIRST_VALUE(value2) OVER (PARTITION BY key 
                                     ORDER BY CASE WHEN value2 IS NULL 
                                                   THEN 1 
                                                   ELSE 0 END, id DESC) AS value2,
           FIRST_VALUE(value3) OVER (PARTITION BY key 
                                     ORDER BY CASE WHEN value3 IS NULL 
                                                   THEN 1 
                                                   ELSE 0 END, id DESC) AS value3
    FROM tablename
    -- WHERE key IN ( {список значений} )


    Однако я полностью согласен с тем, что сказал Роман Юрьевич Ипатьев,
    переписать таблицу в нормальную форму
    Ответ написан
    Комментировать
  • Когда нужно писать имя таблицы в запросе?

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

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

    Под понятием "таблица" следует понимать строго один экземпляр исходного набора данных. Иными словами, запрос, в котором используется две копии одной таблицы, либо используется дополнительная синтетическая таблица констант, запросом с источником данных из одной таблицы не является.

    ---

    В некоторых диалектах указание алиаса может быть обязательно и по причине интерференции имён из разных пространств.

    Например, в хранимых объектах MySQL при совпадении имени поля таблицы с именем локальной переменной обращение без указания алиаса - это всегда обращение к переменной. Поэтому для MySQL правило ещё строже - алиас указывай всегда.

    И даже такая строгость порой недостаточна. Пример. Обратите внимание на сортировку - в ней id интерпретируется как имя переменной, а не имя поля выходного набора, и потому результат "странный". Кстати, это тот случай, когда вообще ничто не поможет, кроме использования выражения выходного поля вместо его имени.
    Ответ написан
    Комментировать
  • Как оптимизировать sql запрос (MySQL)?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Не используйте картезианское произведение - нечитаемо. Используйте нормальный JOIN-синтаксис:
    SELECT `p`.`sum`, `p`.`type`, `p`.`visit` 
    FROM `visits` AS `v`
    JOIN `payments` AS `p` ON `v`.`id` = `p`.`visit` 
    WHERE DATE(p.date) = '2021-10-04' AND `v`.`office` = '1'


    Соответственно для оптимизации запроса требуется:

    1. избавиться от функции в условии отбора и конвертировать его в вид
    SELECT `p`.`sum`, `p`.`type`, `p`.`visit` 
    FROM `visits` AS `v`
    JOIN `payments` AS `p` ON `v`.`id` = `p`.`visit` 
    WHERE p.date >= '2021-10-04' 
      AND p.date < '2021-10-05' 
      AND `v`.`office` = '1'

    2. Создать индексы:

    2a. visits (office, id).
    2b. payments (`date`, visit) и payments (visit, `date`), посмотреть какой из них используется, удалить неиспользуемый.

    3. Если поле `v`.`office` имеет числовой тип, изменить условие отбора по этому полю на AND `v`.`office` = 1. В исходном виде, если поле числовое, то и поле, и значение приводятся к floating-point number, и только потом сравниваются.
    Ответ написан
  • Как удалить primary key с auto increment?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Если поле объявлено как AUTO_INCREMENT, то оно ОБЯЗАНО быть первичным ключом либо его префиксом. Если удалить PRIMARY KEY, но НЕ удалить AUTO_INCREMENT, результирующая структура не будет отвечать этому требованию - поэтому возникает ошибка.

    Следовательно, в одном ALTER TABLE следует выполнить обе операции - и удалить первичный ключ, и атрибут AUTO_INCREMENT (например, изменить на DEFAULT {значение}). Либо выполнить два ALTER TABLE, но в обратном порядке - сначала удалить атрибут AUTO_INCREMENT, и только потом первичный ключ.

    DEMO
    Ответ написан
    1 комментарий
  • Как объединить два SQL запроса в один?

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

    SELECT p.*, GROUP_CONCAT(c.name) countries
    FROM p
    JOIN с ON FIND_IN_SET(c.id, p.country)
    GROUP BY p.id

    Если в поле p.country к тому же имеются паразитные пробелы- перед связыванием их необходимо удалить.

    Настоятельный совет - нормализовать данные. CSV - это крайне неудачное решение.
    Ответ написан
    1 комментарий
  • Как работает 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. Впрочем, далеко не все специфичные конструкции так комментируются - скажем, если в теле хранимой процедуры имеется обращение к функции, отсутствующей в младшей версии, то это обращение не комментируется и при разворачивании на младшей версии приведёт к ошибке. Но тут уж, как говорится, на каждый чих не наздравствуешься...
    Ответ написан
    Комментировать
  • Как создать скрипт для получения данных из sql БД?

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

    Так что создаём Event Procedure, которая выгружает результат нужного запроса в файл в нужном формате, запускаем Event Scheduler... и всё.
    Ответ написан
    Комментировать
  • Какой алгоритм используется при возможности 2 неудачных попыток?

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

    Рассмотрим, что у нас есть только один предмет. Очевидно, что придётся его кидать с 1 метра, с 2, с 3... пока не разобьётся. Максимум будет 5000 бросков.

    Но у нас есть 2 предмета.

    Тогда мы можем бросить первый не с 1 метра, а сразу с какого-то N. Если он разобьётся, то придётся второй кидать с 1, 2, ... и по максимуму второй кинем N-1 раз. а всего будет N бросков.

    Но если он не разбился, то мы можем бросить первый уже с бОльшей высоты. Какой? Допустим, он разобьётся. Чтобы получить по максимуму те же N бросков, второй предмет мы уже может бросить N-2 раз, а, значит, первый предмет надо сбрасывать с высоты N+(N-1).

    Если первый снова не разбился, на следующем шаге его можно сбросить с высоты N+(N-1)+(N-2)... и так далее.

    Лишнего нам тоже не надо. А, значит, надо подобрать такое наименьшее N, при котором N-й бросок первого предмета будет с 5000 метров или выше.

    Итого - имеем N+(N-1)+(N-2)+...+1 >= 5000. Сумму арифметической прогрессии знаем, квадратные уравнения решать умеем. Получаем N=100.
    Ответ написан
    Комментировать
  • Как спроектировать базу данных слов?

    @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), ...
    Ответ написан
    Комментировать