Ответы пользователя по тегу SQL
  • Фильтрация характеристик товаров с подсчетом?

    @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 комментария
  • Как составить 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.
    Ответ написан
    Комментировать
  • Если БД две, то к какой из них будет обращение?

    @alexalexes
    Если это MySQL, сразу после подключения есть запрос на выбор БД (use ваша_база), его нельзя проигнорить и начать выполнять другие запросы, связанные с контекстом таблиц.
    Если это другая СУБД, то выбирается по умолчанию схема данных та, которая закреплена за пользователем по его правам доступа, либо она имеет то же имя, что и логин пользователя.
    Ответ написан
    Комментировать
  • Как отфильтровать таблицу по первому и последнему символам в ms sql?

    @alexalexes
    Так попробуйте:
    select id, name from testtable where trim(replace(Name, char(9), ' ')) like 'S%n';
    select id, name from testtable where trim(replace(Name, char(9), ' ')) like '%n';
    Ответ написан
    3 комментария
  • Как из двух таблиц создать одну с разбивкой по датам по колонкам?

    @alexalexes
    Сначала выбираете доступные даты:
    SELECT distinct P.date
    FROM Query Q
    JOIN Position P ON Q.id = P.query_id
    where P.Date between _ and _

    Потом, строите динамический запрос в той среде выполнения кода, где вызывали первый запрос:
    SELECT Q.Query,
                 QP1.Cnt,
                 QP2.Cnt,
                 ......
    FROM Query Q JOIN Position P ON Q.id = P.query_id
    left join (select Q1.Query, P1.Date, count(*) as Cnt from Query Q1 JOIN Position P1 ON Q1.id = P1.query_id group by Q1.Query, P1.Date) QP1 on QP1.Query = Q.uery and P1.Date = P.Date
    left join (select Q2.Query, P2.Date, count(*) as Cnt from Query Q2 JOIN Position P2 ON Q2.id = P2.query_id group by Q2.Query, P2.Date) QP2 on QP2.Query = Q.Query and P1.Date = P.Date
    ....
    where P.Date between _ and _
        and (QP1.Cnt > 0 or QP1.Query is null)
        and (QP2.Cnt > 0 or QP2.Query is null)
        ....

    Строк в каждом секции с ... должно быть столько, сколько дат.
    Ответ написан
    Комментировать
  • Как составить SQL запрос для отчета с разным количеством строк по категории?

    @alexalexes
    При помощи SQL вы получаете исходные данные, в виде первой таблицы.
    Далее работаете только кодом PHP.
    Вторая таблица - это у вас несколько матриц, по количеству подразделений.
    Одна матрица n*m это:
    n - макс. индекс предмета 000n в пределах одного подразделения.
    m - макс. индекс видов предметов во всей исходной выборке.
    Позиция в матрице i,j:
    i - это 000i
    j - индекс вида предмета.

    Для вывода результата вам нужно получить структуру:
    $result =
    [
      1 =>  // department_id
      [
         1 /* 000i индекс */ => [1 /*индекс вида предмета*/ => '1_1_0001', 2 => '1_2_0001', 3 => '1_3_0001' /* непосредственно данные */],
         2 /* 000i индекс */ => [1 /*индекс вида предмета*/ => '1_1_0002', 2 => '1_2_0002', 3 => '1_3_0002' /* непосредственно данные */],
         3 /* 000i индекс */ => [1 /*индекс вида предмета*/ => '1_1_0003', 3 => '1_3_0003' /* непосредственно данные */],
         ...
      ],
      2 =>
      ...
    ];

    Вариант 2, динамически в PHP создать запрос:
    select t.department_id,
              t1.item as type_1,
              t2.item as type_2,
              ...
    from t
    left join (select t.department_id, t.item from t where t.type_id = 1) t1 on  t1.department_id = t.department_id
    left join (select t.department_id, t.item from t where t.type_id = 2) t2 on  t2.department_id = t.department_id
    ...
    where 1 = 1
        and (SUBSTRING_INDEX(t.item, '_', -1) + 0 = SUBSTRING_INDEX(t1.item, '_', -1) + 0 or t1.item is null)
        and (SUBSTRING_INDEX(t.item, '_', -1) + 0 = SUBSTRING_INDEX(t2.item, '_', -1) + 0 or t2.item is null)
       ...
      -- тут нужно получить равенство всех субиндексов 0000i от t.item сравнить со всеми tn.item
    order by  t.department_id, SUBSTRING_INDEX(t.item, '_', -1) + 0
    Ответ написан
    2 комментария
  • Что нужно исправить, чтобы sql код заработал?

    @alexalexes
    У вас нет связи между таблицами Orders и Products.
    Либо потеряли свойство, для обеспечения связи "один-ко-многим":
    (Если один заказ может содержать в себе строго один продукт)
    CREATE TABLE Orders (
    ...
    Product_Id int,
    FOREIGN KEY (Product_Id) REFERENCES Products(Product_Id) -- внешний ключ к продуктам
    ...

    Либо потеряли целую таблицу, для обеспечения связи "многим-ко-многим":
    (Если один заказ может содержать в себе много продуктов)
    -- Таблица "Позиция продукта в заказе"
    CREATE TABLE Order_Positions (
    position_id INT PRIMARY KEY,
    order_id INT,
    product_id INT,
    FOREIGN KEY (Product_Id) REFERENCES Products(Product_Id), -- внешний ключ к продуктам
    FOREIGN KEY (order_id) REFERENCES Orders(order_id) -- внешний ключ к Заказам
    );
    Ответ написан
    Комментировать