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

    @alexalexes
    select A.*
    from (SELECT Pss.session_id,  Pss.peak,
             row_number() over (partition by Ps.id order by Pss.peak desc) rnm -- нумеруем оконной функцией выборку в пределах каждого Ps.id по нужной сортировке
        FROM peak_sessions_sets Pss
        JOIN peak_sessions Ps ON Pss.session_id = Ps.id
        WHERE Ps.user_id = 1
    ) A
    where A.rnm = 1 -- извлекаем по 1 записи
    order by A.Peak Desc -- если надо, то еще как-то сортируем итог
    Ответ написан
    Комментировать
  • Как найти общие поля в таблицах?

    @alexalexes
    Если задача на знание справочника SQL, то есть такая конструкция:
    таблица1 join таблица2 using (общие_имена_полей)
    это эквивалент:
    таблица1 join таблица2 on таблица1.общее_имя_поле = таблица2.общее_имя_поле...

    Вариант с using будет работать, если выдерживается культура именования, при которой в названии поля есть название таблицы.
    Ответ написан
  • Можно ли делать запрос к промежуточной таблице многие-ко-многим для извлечения конкретной информации?

    @alexalexes
    Что-то много философии про можно/нельзя. Нужно влоб погуглить "join-ы в sql" и набросать что-то такое:
    select b.*, -- все колонки по книге
            a.* -- все колонки по сведениям об авторе
    from books as b
    join book_autor as ba on b.book_id = ba.book_id  -- если у книги может не быть авторов, то нужен left join
    join autors as a on ba.autor_id = a.autor_id -- если у книги может не быть авторов, то нужен left join
    where b.book_id = :book_id -- сюда подставляем параметр нужной книги.
    Ответ написан
  • В какой базе данных лучше всего хранить данные для дашбордов?

    @alexalexes
    В реляционной базе - основная таблица - это лог событий.
    event_log:
    event_id - идентификатор события
    event_date - дата и время события
    event_type_id - тип события (пришло или ушло)
    value - сколько (пришло или ушло, положительное значение)
    А чтобы подготовить данные для визуализации, переводите лог в агрегированный вид:
    либо делаете view на основе запроса, либо делаете хранимую процедуру для генерации агрегированных данных и кладете их в отдельную таблицу:
    daily_statistics:
    id - идентификатор агрегированной точки
    stat_date - дата агрегированной точки
    in_value - пришло (кол-во)
    out_value - ушло (кол-во)
    current_value - баланс

    Записи лога событий вы храните до тех пор пока они будут затрагиваться периодом хотя бы одной агрегирующей процедурой. При 2-кратном устаревании записей лога - эти записи можно удалять (или смотреть регламент, сколько хранятся физические документы, которые отражают эти данные, и следовать регламенту).
    Ответ написан
    1 комментарий
  • Как сделать что-то вроде джойна из таблицы в ту же самую таблицу?

    @alexalexes
    Еще бы какой-то атрибут добавить, чтобы тип записи различать - тогда жить можно.
    select t1.*, -- тематики
          t2.* -- вопросы
    from table_1 t1
    join table_1 t2 on t2.topic = t1.id
    where t1.topic is null
    and t1.Name like 'Тематика%' -- не хватает атрибута type, чтобы различать раздел от тематики
    Ответ написан
  • Как иерархические данные из таблицы преобразовать в объекты Java?

    @alexalexes
    Составить SQL-запрос на основе синтаксиса WITH RECURSIVE, чтобы выборка происходила от корня к листьям.
    Выполнить запрос и получившуюся выборку прогнать через рекурсивную функцию, которая построит дерево, на основе описанной структуры элемента дерева.
    Ответ написан
    Комментировать
  • В чем разница между функцией и триггером?

    @alexalexes
    Триггер - это функция (точнее процедура), запускаемая (поджигаемая) событиями изменения данных - insert, update, delete (до или после события), на определенной таблице.
    В описании триггера обязательно указано событие, на которое он подписан для начала выполнения.
    Обычная функция может быть вызвана как пользователем, так и из тела триггера.
    Триггеры, функции, процедуры как правило пишутся процедурным языком, встроенным в СУБД, в отличии от декларативного языка SQL.
    Ответ написан
    Комментировать
  • Некоторые бинарные строки не определяются по оператору LIKE, проблема не дебажится, в чём может быть причина?

    @alexalexes
    Вероятно, проблема в состоянии индекса на поле info_hash_v2 (вы же используете индексы в базе для ускорения поиска?). Запустите перерасчет индекса для устранения глюка.

    PS:
    $info_hash_where = "WHERE tor.info_hash = '$info_hash' OR tor.info_hash_v2 LIKE '$info_hash%'";

    Ай-ай-ай. Склейка параметров запроса с текстом запроса, ой не хорошо. Не хотите познакомиться с подготовленными запросами?
    Или нормально исследуйте класс объекта DB, вдруг там есть нормальный метод bind_param, а то вдруг используете инструмент не до конца по назначению.
    Ответ написан
  • Как оптимальнее всего организовать хранение тяжёлых данных и чтобы потом максимально быстро доставать оттуда данные для отчётов?

    @alexalexes
    Структура таблицы нормальна, только добавьте индекс на поле date_submitted и индекс на поле score и будет летать.
    Запрос для получения рейтинга на каждый день для всех пользователей будет примерно такой:
    with date_list as (/*Любым способом получаете непрерывный список дат интересуемого диапазона */)
    select A.date, u.user_id, nvl(A.max_score, 0) max_score /* nvl зависит от СУБД */
    from (select dl.date, u.user_id, tb_max_score.max_score,
              rank() over (partition by dl.date order by random() /*реализация функции random зависит от СУБД*/ ) rnk
    from (select us.date_submitted, max(us.scope) max_score
               from user_score us) tb_max_score  -- выясняем макс-ные баллы
    left join date_list dl on dl.date = tb_max_score.date_submitted
    left join user_score us on dl.date = us.date_submitted  -- выясняем, у кого макс-ные баллы
                                      and us.score = tb_max_score.max_score
    ) A
    cross join user u u.user_id = A.user_id -- прицепляем тех, кто возможно не участвует в рейтинге
    where A.rnk = 1
    Ответ написан
    Комментировать
  • Как объединить данные товара и фото товара в одном запросе?

    @alexalexes
    Можно, через join этих двух таблиц.
    Результатом запроса будет выборка:
    (product_)id, (product_)name, (photo_)id, (photo_)url
    1, 'Товар 1', 1, 'example.png'
    1, 'Товар 1', 2, 'example2.png'

    На стороне скрипта, который отправлял запрос SQL в СУБД, собираете на основе этой выборки объект с требуемой структурой, и потом перекодируете его в строку JSON.
    Ответ написан
    1 комментарий
  • Можно ли составить такой sql запрос?

    @alexalexes
    Если универсальный запрос составлять, который не зависит от состава свойств, то он будет многострочный, нужно собирать свойства в массив в той среде откуда обращались к СУБД:
    select 
      ar.id, 
      ar.name, 
      ar.date, 
      ar.text,
      ap.property_id,
      p.name as property_name, --поскольку у вас есть в базе реализовано универсальное хранение свойств, то почему бы не вывести имя свойства из справочника?
      ap.value as property_value
    from  articles as ar
    left join articles_property as ap on  ap.article_id = ar.id
                                                            and ap.property_id in (/* перечисляем все необходимые свойства */) 
    left join property as p on  ap.property_id = p.id -- справочник названий свойств

    Другой вариант запроса дает конкретные значения свойств, и довольно плоскую выборку, не требующую постобработки (одна строка - это строго одна статья). Но такой запрос не универсален по набору свойств.
    select 
      ar.id, 
      ar.name, 
      ar.date, 
      ar.text,
     (select value
        from articles_property as ap
      where ap.article_id = ar.id
          and ap.property_id = 10) as author
    from  articles as ar
    Ответ написан
  • Как выбрать много пользователей через чекбоксы и выполнить sql запрос?

    @alexalexes
    Оборачиваете html-таблицу в форму, с кнопочкой сабмита. Когда отметили нужное, пользователь должен засабмитить форму. В форме нужно указать метод передачи GET или POST и адрес, где будет располагаться серверный скрипт обработки формы.
    В скрипте примерно такой код:
    <?php
    // считаем, что данные пришли по POST-у
    if(isset($_POST['submit'])) // проверяем, что приехали данные формы по submit, в кнопке сабмита атрибут name должен иметь значение submit
    {
       $inserted_user_count = 0;
       if(isset($_POST['selected_users'])) // присутствуют отмеченные пользователи
       {
          $pdo = new PDO(параметры подключения к базе);
          foreach($_POST['selected_users'] as $selected_user_id)
          {
            $stmt = $pdo->prepare('insert into ваша таблица (атрибуты таблицы) values (значения атрибутов таблицы, кроме user_id, :user_id)');
            $stmt->bindParam(':user_id', $selected_user_id, PDO::PARAM_INT);
            // еще байндим какие-то параметры у запроса, если есть плейсхолдеры, кроме :user_id.
            $stmt->execute(); // наконец, выполняем запрос
            $pdo->commit(); // фиксируем изменения в базе данных, если у вас соединение открыто не в режиме автокамита
            $inserted_user_count++;
          }
          $pdo = null; // закрываем соединение с базой
       }
       echo 'Обработано пользователей: '.$inserted_user_count;
    }
    ?>
    Ответ написан
    Комментировать
  • Как прибавлять значение в базе данных SQL для бота aiogram?

    @alexalexes
    1. Выбрать из базы запись по известному user_id.
    2. Если получили запись, то выполнить обновление атрибута записи win = win + 1 где user_id этой записи равен известному user_id (то же самое в случае проигрыша loss = loss + 1).
    3. Если не получили запись, то делаете вставку записи пользователя, с win = 0, loss = 0 (с 1 в нужной ситуации).
    Ответ написан
  • Как можно рассортировать элементы базы данных по русскому алфавиту?

    @alexalexes
    У MySQL для сортировки кириллицы нет специфичных рекомендаций к order by.
    Только, если вы не захотите применить естественную сортировку (от кодировки не зависит), то в MySQL нет для этого функций, есть некоторое подобие решения проблемы:
    select '10' Name union
    select '1' Name union
    select '20' Name union
    select '2' Name
    order by length(Name), Name
    Ответ написан
    Комментировать
  • Как составить запрос sql?

    @alexalexes
    Бывает, нужно получить непустой результат при любых обстоятельствах.
    Но так делают, не потому что нет других средств, а просто лень выписывать это за пределами SQL.
    select A.*
      from (select t.col1, t.col2, ..., t.colN from t -- выборка для "не по умолчанию"
            union all 
            select def_col1, def_col2, ... def_colN from dual -- строка значений по умолчанию
           ) A
    where rownum = 1 -- выбираем только первую строку, неважно из чего

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

    @alexalexes
    Если нужно ограничить выборку по вычисляемой колонке case, а разбирать смысл ее лень (или вы в процессе отладки это делаете), то нужно взять этот кейс, перетащить в where и проверить на is not null. Все, что в условия кейса попадает - будет строковым значением (нужно глазками посмотреть, чтобы в кейсе не было исходов с null), а все что не попадает в его условия - обратится в null (если явно не прописан else).
    SELECT id,
    CASE
      WHEN price > 10000 AND price < 11000 THEN 'Economy'
      WHEN price >= 20000 AND price <= 30000 THEN 'PremiumEconomy'
      WHEN price > 100000 THEN 'Business'
    END as service_class, price
    FROM tickets
    where CASE
      WHEN price > 10000 AND price < 11000 THEN 'Economy'
      WHEN price >= 20000 AND price <= 30000 THEN 'PremiumEconomy'
      WHEN price > 100000 THEN 'Business'
    END is not null

    А если делать по уму, конечно, кейс оставлять в where - это крайняя мера. Его быть не должно, это ухудшит показатели плана выполнения запроса (не всегда). Нужно вытаскивать булеву конструкцию, желательно, логически упрощенную.
    SELECT id,
    CASE
      WHEN price > 10000 AND price < 11000 THEN 'Economy'
      WHEN price >= 20000 AND price <= 30000 THEN 'PremiumEconomy'
      WHEN price > 100000 THEN 'Business'
    END as service_class, price
    FROM tickets
    where (price > 10000 AND price < 11000) --  'Economy'
       or (price >= 20000 AND price <= 30000) --  'PremiumEconomy'
       or (price > 100000) -- 'Business'

    PS: Конечно, странные у вас кусочные интервалы между классами обслуживания. Скажем, показатель в 12000 выпадет из любого класса. Обычно, их делают перекрывающими диапазонами. Ну, да ладно, тем интересней для вас разбирать запрос.
    Ответ написан
    Комментировать
  • Почему в данных таблицы все не по порядку?

    @alexalexes
    О порядке добавления записей не нужно заботиться.
    У СУБД нет задачи хранить записи в строгом порядке, ваша задача понять, удовлетворит ли вас результат сортировки, если при выборке задать сортировку по darg-w:
    select *
      from verbs
    order by darg-w

    Если хотите получать список в порядке добавления, то логично сортировать по id:
    select *
      from verbs
    order by id

    Если хотите особую сортировку, которая не подчиняется ни id, ни естественному весу строк, то можете ввести новую колонку и следить за позиционированием строк при выборки сами, или по каким-то другим правилам вычислять позицию:
    select *
      from verbs
    order by position -- дополнительное поле, в которое будете сами или программно вбивать порядок сортировки

    Или запрос может выдергивать сам определенные строки, давая им высший приоритет (можно написать любое правило, что требует бизнес логика, или что в голову сбредет):
    select *
      from verbs
    order by case when id = 100 then 0 else 1 end -- даем записи id=100 наивысший приоритет, в любом состоянии списка она будет на 1 месте!
            , id -- остальные записи отсортируются в порядке добавления

    PS: Важно, чтобы поля, которые применяются в сортировке, были проиндексированы (в схеме СУБД были созданы индексы по данным полям и они своевременно пересчитаны).
    Ответ написан
    1 комментарий
  • Как проверить принадлежат ли массивы из одной таблицы массивам в другой?

    @alexalexes
    С помощью функции json_to_recordset проводите нормализацию таблиц, чтобы на выходе pair получилась вот такая псевдотаблица-выборка:
    pair
    id_group, name
    1, "ананас",
    1, "апельсины",
    2, "ананас",
    2, "арбуз"
    ...
    Дальше тоже самое делаете с order_list.
    Ну, а дальше все приведено в 3-ю нормальную форму, можно, наконец, использовать SQL-ные сравнения/соединения этих псевдовыборок и высчитывать кол-ва того-сего.
    PS: Такое решение годится как разовое для получения результата, например, если вам нужно срочно сделать нестандартный отчет для руководства, а структура таблиц спроектирована из рук вон плохо.
    Нужно изначально планировать структуру базы так (приводить к 3-й нормальной форме), чтобы не прибегать к декомпозиции полей с помощью функций JSON, если компоненты внутри JSON будут использоваться для соединения между таблицами.
    Ответ написан
  • Как передавать один параметр, а не 3?

    @alexalexes
    FROM views v JOIN memes m JOIN comments c
    Вы конечно, не указали, в какой СУБД пишете, но странно видеть JOIN без ON или USING.
    Если это эквивалент синтаксиса с USING, то вы увидите статистику, если по пользователю есть И просмотры, И мемы, И комментарии. Если в одной из таблиц не будет записей, то пользователь вывалится из статистики.
    Если это эквивалент:
    FROM views v, memes m, comments c
    То такое декартово произведение таблиц с использованием distinct будет не производительно.
    Рационально вам написать такое:
    SELECT (select COUNT(v.id) from views v where v.user_id = u.user_id )      AS просмотры,
           (select COUNT(DISTINCT v.meme_id) from views v where v.user_id = u.user_id) AS [уникальные просмотры],
           (select COUNT(m.id) from memes m where m.user_id = u.user_id)      AS [выложено мемов],
           (select COUNT(c.id) from comments c where c.user_id = u.user_id)      AS [написано комментариев]
      FROM users u -- лучше связаться с таблицей users
     WHERE u.user_id = 1

    Тогда каждый подзапрос будет работать по своей агрегации (да, если по какой-то таблице не будет записей, то вы увидите по ней ноль, а не пустую строчку по всем параметрам), дистинктовать вам нужно только по параметру уникальные просмотры - но его использование не связано с размножением записей при объединении таблиц, так что он посчитает его достаточно быстро.
    PS: Если вы не забыли создать индексы для v.user_id, v.meme_id, m.user_id, c.user_id, то должно все летать на космической скорости.
    Ответ написан
  • Как вывести id?

    @alexalexes
    1. Вычисляете агрегированную выборку - подзапрос A.
    2. Сортируете выборку в том порядке, как собираетесь нумеровать - подзарос B.
    3. Нумеруете строки доступной функцией в конкретной СУБД (в Oracle это rownum, в остальных средах есть row_number, в MySQL 5 версии нужно делать костыль из пользовательской переменной @ и if-a).
    select rownum, B.*
    from (select A.*
                from (SELECT v.user_id,
                      u.nickname,
                     COUNT(DISTINCT v.meme_id) as meme_count
                    FROM views as v
                       join  users u on u.id = v.user_id
                   GROUP BY v.user_id, u.nickname) A
            order by A.meme_count desc) B
    Ответ написан