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

    @alexalexes
    select a.*
    from (
    select s.*,
              row_number() over (partition by `customer_id` order by unit_importance, updated_at desc) rn
      from stream s
    ) a
    where a.rn = 1

    Единственное, у вас MySQL должен быть 8+ версии. А если 5-ой версии, то ищите аналог оконной функции.
    Ответ написан
    4 комментария
  • Как создать триггер для изменения поля одной таблицы по условию из другой?

    @alexalexes
    Создаете функцию для триггера:
    CREATE OR REPLACE FUNCTION set_employee_status()
      RETURNS TRIGGER
      LANGUAGE PLPGSQL
      AS
    $$
    DECLARE curr_row RECORD;
    BEGIN
      IF tg_op = 'INSERT' OR tg_op = 'UPDATE' THEN -- проверяем допустимые операции
            IF NEW is null THEN -- выбираем NEW/OLD строку
               curr_row := OLD;
            ELSE
               curr_row := NEW; 
            END IF;
    	IF curr_row.date_start <= CURRENT_DATE and curr_row.date_end >= CURRENT_DATE THEN
    	   update employee -- тут изменяется таблица работников!
               set empoyee_status = 1
              where emp_id = curr_row.employee_id;
              ELSE
              update employee -- тут изменяется таблица работников!
               set empoyee_status = 0
              where emp_id = curr_row.employee_id;
    	END IF;
      END IF;
      RETURN NEW;
    END;
    $$

    Потом нужно присоединить функцию к триггеру:
    CREATE TRIGGER tr_set_employee_status
      BEFORE UPDATE
      ON vocation -- тут на таблицу отпусков вешается триггер!
      FOR EACH ROW
      EXECUTE PROCEDURE set_employee_status();

    PS: Если функция будет вешаться на разные события (в особенности, на delete), то нужно выбирать NEW/OLD источник записи для определения статуса.
    Ответ написан
  • В чем различие между phpMyAdmin, MySQL workbench и Microsoft SQL Server?

    @alexalexes
    Начните с того, чтобы различать компоненты, которые ставят на серверную часть, где будет работать СУБД.
    И клиентскую часть компонентов - это те утилиты и драйверы, с помощью которых вы будете подключаться к СУБД.
    Microsoft SQL Server - насколько я помню, содержит сам СУБД сервер от Microsoft, который устанавливается на сервер, и утилиты, которые вы ставите на клиентскую часть, чтобы подключаться к серверу.
    MySQL workbench - это клиент MySQL (к MS СУБД никакого отношения не имеет) с графической оболочкой, который ставиться на любую настольную ОС.
    phpMyAdmin - это тоже клиент для MySQL (еще для другого форка СУБД - MariaDB), но работающий на PHP веб-сервере. Вы ставите сначала Apache - http-сервер, потом вам нужно поставить PHP-сервер, а потом включить расширение mysqli или PDO, чтобы скрипты phpMyAdmin могли использовать функции PHP для работы с СУБД. Ну, естественно, вам нужно установить MySQL/MariaDB сервер - а куда вы собственно будете подключаться.
    PS: На клиентской ОС не обязательно ставить графические утилиты, чтобы работать с СУБД. Достаточно установить ODBC-клиентский драйвер для работы с определенной СУБД, и открываете консоль - можете подключаться и писать запросы в режиме командной строки - дешево и сердито.
    Ответ написан
    Комментировать
  • SQL сумма продажи за день?

    @alexalexes
    В зависимости от диалекта SQL нужно округлить дату до дней или выделить только дату без времени, чтобы правильно сгруппировать сумму.
    Например, с помощью trunc так это делается в Oracle:
    select trunc(payment_date) as p_date, sum(amount) as daily_income 
    
     from payment
    
     where extract(month from payment_date) = 7
         and extract(year from payment_date) = 2005 -- про extract - тоже нужно смотреть, как это принято в конкретном диалекте SQL
    
    group by  trunc(payment_date)
    order by p_date desc
    Ответ написан
    Комментировать
  • Фильтрация характеристик товаров с подсчетом?

    @alexalexes
    Из where убрать дополнительное условие фильтрации, и добавить его же в case в count.
    Тогда count будет отбивать именно статистику по условиям фильтрации (считается все, что выходит из case не null), но занулять там, где условия не выполняются.
    ...
    count(
    case
    when p.id = ANY (
    	SELECT prod_id
    	FROM "Product_properties" pp
    	WHERE pp.attr_alias = 'ram' AND pp.option_alias IN ('2gb','3gb','4gb','8gb')
    )
    AND
    p.id = ANY (
        SELECT prod_id
        FROM "Product_properties" pp
        WHERE pp.attr_alias = 'storage' AND pp.option_alias IN ('16gb','128gb')
    )    
    then 1
    end
    )
    ...

    PS: Подзапросы Any можно вынести в секцию With, если они дают однотипную выборку и используются во многих местах.
    Ответ написан
    5 комментариев
  • Когда каскадное обновление это плохо?

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

    @alexalexes
    select B.*
    (select A.*,
                max(A.Квартал) over (partition by A.Год) as Макс_Квартал
      from A) B
    where B.Квартал = B.Макс_Квартал
    Ответ написан
    Комментировать
  • Где ошибка в SQL запросе к полю содержащему XML?

    @alexalexes
    SET QUOTED_IDENTIFIER ON;
    -- create
    CREATE TABLE entity (
      xml ntext
    );
    
    -- insert
    INSERT INTO entity(xml) VALUES ('<r><authCard>abc123slip4</authCard><authCard>abc1234</authCard></r>');
    
    -- fetch 
    SELECT * FROM entity
    where cast(xml as xml).value('(/r/authCard)[1]', 'nvarchar(max)') LIKE N'%slip%';
    Ответ написан
    3 комментария
  • Как правильно сгруппировать данные двух таблиц чтоб записи соединялись по количественному номеру записи?

    @alexalexes
    Чтобы любую таблицу обложить историей изменения, нужно создать следующую обвязку:
    1. Создать таблицу <название исходной таблицы>__history
    Поля таблицы:
    Первичный ключ - history_id,
    Копируем названия полей исходной таблицы как есть (всем полям даете возможность быть null).
    Делаем внешние ключи таблицы истории к исходной таблице (обычно id- исходной таблицы нужно привязать) и к другим таблицам, такие же как в исходной таблице, но опускаем ограничение уникальности ключей. Не используем каскадное обновление значение ключей.
    Добавляете поле - вид операции над строкой исходной таблицы (вставка, обновление, удаление).
    И самое главное, в таблице истории должно быть поле next_history_id - делаете по нему связанный список истории изменения одного поля. Как это поле работает? - см. пункт 2.
    2. Создаете триггер/ы на события вставки, изменения, удаления для исходной таблицы в ней пишите тело со следующими действиями:
    Читаете id тронутой событием записи из исходной таблицы.
    Определяете history_id по данной id, где next_history_id is null - запоминаете в локальной переменной как before_history_id.
    Если действие не удаление, то создаете запись в таблице истории из new-полей, которые пришли в insert/update для исходной таблицы, добавляете значение поля вида действия, next_history_id делаете null, получаете history_id этой вставленной записи - записываете в переменную new_history_id.
    Если действие - удаление, то new поля вычитывать не нужно, нужно записать значение поля вида действия, next_history_id делаете null, получаете history_id этой вставленной записи - записываете в переменную new_history_id.
    Делаете обновление поля next_history_id = new_history_id у записи истории со значением ключа before_history_id.
    Тело триггера готово.
    На любое действие в исходной таблице будет создаваться запись в истории, с указанием действия, а также будет формироваться цепочка изменений конкретной записи через атрибут next_history_id.
    Чтобы вычитать последнее изменение по строчке исходной таблицы, нужно обратиться в таблицу истории по id от исходной таблицы и next_history_id is null.
    Ответ написан
    Комментировать
  • Как составить SQL запрос с разбиением дат на несколько?

    @alexalexes
    -- Тестовая выборка
    with t as (select to_date('2024-09-17 11:52:17', 'yyyy-mm-dd hh24:mi:ss') begin_date, to_date('2024-12-17 11:52:17', 'yyyy-mm-dd hh24:mi:ss') end_date, 3 Cnt from dual union
    select to_date('2024-06-10 14:52:19', 'yyyy-mm-dd hh24:mi:ss') begin_date, to_date('2024-07-10 14:52:19', 'yyyy-mm-dd hh24:mi:ss') end_date, 1 Cnt from dual)
    -- Иерархический запрос
    select distinct T.*,
           add_Months(T.Begin_Date, Level - 1) as Current_Date, -- отсчет месяцев
           Level as Current_Val  -- текущее значение отсчета
      from T
      CONNECT BY add_Months(T.Begin_Date, Level) <= T.End_Date
    order siblings by T.Begin_Date desc
    Ответ написан
    Комментировать
  • Какую команду следует использовать для поиска строк, содержащих значение больше определенного числа?

    @alexalexes
    1) Создать таблицу cst_stat.
    id
    cst_id -- внешний ключ к cst
    p_key -- значение ключа в JSON
    p_value -- значение по ключу в JSON
    2) Создать скрипт, который вычитает данные из таблицы, сдекодит JSON и запишет в cst_stat распарсенный JSON.
    3) Создать уже привычный запрос с использованием таблиц cst и cst_stat.
    select *
    from cst
    
    where exists( select *
                               from cst_stat
                                   where cst.id = cst_stat.cst_id
                                   and cst_stat.p_key = 5 and cst_stat.p_value = 1.5
    ) -- вариант поиска в JSON значения 5: 1.5

    4) Переписать систему сбора статистики, чтобы записывался данные в нормализованном виде, без JSON.
    Ответ написан
    Комментировать
  • Из-за чего возникает ошибка mysql при создании таблицы?

    @alexalexes
    ... `key` INT ...
    В обратные кавычки берите названия колонок, потому что без них key будет восприниматься интерпретатором как ключевое слово.
    Ответ написан
    Комментировать
  • Как включить множественное редактирование в DBeaver?

    @alexalexes
    Alt+Shift позволяет выделять несколько фрагментов для редактирования.
    Но все же будет быстрее использование традиционной функции Найти и заменить Ctrl+F.
    Ответ написан
    Комментировать
  • Как в DataGrip sql запрос преобразовать в код для vba Excel?

    @alexalexes
    В редакторе текста DataGrip есть функция замены текста с использованием регулярных выражений?
    Если есть, включаете опцию регекспов и делаете две замены:
    1) Искать ^ (начало строки). Заменить на sql = sql & "
    2) Искать $ (конец строки). Заменить на "
    3) Убрать лишний sql & в первой строке.
    Ответ написан
    Комментировать
  • Как уменьшить кол-во case'ов, и просто подтянуть по другой таблице?

    @alexalexes
    Делаете две таблицы:
    1. Фирма-отправитель Company_Sender
    id - идентификатор компании
    name - наименование компании

    2. Шаблоны поиска отправителя Sender_Template
    id - идентификатор шаблона
    template - текст шаблона
    company_id - идентификатор фирмы-отправителя

    Искать потом можно таким запросом, либо делать Update на какое-нибудь поле в t для пометки результата:
    select t.*, 
    (select Cs.Name
       from Sender_Template St
       join Company_Sender Cs on Cs.Id = St.Company_Id 
      where  t.baza like St.template
      limit 1
    ) as Sender_Name -- если null, значит ни один шаблон не подошел
    from t

    PS: Это самый примитивный вариант автоматизации like. Нельзя задавать шаблоны за пределами возможностей синтаксиса like. Нужно как-то отличать дубликаты, если будет определение на больше чем один шаблон.
    Ответ написан
    Комментировать
  • Как изменить запрос SQL?

    @alexalexes
    Склейте строку под ваш формат вывода:
    SELECT concat(TABLE_SCHEMA, '.', TABLE_NAME, '.', COLUMN_NAME) as COLUMN_NAME
      FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_NAME = 'info' 
        AND TABLE_SCHEMA = 'db'

    PS: А зачем вам вычитывать структуру базы, если не секрет? В прикладных задачах вообще не должно быть обращений в служебные таблицы MySQL.
    Ответ написан
  • Возможно ли в oracle sql объединить JSON массивы, являющиеся записями запроса?

    @alexalexes
    Смотрите в сторону функции ListAgg - она объединит все значения через разделитель.
    Потом останется только обрамить результат в скобки:
    select '[' || ListAgg(item, ',') over (order by rownum) || ']'  as item_arr
      from table

    PS: ListAgg работает с данными, которые можно привести к varchar/varchar2. То есть, у вас есть физическое ограничение в 4000 символов в результирующей строке. Или у вас данные изначально в BLOB/CLOB.
    В этих случаях вам нужно использовать хранимую функцию, поскольку в чистом SQL вы не сможете работать с безразмерными атрибутами.
    PPS: А вообще, нужно избавиться от JSON и нормализовать таблицу.
    PPPS: Если вы делаете API, то формировать JSON для ответа API - это не функция СУБД, этим должна заниматься прослойка перед СУБД.
    Ответ написан
    Комментировать
  • Получение статьи и комментариев к ней: одним запросом или двумя?

    @alexalexes
    Вопрос лежит в плоскости оптимизации.
    Если вам приемлемо по количеству обращений и времени делать несколько отдельных запросов, чтобы сформировать объект поста на бэкенде перед СУБД, то делайте. Если нужно уменьшить количество запросов, но пожертвовать объемом пересылаемых данных между бэком и СУБД, то какие-то атрибуты поста, которые идут списком/массивом можно получать одним запросом.
    Обычно, дилемма состоит в том, как получать необъемные скалярные свойства поста - id, дата публикации, автор и т.д. и не сильно глубоких списков, скажем, изображения галереи поста, которые редко превышает пару десятков штук. Вот это можно спокойно джойнить, и не бояться дублирования свойств поста в выборке.
    Если вы работаете с длинным текстом поста, и безразмерными списками, то тут нужны отдельные запросы. Скорее всего в комментариях у вас будет порционная подгрузка по страницам, или по кустам дерева комментариев, если оно многоуровневое.
    Ответ написан
    Комментировать
  • Как достать промежуток между транзакциями?

    @alexalexes
    Нужно, чтобы СУБД поддерживала оконные функции (если у вас MySQL 5 версии, то мужайтесь).
    select user_id,
              order_id,
              time,
              lag(time) over (partition by user_id order by order_id) as before_time, -- предыдущее значение time в пределах user_id по сортировке order_id
             time - lag(time) over (partition by user_id order by order_id) as period, -- математика вычитания времени зависит от СУБД.
             max(time) over (partition by user_id) - min(time) over (partition by user_id)  as user_period -- период между самой ранней записью по пользователю и самой поздней записью по пользователю
    from t
    Ответ написан
  • Как взять каждое значение массива mysqli_fetch_array и занести каждое значение в строку таблицы mySQL?

    @alexalexes
    У вас:
    while($row=mysqli_fetch_array($res))
    {  
        // #########################
        // ####  начало тела цикла  #####
        // ##########################
        $iduser=$id;
        $idkat=$row['idkat'];
         // #########################
        // ####  конец тела цикла  #####
        // ########################## 
    }  
        $res=mysqli_prepare($bd, "INSERT INTO zakaz (iduser,idkat) 
     VALUES(?,?)");
     mysqli_stmt_bind_param($res, 'ii', $iduser,$idkat); // подставляем переменные, которые присвоились на ПОСЛЕДНЕМ прогоне цикла
     $result2=mysqli_stmt_execute($res);

    Как вы ожидаете:
    while($row=mysqli_fetch_array($res))
    {  
        // #########################
        // ####  начало тела цикла  #####
        // ##########################
        $iduser=$id;
        $idkat=$row['idkat'];
        $res2=mysqli_prepare($bd, "INSERT INTO zakaz (iduser,idkat) 
     VALUES(?,?)");
     mysqli_stmt_bind_param($res2, 'ii', $iduser,$idkat); // подставляем переменные, которые присвоились на ТЕКУЩЕМ прогоне цикла
     $result2=mysqli_stmt_execute($res2);
         // #########################
        // ####  конец тела цикла  #####
        // ########################## 
    }

    PS: Есть нюанс. Обработку второго запроса нужно вести по отдельному дескриптору $res2, чтобы не поломать дескриптор $res, по которому работает while.
    Ответ написан
    Комментировать