Ответы пользователя по тегу SQL
  • Как составить запрос 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
    Ответ написан
  • Как сделать категории в интернет магазине?

    @alexalexes
    Пишется один рекурсивный запрос одного из видов (или оба вида, чтобы два раза не вставать).
    1) Получения списка детей, если известны параметры родителя (до определенного уровня, с пропуском неважных уровней).
    2) Получения списка предков (до определенного уровня, с пропуском неважных уровней), если известны параметры ребенка.
    Выносите эти запросы в секцию with, даете им понятные псевдонимы.
    Далее ниже по тексту пишите уже привычные запросы, используя эти псевдонимы, словно это view или кеш-таблицы.

    PS: Если иерархическая выборка нужна в подзапросе, и она зависит от изменяемых в ходе выборки входных параметров ребенка/родителя, то тут нужно выносить 1 и 2 в хранимые функции, где результат функции будет табличный курсор. При использовании результата этого курсора, обычно, делают преобразование результата функции в тип "таблица" через выражения cast.
    Ответ написан
    Комментировать
  • Что такое выражение в SQL?

    @alexalexes
    Выражение, это значит, что в месте между, например, select и запятой может не только выбираться значение столбца (выполняться тривиальное действие):
    select col1, -- извлекли содержимое колонки - вполне тривиальное действие
               col2 from table1

    Но выполнятся более функциональное действие, требующее от планировщика запросов разобрать что-то, что находится до селекта и запятой (почему что-то? - это и есть выражение))) ):
    select (col1 + col2) * 10 as result, -- а тут уже применили ариф. операции - написали выражение
               col2 from table1

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

    @alexalexes
    Стандартная практика ведения истории изменения данных таблицы.
    Вешаете триггер по операциям UPDATE, INSERT, DELETE перед их выполнением (опция before) на интересуемую таблицу и вставляете данные из атрибутов old.* триггера в таблицу истории.
    Таблица истории:
    history_id - идент. записи истории
    next_history_id - идент. следующей записи истории в пределах одной записи отслеживаемой таблицы (у последней он null)
    oper_type - тип операции (UPDATE, INSERT, DELETE - можно числами записать)
    old.* - все атрибуты таблицы, значения до выполнения операции.
    new.* - все атрибуты таблицы, которые пытались внести операциями UPDATE или INSERT. Этот набор нужен, если вы следите за историей на транзакциях, которые были откатаны назад (неудачные попытки). В этом случае, в триггере нужно указать специальную опцию, чтобы он работал в режиме автономной транзакции.
    При внесении новой записи истории, в предыдущей записи по такому же первичному ключу отслеживаемой таблицы нужно добавлять next_history_id от history_id новой записи.
    Таким образом в отслеживаемой таблице будет актуальное состояние записи, а в таблице истории - цепочка изменений записей.
    По каждому первичному ключу записи отслеживаемой таблицы можно построить цепочку изменений по history_id и next_history_id.
    А по next_history_id is null можно быстро получить последнее изменение из этой цепочки.
    Естественно, к этим полям нужно добавить индексы.
    Ответ написан
    Комментировать
  • Как реализовать получение уникального айди из базы данных?

    @alexalexes
    Ну, insert вы для себя открыли.

    я хотел сделать отдельный параметр в бд, который проверяется

    посмотрите, как пользоваться select-ом, да еще с входными параметрами, чтобы извлечь строку.

    заменить в ней значение,

    Ищем как пользоваться запросом c update, да еще с параметрами.
    PS: Если еще посмотрите, как пользоваться delete, то CRUD комплект вы изучили, как взаимодействовать с базой.
    PPS: cursor после выполнения insert может содержать свойство last insert id, но это не точно.
    Ответ написан
    Комментировать
  • Как правильно организовать таблицы?

    @alexalexes
    1. Сделать правильную таблицу Client с полем год.
    2. Создать индекс на поле год.
    3. Сделать импорт из таблиц Client_ГОД в таблицу Client с указанием поля года.
    4. Переписать запросы, чтобы присутствовала таблица Client в контексте нужного года (выборка с параметром год).
    5. Если очень нужно ограничить выборку по нужному году (по соображениям разграничения прав), то для определенных запросов сделать view по нужному году, выдать права на view для определенного пользователя.
    Ответ написан
    Комментировать
  • Как получить timestamp,обрезав пустое время?

    @alexalexes
    komino, это проблема разработчика, а не конфига драйвера СУБД, как он будет интерпретировать значение даты в конкретном запросе, если ему не подходит статичный шаблон nls_date_format. Такой шаблон не имеет в себе лексического интерпретатора, способного выполнять условные операторы.
    Решение:
    select
    -- вариант 1
    to_char(sysdate, 'DD.MM.YYYY' || decode(sysdate - trunc(sysdate), 0, '', ' HH24:MI:SS')) as your_format_date_1, 
    -- вариант 2
    case
      when sysdate - trunc(sysdate) > 0
      then to_char(sysdate, 'DD.MM.YYYY HH24:MI:SS')
      else to_char(sysdate, 'DD.MM.YYYY')
    end as your_format_date_2
    from dual;
    Ответ написан
  • Почему sql запрос не определяет имя таблицы, если записывать имя через prepare?

    @alexalexes
    1. В качестве входных параметров никогда не использовались имена таблиц в подготовленных запросах - это попытка забивать микроскопом гвозди.
    2. Метки для входных параметров - это не тип данных, это просто название места куда будет подставлено значение этой метки по ключу из массива значений.
    Причем, именованные метки нужно связывать со значением с помощью специальной функции:
    $stmt = $db->prepare("SELECT * FROM moya_tablitsa WHERE id = :metka_parametra_identifikatora");
    $stmt->bindParam(':metka_parametra_identifikatora', 123);
    $stmt->execute();

    Но можно не использовать именованные метки (если их несколько в запросе, то нужно вставлять значения по порядку)
    $stmt = $db->prepare("SELECT * FROM moya_tablitsa WHERE id = ?");
    $stmt->execute([123]);

    Можно использовать связывающую функцию, указав порядок метки.
    $stmt = $db->prepare("SELECT * FROM moya_tablitsa WHERE id = ?");
    $stmt->bindParam(1, 123); // 1 - это номер метки, 123 - значение параметра
    $stmt->execute();
    Ответ написан
    Комментировать
  • Есть ли бесплатное API для получения всех улиц и домов конкретного города?

    @alexalexes
    https://fias.nalog.ru/Updates
    Тут есть полный архив адресов и разностные файлы на определенную дату.
    Ответ написан
    Комментировать
  • Подсчёт кол-ва детей у сотрудников access?

    @alexalexes
    Подскажите пожалуйста - в каком направлении думать.

    Подтянуть знания:
    1. Псевдонимы таблиц и полей в SQL.
    2. Соединения таблиц (join, left/right/cross join).
    3. Использование группировок в выборке.
    4. Агрегирующие функции (count, max, min и т.д.).
    В перспективе:
    5. Оконные функции.
    6. Подзапросы для получения скалярного значения (используется в секции select или в where)
    7. Подзапросы в секции from
    Select w.`Код`, w.`Фамилия`, w.`Имя`, w.`Отчество`, 
               count(ch.*) as Child_Count -- кол-во детей
               -- count(distinct ch.`Фамилия`, ch.`Имя`, ch.`Отчество`, ch.`Дата рождения`) as Child_Count -- кол-во детей по группе уникальных полей по таблице Дети, без использования идентификатора
    from `Список` w
    join `Дети` ch on ch.`КодСотрудника`  = w.`Код`
    group by w.`Код`, w.`Фамилия`, w.`Имя`, w.`Отчество`
    Ответ написан
  • Как правильно составить запрс с двумя INNER JOIN?

    @alexalexes
    Очевидно, что нужны алиасы к таблицам, особенно к тем, которые несколько раз присоединяются.
    select psc.*, 
      pt1.`value` as `picture`, 
      pt2.`value` as `sort_pos`
     from `pref_site_content` as psc
        inner join `pref_site_tmplvar_contentvalues` as pt1 on pt1.`contentid` = psc.`id` and pt1.`tmplvarid` = 37 
        inner join `pref_site_tmplvar_contentvalues` as pt2 on pt2.`contentid` = psc.`id` and pt2.`tmplvarid` = 111 
        where psc.`id` not in (898, 899, 900, 902)
           and (`template` = 40 and `published` = 1) -- тут, возможно, тоже можно добавить, если в таблицах поля одинаково названы
    Ответ написан
  • Как внутри echo или переменной выполнить цикл и ещё одно echo?

    @alexalexes
    // Вы определитесь:
    $table = /* либо копите результат верстки в переменной table, а потом после обработки выводите все содержимое на строке N */
     '
        <tr>
        <td>'. $trtd .'</td> //отрисовывает первым столбиком таблицы номер сотрудника в таблице бд
        <td>'. $array[0]++ .'</td> //отрисовывает вторым столбиком таблицы имя сотрудника в таблице бд
        '. // зачем тут перед for конкатенация ?
    
    for ($td=1; $td<=$daysinmonth; $td++){
    // Либо сразу выводите результат через echo, не накапливая ничего для вывода контента
    echo '<td>тут какое-то значение, в будующем должен быть код с операторами if и т.д.</td>';}.' //отрисосывает оставшиеся столбцы в зависимости от кол-ва дней в месяце
        </tr>';// если вы множите ячейки дней месяца, то наверное, строку таблицы нужно закрывать не в теле цикла?
      /*строка N */  echo ($table); // вывод всего накопленного содержимого

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

    @alexalexes
    Как мне получить 12 строчек,

    применить в запросе клаузу limit

    по убывающей значения numberofVisits


    применить в запросе клаузу order by с опцией desc по данному полу выборки.
    Ответ написан
    Комментировать
  • Как мне составить правильный SQL запрос?

    @alexalexes
    SELECT  *
    FROM  multfilms as m
    where m.title like '%Шрек%'
    union
    SELECT  *
    FROM  multserials as m
    where m.title like '%Шрек%'

    union будет работать, при условии, что выборках одинаковое кол-во колонок и данные в них одинакового типа.

    Но вообще, если вы под каждый тип контента создаете новую таблицу с почти однотипными атрибутами - значит, это признак того, что вы делаете ошибку проектирования с точки зрения архитектуры реляционных баз.
    Правильно сделать так:
    Сделать таблицу типа фильма по контенту:
    film_content_type
    С атрибутами:
    id - идент. типа
    full_name - полное название типа контента (фильм, мультфильм, сериал и т.д.)
    ... другие атрибуты типа фильма.

    И у вас будет единственная таблица с фильмами:
    films
    атрибуты
    id - идент. фильма
    content_type_id - тип фильмового контента (внешний ключ к таблице film_content_type)
    title - Название фильма
    ... другие атрибуты фильма

    Тогда запрос будет такой:
    SELECT  f.*, 
           t.full_name
    FROM  films f
    join film_content_type t on t.id = f.content_type_id
    where f.title like '%Шрек%'

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

    @alexalexes
    Ничего не понятно. Но из того, что привели в примере и проговорили словами можно слепить это:
    $table = Model::selectRaw('title, name_list, count(*) as count, sum(count_model * 2) as total, min(created_at) AS date') // в выбираемые поля нужно добавить title - вы же хотите его извлечь?
                ->groupBy('title, name_list') // сюда нужно прописать группируемые поля, которые не участвуют в агрегирующих функциях count, sum, min и т.д.
                ->orderBy('name_list', 'DESC') // тут пишите поле, по которому сортируете, ASC или DESC - направления сортировки
                ->take(10)
                ->get();
    Ответ написан