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

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

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Транспонирование таблиц в SQL не предусмотрено в большинстве БД.
    Если набор параметров динамический, то так не получится, потому что не ясно сколько получится столбцов в итоге, а динамически их делать нельзя.
    Можно собрать JSON с атрибутами, но это тоже такое себе.
    Обычно такое транспонирование делают в коде на бэке, а не в SQL.
    Между тем вы не написали даже какая у вас БД и на чем делаете бэкенд.

    На постгресе оптимально было бы сделать джойн, группировку, а при агрегации собирать массив key-value, или JSON, тогда у вас будет два столбца: id, params. Второй столбец будет содержать json'ы.

    Ещё один способ можно применить при более-менее статичном наборе возможных параметров. Отдельным запросом получаете все возможные уникальные имена параметров в алфавитном порядке и в том же порядке джойните слева (left join) соответствующие значения. При агрегации вы просто собираете csv-строку с строковыми значениями параметров, а для тех параметров, которых нет, будет пустая строка или null.
    Можно собирать не строку с разделителями, а массив строк, или json-список.
    Ответ написан
  • Как работать с файлом SQL объемом 20 ГБ?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Вы выбрали плохой путь по ряду причин.
    Во-первых, вы пытаетесь вычитать весь 20гб файл в оперативную память. Это будет долго, отожрёт кучу свопа и не факт. что завршится успешно.
    Во-вторых, вы пытаетесь запустить весь SQL за один раз - это вы правильно поняли.ч то проблематично.
    Ну а в-третьих...
    В общем, следует глазами посмотреть в SQL и понять что там. Если там дамп БД, то сперва идут стейтменты для содания таблиц, индексов, хранимок, а потом уже операции вставки в эти таблицы.
    Ваш файл называется "часть 3", так что, возможно, часть нужных стейтментов для создания структур просто оказались в других фвйлах.
    Обычно кусок SQL, который создаст все таблицы, не так уж и велик по размеру. Можно открыть файлы с дампом текстовым редактором и вытащить оттуда куски SQL из начала с созданием структуры. Положить эти кусуи в отдельный файл. Иногда в SQL-файле с дампом лежит и команда создания базы, посмотрите внимательно.

    Когда у вас операции вставки данных в БД в отдельном огромном файле, всё тсановится чуточку проще.
    Если у вас задача одноразовая и нужно просто найти один номер и больше ничего, то можно просто воспользоваться командой grep на SQL файле. Она поищет нужный номер и покажет строчки, в которой он встретился. Параметры командной строки могут настроить выхлоп так, чтобы показывались несколько строчек. Это, возможно пригодится, если отдельные стейтменты со вставками занимают по много строк. Так можно быстро найти нужные данные не возясь с поднятием БД.

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

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Вы смутили народ соей странной постановкой задачи.
    В реальном мире смысл монеты ка краз в ее неуникальности и взаимной заменяемости с другими такими же. А у вас это не монеты, а, своего рода, токены. И если формулировать так, то станет гораздо понятнее.

    У вас определённо должна быть таблица токенов и, если каждй токен кому-то принадлежит, то токен должен ссылаться на текущего владельца.
    Вообще тут можно всё сделать очень по-разному в зависимости от того, какие операции и какие отчеты вам нужны чаще, а какие реже, какие агрегации надо делать.
    К примеру, можно хранить у каждого токена ссылку на его текущего владельца, а в отдельном журнале историю движения токена в том виде в каком вы предложили.
    Фактически это журнал транзакций передачи токенов между пользователями.

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

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

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

    Вам стоит поизучать курс баз данных, чтобы понимать какие неочевидные для новичков проблемы кроются в бизнес логике, когда ваша система постянно осуществляет одновременные переводы между пользователями. Там целый мир и CAP-теорема. Почитайте.

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

    trapwalker
    @trapwalker
    Программист, энтузиаст
    SELECT * 
    FROM articles a
    WHERE NOT EXISTS(SELECT * FROM tag2article ta WHERE ta.tag_id = 5 AND ta.article_id = a.id)
    Ответ написан
    Комментировать
  • Почему SQL запрос ничего не возвращает?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Потому, что last_time вы извлекаете без учета client_id, а потом добавляете это ограничение и, очевидно, по этому пользователю не было ни одной записи за эти секунды, а были по другому пользователю.

    но говнокод тот еще, конечно. Не удивительно, что для вас не прозрачна причина такого поведения кода, когда он так плохо написан.

    Короче, в первом зпросе забыли добавить "WHERE client_id =..."
    Ответ написан
  • Попадает время в промежуток между двумя time или нет?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Да как-как? как обычно
    localtime >= open_time and localtime < close_time
    UPD:
    Не сразу понял в чем проблема.
    Речь, похоже, о заведениях типа ночных клубов, которые работают, скажем, с 22:00 до 05:00 и нужно понять попадает ли какое-то время в этот интервал, если два времени оказались по разную сторону от полуночи.
    Тут спасёт сложное условие:
    SELECT *
    FROM shop
    WHERE
    (open_time <= close_time) AND (localtime BETWEEN open_time AND close_time) OR
    (open_time > close_time) AND NOT (localtime BETWEEN close_time AND open_time)

    Это замечательно работает, если ваши магазины работают каждый день по одному графику, а если нет, то нужно строить расписание на неделю. Это доволно быстро работает, если хранить расписание в отдельной таблице в виде нтервалов работы в секундах от начала недели и ссылку (многие к одному) на учреждение.

    UPD2: Перенесу, пожалуй, сюда и пример с недельным расписанием из своего комментария.

    Интереснее когда график работы магазина разный в выходные и будни, причем, скажем, на выходных магазин открыт в полночь.
    Ну, к примеру, пн-пт - 10:00-23:00 а сб-вс - 10:00-01:00.
    Тут вообще интересно. Фактически магазин не работает в суботу с полуночи до часу ночи, но работает в понедельник с полуночи до часу ночи.
    В таких случаях расписание лучше задавать набором интервалов в часах, минутах или, обычно, в секундах от полуночи понедельника.
    В часах проще показывать на примере.
    0-1, 10-23 - понедельник
    34-47 - вторник
    и т.д.
    По-хорошему должен быть специальный бинарный тип данных, способный хранить такие интервалы эффективно и индексировать их.
    Очевидно. что для выше изложенного графика таких интервалов надо около 7+2 - по одному основному на каждый день, час после полуночи понедельника, и час после полуночи воскресенья.
    Итого 9 интервалов на магазин, если без перерывов. С обеденными перерывами будет 16 интервалов на магазин. В любом случае не критично. Просто нужно задавать реальное расписание магазина в формализованной форме (какой-то формулой) прямо в записи об этом магазине, а в таблицу с интервалами просто кэшировать развернутое расписание при апдейте формулы.
    У нас точно также интервалами с кэшированием в отдельной таблице было устроено расписание ВУЗа и всё работало мгновенно.
    Ответ написан
  • Как упростить SQL запрос?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Что-то у меня дежавю. Недавно вы с похожим вопросом сюда приходили.
    Не задания ли это для какого-нибудь теста?
    Да и вам намекали, что отвечать на такие вопросы удобнее, если вы не вот эту хрень рисуете в описании таблиц, а sql-дамп метаданных приводите. Там видно и ключи, и ссылки, и индексы. Да и выполнить такой SQL для эксперимента можно мгновенно. А вы игнорируете рекомендации.

    Такого рода сортировки по сложным сложных джойнам и на довольно больших объёмах быстро работать не будут. Такие вещи решают денормализацией.
    Можно сделать отдельную аггрегированную таблицу, которая будет 1к1 джойниться к вашей тблице продуктов и предоствлять уже посчитанные данные.

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

    trapwalker
    @trapwalker
    Программист, энтузиаст
    SELECT  
        p.*, 
        (SELECT COUNT(op.count) FROM orders_products op WHERE op.product_id = p.id) AS countorders
    FROM    products p
    ORDER BY p.id ASC
    LIMIT 25

    Нужно убедиться, что на op.product_id есть индекс, а лучше foreign key, чтобы еще и целостность данных соблюдалась автоматически.
    В таком виде и с таким ограничением при наличии упомянутого индекса запрос должен занимать миллисекунды
    Ответ написан
    Комментировать
  • Как выбрать 3 записи с максимальным значение PostgreSQL?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Отсортировать и указать лимит выдачи. Буквально. А в чем вопрос? Что у вас не получилось?
    Ответ написан
    7 комментариев
  • Как слить массивы объединив дубликаты пар ключ-значение?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Делайте group by по нужным полям, а остальные агрегируйте с помощью group_concat.
    Ответ написан
    Комментировать
  • Почему запрос SQL возвращает пустоту?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    У вас максимальная модель выбирается среди всех продуктов: select max(model) from product
    и это может оказаться не принтер. А потом вы ищете принтер с именно такой моделью. Видимо такого нет.
    Ответ написан
    2 комментария
  • Как выбрать активную цену и предыдущую?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Ну так а в чем у вас проблема-то? Вы в принципе не знаете как запрос писать и это задание такое?
    Если так, то данный ресурс не для этого.
    Если у вас конкретный вопрос, то заайте его конкретно. Что именно у вас не получется?
    Не ясно как сформулировать рамочные условия с интервалами, пересекающими конкретную дату?
    Не понятно как сгруппировать интервалы по товарам?
    Не знаете про coalesce?
    Запутались с граничными точками интервалов?
    В чем проблема?
    Ответ написан
  • Почему при объеденении второй запрос отрабатывает некорректно?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Вы не правильно понимаете для чего и как предназначен union.
    Судя по всему вы хотели добиться чего-то такого:
    SELECT
        c.id,
        Count(s.email) as kol1,
        Count(cd.email) as kol2,
        Count(s.email) + Count(cd.email) as summa
    From 
        campaigns c
        Left Join subscribers s on 
            c.id = s.campaigns_id
            And s.created_on between '2020-10-15' and '2020-11-01'
        Left Join subscribers_deleted cd on 
            c.id = cd.campaigns_id
            And cd.created_on between '2020-10-15' and '2020-11-01'
    group by c.id

    Но я бы делал так:
    SELECT
        c.id,
        (SELECT Count(s.email) FROM subscribers s WHERE 
            c.id = s.campaigns_id And s.created_on between '2020-10-15' and '2020-11-01'
        ) as kol1,
        (SELECT Count(cd.email) FROM subscribers_deleted cd WHERE
            c.id = cd.campaigns_id And cd.created_on between '2020-10-15' and '2020-11-01'
        ) as kol2
    From campaigns c

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

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

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Уберите из блока SELECT всё, кроме имени девушки.
    Если у них полигамные отношения бывают, то можно SELECT DISTINCT сделать, чтобы полигамные девушки не дублировались.
    Ответ написан
    Комментировать
  • Как решить задачу sql?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    SELECT
      e.name, SUM(t.hours)
    FROM 
      employees e
        JOIN time_reports t ON t.employee_id = e.id
    GROUP BY e.id, e.name
    ORDER BY 2 DESC
    LIMIT 3
    Ответ написан
  • Запрос в MySQL. Есть идея?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    например так:
    SELECT t.*
    FROM my_table t
    WHERE NOT EXISTS(
      SELECT null FROM my_table t2 WHERE t2.link_id = t.link_id and t2.flag=0
    )

    Можно и с джойном:
    WITH tt AS(SELECT DISTINCT link_id WHERE flag = 0)
    SELECT t1.*
    FROM
        my_table t1
        LEFT JOIN tt t2 ON t2.link_id = t.1link_id
    WHERE t2.link_id is None
    Ответ написан
    3 комментария
  • Как лучше посчитать записи в базе?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    SELECT type, count(*)
    FROM table_name
    GROUP BY type
    Ответ написан
    3 комментария
  • Как правильно написать SQl запрос?

    trapwalker
    @trapwalker
    Программист, энтузиаст
    Вам нужно не группировку, а сортировку и оконную функцию.
    Но вы же не удосужились написать о какой БД речь, как вам помогать?

    На файрбёрде я уже не помню как такое делать. Тем более на современном. Давно не трогал.
    Хранимку бы по-быстрому запилил и сделал в цикле по отсортированному селекту проверку на равенство ФИО с предыдущим. Если равно, то обнулял бы фио
    Ответ написан