Запросы по месяцам и дням - PullRequest
0 голосов
/ 06 декабря 2018

Моя база данных журналов доступа хранит время как эпоху и извлекает год, месяц и день как целые числа.Кроме того, разделение базы данных основано на извлеченном Y / m / d, и у меня есть 35-дневное удержание.

Если я выполню этот запрос:

select * 
from mydb 
where year in (2017, 2018) 
  and month in (12, 1) 
  and day in (31, 1) 
  • 29 января 2018 года я получу данные за 31.12.2017 и 01.01.2017.
  • 5 января 2018 года я получу данные за 01.12.2017, 31.12.2017 и 01.01.2017 (нежелательно)

Iтакже осознайте, что я могу сделать что-то вроде этого:

select * 
from mydb 
where (year = 2017 and month = 12 and day = 31) 
   or (year = 2018 and month = 1 and day = 1)

Но то, что я действительно ищу, так это: хороший способ написать запрос, в котором я указываю номер месяца и дня года в качестве начала, а затемчетвертое значение (количество дней +), а затем получить все данные за 31.12.2017 + 5 дней, например.

Есть ли в SQL собственный способ сделать это?У меня огромный набор данных, и если я не укажу дни и вынужден полагаться на эпоху, запрос будет длиться вечно.Я также не имею никакого влияния на конфигурацию разметки.

1 Ответ

0 голосов
/ 06 декабря 2018

С Impala в качестве диалекта dbms и SQL вы сможете использовать обычные табличные выражения, но не рекурсию.Кроме того, могут быть проблемы с вставкой параметров.

Ниже приведено непроверенное предложение, которое потребует от вас найти некоторые варианты функций.Сначала он генерирует набор строк с целым числом от 0 до 999 (в примере).При необходимости достаточно легко увеличить количество строк.Из этих строк можно добавить количество дней к литералу отметки времени, используя date_add(timestamp startdate, int days/interval expression), а затем с помощью year(timestamp date) и month(timestamp date) и day(timestamp date) см. Функции даты и времени для создания столбцов, необходимых дляв соответствии с вашими данными.

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

Приведенный ниже код был создан с использованием T-SQL (SQL Server), и его можно протестировать здесь .

-- produce a set of integers, adjust to suit needed number of these
;WITH
  cteDigits AS (
      SELECT 0 AS digit UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL
      SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
      )
, cteTally AS (
      SELECT 
              d1s.digit 
            + d10s.digit * 10
            + d100s.digit * 100  /* add more like this as needed */
            -- + d1000s.digit * 1000  /* add more like this as needed */
            AS num
      FROM cteDigits d1s
      CROSS JOIN cteDigits d10s
      CROSS JOIN cteDigits d100s /* add more like this as needed */
      -- CROSS JOIN cteDigits d1000s /* add more like this as needed */
      )
, DateRange AS (
    select 
          num
        , dateadd(day,num,'20181227')        dt
        , year(dateadd(day,num,'20181227'))  yr
        , month(dateadd(day,num,'20181227')) mn
        , day(dateadd(day,num,'20181227'))   dy
    from cteTally
    where num < 10
    )
select
*
from DateRange

I думаю это эквиваленты Impala для вызовов функций, использованных выше:

, DateRange AS (
    select 
          num
        ,        date_add(to_timestamp('20181227','yyyyMMdd'),num)    dt
        ,  year( date_add(to_timestamp('20181227','yyyyMMdd'),num) )  yr
        , month( date_add(to_timestamp('20181227','yyyyMMdd'),num) )  mn
        ,   day( date_add(to_timestamp('20181227','yyyyMMdd'),num) )  dy
    from cteTally
    where num < 10

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

select * from mydb t
inner join DateRange on t.year = DateRange.yr and t.month = DateRange.mn and t.day = DateRange.dy

оригинальное сообщение

Хорошо, если не знать, какую базу данных предложить решениядля, вот предложение с использованием SQL Server:

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

--Sql Server 2014 Express Edition
--https://rextester.com/l/sql_server_online_compiler

declare @yr as integer = 2018
declare @mn as integer = 12
declare @dy as integer = 27
declare @du as integer = 10

;with CTE as (
    select
           datefromparts(@yr, @mn, @dy) as dt
         , @yr as yr
         , @mn as mn
         , @dy as dy

    union all

    select
           dateadd(dd,1,cte.dt)
         , datepart(year,dateadd(dd,1,cte.dt)) 
         , datepart(month,dateadd(dd,1,cte.dt)) 
         , datepart(day,dateadd(dd,1,cte.dt)) 
    from cte
    where cte.dt < dateadd(dd,@du-1,datefromparts(@yr, @mn, @dy))
    )
select
*
from cte

Это приводит к следующему результату:

+----+---------------------+------+----+----+
|    |         dt          |  yr  | mn | dy |
+----+---------------------+------+----+----+
|  1 | 27.12.2018 00:00:00 | 2018 | 12 | 27 |
|  2 | 28.12.2018 00:00:00 | 2018 | 12 | 28 |
|  3 | 29.12.2018 00:00:00 | 2018 | 12 | 29 |
|  4 | 30.12.2018 00:00:00 | 2018 | 12 | 30 |
|  5 | 31.12.2018 00:00:00 | 2018 | 12 | 31 |
|  6 | 01.01.2019 00:00:00 | 2019 |  1 |  1 |
|  7 | 02.01.2019 00:00:00 | 2019 |  1 |  2 |
|  8 | 03.01.2019 00:00:00 | 2019 |  1 |  3 |
|  9 | 04.01.2019 00:00:00 | 2019 |  1 |  4 |
| 10 | 05.01.2019 00:00:00 | 2019 |  1 |  5 |
+----+---------------------+------+----+----+

и:

select * from mydb t
inner join cte on t.year = cte.yr and t.month = cte.mn and t.day = cte.dy

Вместо рекурсивного выражения общей таблицы вместо него можно использовать таблицу целых чисел (или использоватьнабор объединенных запросов на выборку для генерации набора целых чисел) - часто называемый таблицей подсчета.Выбор одного метода будет зависеть от типа и версии dbms.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...