Хобрук: Ваш путь к мастерству в программировании

Получите количество записей, создаваемых каждую неделю в SQL

У меня есть таблица Вопросы. Как я могу подсчитать все вопросы, заданные за неделю?

В более общем плане, как я могу сгруппировать записи по неделям, в которые они были созданы?

Questions
id     created_at            title            
----------------------------------------------------
1      2014-12-31 09:43:42   "Add things"
2      2013-11-23 02:98:55   "How do I ruby?"
3      2015-01-15 15:11:19   "How do I python?"
...

Я использую SQLLite, но ответы PG тоже подходят.

Или, если у вас есть ответ, используя Rails ActiveRecord, это замечательно, но не обязательно.

Я пытался использовать DATEPART (), но пока ничего не добился: http://msdn.microsoft.com/en-us/library/ms174420.aspx


  • Укажите неделю. Вы имеете в виду определение ISO 8601 (пн - вс)? И вы хотите объединить недели нескольких лет вместе? Первая неделя года содержит 4 января (ISO 8601)? DATEPART(), а также ваша ссылка относятся к tSQL, который принадлежит SQL Server. Не применимо ни к SQLite, ни к Postgres. 04.01.2015

Ответы:


1

В postgreSQL это очень просто:

SELECT id, created_at, title, date_trunc('week', created_at) created_week
  FROM Questions

Если вы хотите получать количество вопросов в неделю, просто сделайте следующее:

SELECT date_trunc('week', created_at) created_week, COUNT(*) weekly_cnt
  FROM Questions
 GROUP BY date_trunc('week', created_at)

Надеюсь это поможет. Обратите внимание, что date_trunc() вернет дату, а не число (т.е. он не вернет порядковый номер недели в году).

Обновление:

Кроме того, если вы хотите выполнить и то, и другое в одном запросе, вы можете сделать это следующим образом:

SELECT id, created_at, title, date_trunc('week', created_at) created_week
     , COUNT(*) OVER ( PARTITION BY date_trunc('week', created_at) ) weekly_cnt
  FROM Questions

В приведенном выше запросе я использую COUNT(*) как оконную функцию и разбиваю по неделям, в которые был создан вопрос.

04.01.2015

2

Если поле created_at уже проиндексировано, я просто буду искать все строки со значением created_at между X и Y. Таким образом можно использовать индекс.

Например, чтобы получить строки со значением created_at на 3-й неделе 2015 года, вы должны запустить:

select *
  from questions
 where created_at between '2015-01-11' and '2015-01-17'

Это позволит использовать индекс.

Если вы хотите указать неделю в предложении where, вы можете использовать функции date_part или extract, чтобы добавить столбец в эту таблицу, в котором будут храниться год и неделя #, а затем проиндексировать этот столбец, чтобы запросы могли использовать его. .

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

Поскольку вы упомянули, что не хотите добавлять столбец в таблицу, я бы рекомендовал добавить индекс на основе функций.

Например, если ваш ddl был:

create table questions
(
  id int,
  created_at timestamp,
  title varchar(20)
);

insert into questions values
(1, '2014-12-31 09:43:42','"Add things"'),
(2, '2013-11-23 02:48:55','"How do I ruby?"'),
(3, '2015-01-15 15:11:19','"How do I python?"');


create or replace function to_week(ts timestamp)
   returns text
   as 'select concat(extract(year from ts),extract(week from ts))'
   language sql
   immutable
   returns null on null input;

create index week_idx on questions (to_week(created_at));

Вы можете запустить:

select q.*, to_week(created_at) as week
  from questions q
 where to_week(created_at) = '20153';

И получить:

| ID |                     CREATED_AT |              TITLE |  WEEK |
|----|--------------------------------|--------------------|-------|
|  3 | January, 15 2015 15:11:19+0000 | "How do I python?" | 20153 |

(отражает третью неделю 2015 года, т.е. '20153')

Fiddle: http://sqlfiddle.com/#!15/c77cd/3/0

Аналогичным образом вы можете запустить:

select q.*,
       concat(extract(year from created_at), extract(week from created_at)) as week
  from questions q
 where concat(extract(year from created_at), extract(week from created_at)) =
       '20153';

Fiddle: http://sqlfiddle.com/#!15/18c1e/3/0

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

Если таблица большая, вам понадобится либо индекс на основе функции, либо столбец, содержащий эту неделю, которая сама индексируется.

03.01.2015

3

SQLite не имеет собственного типа datetime, как MS SQL Server, поэтому ответ может зависеть от того, как вы храните даты. Не весь T-SQL будет работать в SQLite.

Вы можете сохранить datetime как целое число, отсчитывающее секунды с 01.01.1970 12:00 AM. В неделе 604800 секунд. Таким образом, вы можете запросить выражение вроде

rawdatetime / 604800 -- iff rawdatetime is integer

Подробнее об обработке даты и времени в SQLite здесь: https://www.sqlite.org/datatype3.html

03.01.2015

4

Получите номер недели с помощью strfdate(%V) Сохраните его в БД и используйте его, чтобы определить, на какой неделе был задан вопрос.

http://apidock.com/ruby/DateTime/strftime

SQL тоже может сделать это с помощью DATE_FORMAT (datetime, '% u')

Так что используйте:

SELECT DATE_FORMAT(column,'%u') FROM Table
03.01.2015
  • Это возможно, но мне не нужно создавать какие-либо промежуточные таблицы или дополнительные столбцы для такого рода запросов. 04.01.2015
  • Новые материалы

    Получение стоковых обновлений с помощью Python
    Для начинающего финансового аналитика Введение Описание: Этот проект Python создает скрипт для получения текущих обновлений акций с финансового веб-сайта Yahoo. Для этого проекта мы..

    Это все, что вам нужно знать о Kotlin в 2022 году
    Добро пожаловать! Kotlin — это язык программирования, популярность которого, кажется, растет, его действительно можно использовать для создания чего угодно, и если вы хотите узнать о Kotlin,..

    Текстовый графический интерфейс с Lanterna на Java
    Мой опыт работы с компьютерами (и текстовыми графическими пользовательскими интерфейсами) начался еще в восьмидесятых, когда я был ребенком, на дне рождения друга. Это был «новенький» Amstrad..

    Перезарядите свой мозг: умопомрачительный потенциал мозговых компьютерных интерфейсов
    Способность читать свои мысли и управлять объектами разумом долгое время были предметом человеческого любопытства, ограниченного областью научной фантастики… то есть до сих пор? С технологией,..

    Основы C# — Нулевой оператор объединения (??)
    Оператор ?? называется null-coalescing operator . Этот оператор используется для предоставления значения по умолчанию, если значение операнда в левой части оператора равно null ...

    Сравнение номеров версий в C++ с использованием синтаксического анализа строк
    Номера версий обычно используются для обозначения развития или обновлений программного обеспечения или любого другого продукта. При работе с номерами версий в C++ может быть полезно сравнить две..

    В мир искусственного интеллекта…
    ИИ — это новое топливо в современном мире. Куда бы вы ни обратились, с кем бы вы ни разговаривали — они, как правило, упоминают об ИИ хотя бы раз в ходе разговора. ИИ гудит повсюду. У каждого..