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

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Вы не написали о какой БД идёт речь.
    Некоторые поддерживают вычисляемые поля. Значение такого поля не хранится в БД, оно вычисляется в процессе запроса "ленивым" образом незаметно, а для SQL выглядит как обычное поле.

    Если по какой-то причине вам не подходит вычисляемое поле, то можно воспользоваться триггером. Это менее элегантное решение представляет собой в БД специальную хранимую процедуру, которая запускается автоматически при изменении записи или в ответ на какое-то другое действие и способна менять значение полей.

    Однако я вам рекомендую не поддаваться на все эти соблазны и не хранить никакого кода в БД. Если вы прямо в SQL-запросах каждый раз будете перемножать эти величины, когда это нужно, то ничем это решение не будет менее эффективным чем предыдущие два. Формула у вас не так сложна и вполне очевидна, чтобы не наворачивать лишних сущностей.

    Первое решение ищется по строке "%my_db% calculated fields"/
    Второе: "%my_db% trigger on update"
    Третье и гуглить не надо. Просто умножайте всегда.
    Ответ написан
    Комментировать
  • SQL - сложный запрос многие ко многим?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Как-то так
    SELECT n.id, n.name
    FROM names n JOIN tags_names tn ON tn.goods_id = n.id
    GROUP BY n.id, n.name
    HAVING COUNT(DISTINCT tn.tag_id) = (SELECT COUNT(t.id) FROM tags t)
    Ответ написан
    Комментировать
  • Возможна ли SQL injection длиной в 4 символа или менее?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    %'--
    Для тупо составленного по шаблону запроса вида:
    "SELECT * FROM projects WHERE title LIKE '"+ variable_from_client + "' AND owner_id=13"
    Ответ написан
    1 комментарий
  • Как вывести все поля из БД без повторов?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Или так, если постгрес:
    WITH data AS (
      SELECT 1 AS id, 'Стивен Лэнг, Уильям Сэдлер' AS name UNION
      SELECT 2 AS id, 'Гай Ричи' AS name UNION
      SELECT 3 AS id, 'Стивен Кинг, Стивен Лэнг' AS name
    )
    SELECT DISTINCT unnest(regexp_split_to_array(name, ',\s*'))
    FROM data
    Ответ написан
  • Как выбрать записи у которых 2 и более связанных записей в другой таблице?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Че-то мне страшно теперь в поликлинику идти.
    Вы бы хоть названия таблиц какие-то предложили для ясности, чтоб не сочинять А и Б.
    SELECT rr.* 
    FROM (
      SELECT MIN(r.id) AS id
      FROM recept r
      JOIN history h ON r.id_history = h.id
      GROUP BY r.id_history
      HAVING COUNT(r.id) >= 2
    ) ids
    JOIN recept rr ON rr.id = ids.id
    Ответ написан
  • Как сформировать корректный SQL-запрос?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Не понимаю в чем у вас проблема. делайте дополнительно join источников, добавляйте все необходимые поля в группировку и селект, а больше ничего не изменится.
    При наличии индексов джойны по первичному ключу эффективны.
    Ответ написан
    Комментировать
  • Как правильно написать запрос к БД?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Ну приджойньте table2 трижды под разными алиасами и будет вам разом три коэффициента.
    В чем проблема-то?
    Ответ написан
    2 комментария
  • Как написать SQL?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    SELECT DISTINCT t1.eid
    FROM
        t t1
        JOIN t t2 ON t2.eid = t1.eid AND t2.key = 'patronymic' AND t2.value='Павлович'
    WHERE t1.key = 'place_award' AND t1.value = 'г.Коломна'

    И научитесь уже предоставлять исходные примеры таблиц в виде SQL, чтоб отвечающие могли быстро и без труда потестировать свои решения, а не писать из головы.
    Ответ написан
    Комментировать
  • Как использовать вложенный JOIN при GROUP BY?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    SELECT 
      AVG(length)
      ,SUM(h.price) -- это если сумма средств конкретного пользователя, а не вообще.
      ,(SELECT SUM(price) as s FROM help WHERE source=h.source) -- а это если сумма нужна полная по категории
    FROM 
      watch w 
        JOIN help h ON h.user_id=w.user_id and h.film_id=w.film_id 
    GROUP BY h.source)
    Ответ написан
    Комментировать
  • Как выбрать все значения с нескольких таблиц?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Автор вопроса сам не понимает что ему нужно сделать. Это значит, что результат не важен и мы тоже можем не париться, не углубляться и не гадать как экстрасенсы что же это действительно нужно было тому, кто сформулировал для автора эту задачу.
    Склорее всего решение не нужно ни автору ни тому кто задачу сформулировал -- никому.
    Оно также не нужно, как если бы автор вопроса спросил тут как вырезать аппендицит.
    Из вопроса не ясно есть ли в таблицах данные, какие там есть столбцы, какой диалект SQL, есть ли между данными из таблиц логическая связь. Автору скорее всего пофигу на все это. У него, наверно, есть задание и мы тут это задание должны решить заглянув в астрал и проявив чудеса предусмотрителности.

    SELECT 
      t1.f1 AS t1_f1, t1.f2 AS t1_f2, /*...*/ t1.fn AS t1_fn
     ,null  AS t2_f1, null  AS t2_f2, /*...*/ null  AS t2_fn
      /*...*/
     ,null  AS t7_f1, null  AS t7_f2, /*...*/ null  AS t7_fn
    FROM table1 t1
    UNION
    SELECT 
      null  AS t1_f1, null  AS t1_f2, /*...*/ null  AS t1_fn
      t2.f1 AS t2_f1, t2.f2 AS t2_f2, /*...*/ t2.fn AS t2_fn
      /*...*/
     ,null  AS t7_f1, null  AS t7_f2, /*...*/ null  AS t7_fn
    FROM table2 t2
    UNION
    /*...*/
    SELECT 
      null  AS t1_f1, null  AS t1_f2, /*...*/ null  AS t1_fn
     ,null  AS t2_f1, null  AS t2_f2, /*...*/ null  AS t2_fn
      /*...*/
     ,t7.f1 AS t7_f1, t7.f2 AS t7_f2, /*...*/ t7.fn AS t7_fn
    FROM tablen t7

    Формально требования выполнены.
    Ответ написан
    2 комментария
  • Группировка с выборкой?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Делайте вместо
    COUNT(*)
    подзапрос.
    SELECT
      case when id in (1,2,3,4) then 'Начальная школа'
              when id in (5,6,7,8,9) then 'Средняя школа'
              when id in (10,11) then 'Старшая школа'
              end AS Class_type,
      (
        SELECT COUNT(*) 
        FROM class cc 
        WHERE (
          case when сс.id in (1,2,3,4,5) then 'Начальная школа'
          when cc.id in (6,7,8,9) then 'Средняя школа'
          when cc.id in (10,11) then 'Старшая школа'
        ) = (
          case when c.id in (1,2,3,4) then 'Начальная школа'
          when c.id in (5,6,7,8,9) then 'Средняя школа'
          when c.id in (10,11) then 'Старшая школа'
        )
      ), 
      SUM(case when s.ocenka>4 then 1 end) AS 'Отличники' 
    FROM class c
    GROUP BY Class_type

    Как-то так через задницу. Запутано. Не проверял, нет файрбёрда под рукой
    Ответ написан
    Комментировать
  • Подзапрос вернул более одного значения, как исправить?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Да, вопрос непонятный нифига.
    Но чего именно вы хотите?
    Вы можете лимитировать количество выдаваемых значений:
    SELECT price
    FROM Laptop
    LIMIT 1

    Можно агрегировать получив, скажем, минимальную цену:
    SELECT min(price)
    FROM Laptop

    Или можно сделать join:
    SELECT DISTINCT model, price
    FROM PC p
    JOIN  Laptop l ON l.price = p.price

    Но это тупо и бесполезно. Вы, как бы, сопоставляете ноуты с десктопами по цене и показываете рядом...
    SELECT DISTINCT p.model, p.price, l.model
    FROM PC p
    JOIN  Laptop l ON l.price = p.price

    Я бы в таком случае не разделял на отдельные таблицы эти товары, а хранил бы в одной и сделал бы джойн с самой сообой. А сравнивал бы в некоторых рамках, иначе вы требуете точного совпадения цены.
    Ответ написан
  • Что это за программа (см. скрин)?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Ответ написан
    Комментировать
  • Выбрать строки с отсутствующим полем (значением NULL)?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Пишу на "ощупь", поскольку бд под рукой нет, но будет как-то так:
    SELECT
        keys.name, t.meta_value
    FROM
        (
            SELECT DISTINCT meta_key AS name
            FROM wp_postmeta
        ) AS keys
        LEFT JOIN wp_postmeta AS t ON t.meta_key = keys.name AND t.post_id = :id
    Ответ написан
    Комментировать
  • Почему так работает SQL выборка из поля типа float?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Я отвечу чуть более развёрнуто.
    Дело в том, что float хранит дробные числа в двоичном формате.
    Кроме двоичных мы работаем с десятичными числами и тут возникает проблема.
    К примеру, число 1/3 (одна третья) в десятичной системе счисления будет записываться как бесконечная (периодическая) десятичная дробь 0.33333(3). А вот в троичной системе счисления это число запишется конечной троичной дробью: 0.1 (читается, как "ноль целых и одна третья").
    По такой же схеме у нас десятичное число 0.5 (ноль целых и пять десятых) равно в двоичной 0.1 (ноль целых и одна вторая). 0.25 [10] == 0.01 [2]; 0.75 [10] == 0.5 [10] + 0.25 [10] == 0.11 [2].

    А теперь, внимание, на десятичное число 0.2 (ноль целых и две десятых), для перевода в двоичную систему счисления нам нужно сложить это число из членов двоичного ряда:
    ==1/2, 1/4, 1/8, 1/16, 1/32, 1/64, 1/128, 1/256, 1/512, 1/1024 ...
    0. 0    0    1    1     0     0   ( 1      1      0      0 )

    В круглых скобках обозначен период двоичной дроби. То есть двоичной дробью в конечном количестве знаков после двоичной запятой задать десятичное число 0.2 (ноль целых и две десятых) НЕЛЬЗЯ!

    Если у нас есть лишь конечное количество знаков, то ими представить в точности 2/10 в двоичной системе счисления одним числом невозможно.
    Чему конкретно получится равным "обрзанное" (округлённое конечно) число будет зависеть от того по какой именно двоичный разряд мы его округлили.

    Из всего этого следует, что сравнивать записанные таким образом числа на строгое равенство - плохая идея. На самом деле сравнивать на неравенство тоже так себе. Сравнение должно быть с некоторой точностью и точность эту нужно адекватно контролировать.

    Итак, чтобы сравнить два числа на равенство, скажем a и b, нужно выбрать некое e=0.0000001, которое будет определять точность сравнения и проверять условие: abs(a-b)<e - модуль разности сравниваемых чисел должен быть меньше выбранной точности. Если условие соблюдается, то числа считаем условно равными с заданной точностью. Если нет - не равными.

    Добавлю, что, как отметили выше, цены и денежные суммы вообще в формате с плавающей точкой хранить "плохая примета"=). Для этого есть специальные форматы, которые не создают таких сюрпризов при переводе из/в десятичную систему.
    Вот замечательная статья на хабре про это: Потеря точности из Double во Float или «Куда пропа...
    Ну и еще есть: Что нужно знать про арифметику с плавающей запятой, Наглядное объяснение чисел с плавающей запятой, Разбираемся в числах с плавающей точкой, и т.д.
    Ответ написан
    Комментировать
  • [22007] ERROR: invalid value "{dt." for "YYYY" Подробности: Value must be an integer?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Похоже, в ваш SQL попала строка шаблона в который забыли подставить значение:
    {dt.ToString("YYYY-MM-dd")}
    SQL эту строку интерпретирует как обычную строку, которую вы хотите привести к дате по формату YYYY-MM-dd. Само собой четыре символа {dt. не являются четырьмя цифрами года, которые ожидаются по шаблону. Об этом и ошибка.
    Проблема не здесь, а уровнем выше, где вы готовите SQL-запрос.
    Ответ написан
    Комментировать
  • Как правильно составить Sql запрос для получения данных из двух таблиц?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Если строго по условиям, то так:
    SELECT
      u.name, (SELECT COUNT(*) FROM stat s WHERE s.id_user = u.id)
    FROM users u
    WHERE u.date BETWEEN :dt1 AND :dt2


    Так вы посчитаете статьи только тех пользователей у которых они есть и удобно добавлять условия на сами статьи:
    SELECT u.name, count(*)
    FROM
      stat s
        JOIN users u ON u.id = s.id_user AND u.date BETWEEN :dt1 AND :dt2
    GROUP BY u.id, u.name

    Можно вывернуть наизнанку. Так получится вернуть и ноль статей для пользователей без статей. Как в первом запросе, но проагрегировать можно помимо количества статей, скажем, самое большое количество лайков (если бы у статьи было ещё число лайков). Или самую позднюю статью (если бы у статьи была дата публикации). Первый запрос на это не способен, вернее способен, но за счет либо доп затрат, либо ухищрений и не во всех диалектах.
    SELECT u.name, count(*)
    FROM
      users u  
        LEFT JOIN stat s ON s.id_user = u.id
    WHERE u.date BETWEEN :dt1 AND :dt2
    GROUP BY u.id, u.name
    Ответ написан
  • Как правильно выполнить sql запрос при помощи bat файла?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Попробуйте так:
    set isql="C:\\Program Files(x86)\\FireBird\\FireBird_2_1\\BIN\\isql.exe"
    echo ^
    SELECT C.CODE AS "Табельный", C.NAME AS "Ф.И.О.", T.TRANZDATE AS "Дата", max(T.TRANZTIME) AS "Время", T.INFOSTR AS "Карта" sum(T.SUMM) AS "Сумма" FROM DOCUMENT D LEFT JOIN TRANZT T ON D.ID = T.DOCUMENTID JOIN CLIENT C ON D.CLIENTID = C.ID WHERE T.TRANZDATE = cast('now' as date) and D.STATE = 1 AND D.ISFISCAL = 1 AND D.CLIENTID >=0 AND T.TRANZTYPE = '36' GROUP BY C.CODE, C.NAME, T.TRANZDATE, T.INFOSTR; ^
    | %isql% 127.0.0.1/3050:E:\Torgovlya54\MAIN.GDB sysdba masterkey > outputfile.txt

    Каждая строчка, передаваемая isql должна закачиваться "^", чтобы попасть в одну команду с echo и передаться на вход isql.
    Весь выхлоп isql направлен в текстовый файл.
    У меня винды под рукой нет и файрбёрда тем более. так что пробуйте сами. Пишите если не получится -- будем еще смотреть.
    Ответ написан
    23 комментария
  • Почему sql запрос обновляет только числовые значение?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Потому, что собирать sql таким способом (постановками строк и конкатенацией) очень плохая идея. Используйте параметризированные запросы. Даже в. Php это можно и нужно делать.
    Ответ написан
    Комментировать
  • Как посчитать сумму одинаковых значений по одной колонке, но разных по другой?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Уберите T.TRANZTIME из группировки и из селекта. Там два разных значения.
    Если вам обязательно надо какое-то показать (например последнее), то выкиньте его из группировки, а в селекте поставьте там агрегатор, например, max.
    Вот так ваш Сидоров просуммируется на этом датасете в одну строку:
    SELECT
        C.CODE AS "Табельный",
        C.NAME AS "Ф.И.О.",
        T.TRANZDATE AS "Дата",
        max(T.TRANZTIME) AS "Время",
        T.INFOSTR AS "Карта",
        sum(T.SUMM) AS "Сумма"
    FROM 
        DOCUMENT D
            LEFT JOIN TRANZT T ON D.ID = T.DOCUMENTID
            JOIN CLIENT C ON D.CLIENTID = C.ID
    WHERE
          T.TRANZDATE >='20.02.2020' AND T.TRANZDATE <='20.02.2020' AND
          T.TRANZTIME >='18:55:00' AND T.TRANZTIME <='23:59:59' AND
          D.STATE = 1 AND
          D.ISFISCAL = 1 AND
          D.CLIENTID >=0 AND
          T.TRANZTYPE = '36'
    GROUP BY
        C.CODE,
        C.NAME,
        T.TRANZDATE,
    --    T.TRANZTIME,
        T.INFOSTR
    --    ,T.SUMM

    Но на этом ваши проблемы не кончатся. В вашем SQL много других косяков:
    1. Какой смысл делать такое условие: T.TRANZTIME <='23:59:59'? Любое время будет ему удовлетворять.
    2. Если ваши дата и время связаны, то есть определяют какой-то момент во времени, то их нужно хранить и фильтровать как единое значение, иначе вы сами не заметите как наткнётесь на не очевидную (для новичка) ошибку неконсистентности. К примеру, событие Б позднее события А, но А произошло вечером, а Б утром (другого дня). При вашем отдельном сравнении дат и времён может получиться некорректность из-за того, что время (без даты) события А > времени (без даты) события Б. Соедините дату и время в единое поле datetime или соединяйте их каждый раз когда делаете условную фильтрацию по временнОму диапазону.
    3. Зачем вы группируете по T.SUMM, если собирались агрегировать это поле?
    Ответ написан
    2 комментария