Как сделать SQL МЕЖДУ, где дата и время хранятся отдельно как целые числа - PullRequest
2 голосов
/ 16 ноября 2009

В компании, в которой я работаю, значения даты и времени всегда сохранялись отдельно в целочисленных полях, поэтому, например, 8:30 сегодня утром будет храниться так:

  • дата 20091116 и
  • время 83000 (без начальных нулей, так как это целочисленное поле)

В то время как время, когда я набираю это время, будет храниться как это

  • дата 20091116
  • время 133740

К сожалению, если я захочу добавить BETWEEN к предложению WHERE запроса, это приведет к небольшому усложнению.

В настоящее время система, над которой я работаю, использует запрос примерно так:

declare @minDate int, @minTime int, @maxDate int, @maxTime int
select @minDate = 20091102
select @minTime = 64841
select @maxDate = 20091105
select @maxTime = 102227

SELECT *
FROM transactions
WHERE
    (
        (
            txnDate = @minDate AND 
            txnTime >= @minTime 
        ) OR 
        txnDate > @minDate
    ) AND
    (
        (
            txnDate = @maxDate AND
            txnTime <= @maxTime
        ) OR
        txnDate < @maxDate
    )

Учитывая, что я не могу изменить дизайн базы данных ...
Есть ли лучший способ сделать это?

Ответы [ 4 ]

3 голосов
/ 16 ноября 2009

Если вы сложите их вместе, как:

 cast(20091116 as bigint) * 1000000 + 183000

Вы можете сделать более простую математику. Например:

select @minDate = 20091102064841
select @maxDate = 20091105102227

select *
from (
    select cast(txnDate as bigint) * 1000000 + 
        txnTime as composite_date,
        *
    from YourTable
) sub
where composite_date between @minDate and @maxDate

Другой способ - преобразовать два поля в реальное время. Вы можете сделать это с вычисляемым столбцом:

alter table YourTable add txnDateTime as cast(
    cast(txnDate as varchar) + ' ' + 
    cast(txnTime / 10000 as varchar) + ':' +
    cast(txnTime / 100 % 100 as varchar) + ':' +
    cast(txnTime % 100 as varchar)
 as datetime)

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

2 голосов
/ 16 ноября 2009

Если вы беспокоитесь о производительности (и, следовательно, имеете индексы для txnDate и txnTime), вы должны использовать это:

SELECT * FROM transactions
WHERE (txnDate > @minDate AND txnDate < @maxDate)
   OR (txnDate = @minDate AND txnTime >= @minTime)
   OR (txnDate = @maxDate AND txnTime <= @maxTime)

В остальном, уловка Андомара с бигинтом в порядке и ясна.

1 голос
/ 16 ноября 2009

Переопределить @minDate и @ maxDate

declare @minDate bigint, @maxDate bigint
select @minDate = 20091102064841
select @maxDate = 20091105102227

Тогда, возможно, запрос можно упростить до

SELECT *
FROM transactions
WHERE ((CAST(txnDate AS bigint) * 1000000) + txnTime) BETWEEN @minDate AND @maxDate
0 голосов
/ 16 ноября 2009

Вы должны рассчитать компоненты Date и Time и создать одно значение, в котором есть DATETIME. Вы должны сделать то же самое для @variables. Затем вы делаете сравнение.

Это дает вам ряд преимуществ, таких как проверка данных, функции даты и времени, точность и т. Д.

declare @minDate int, @minTime int, @maxDate int, @maxTime int
select @minDate = 20091102
select @minTime = 64841
select @maxDate = 20091105
select @maxTime = 102227

DECLARE @MinDateTime DateTime

select @MinDateTime =
    cast (convert (varchar, @minDate / 10000) + '/' +
    convert (varchar, (@minDate % (@minDate / 10000))/100) + '/' +
    convert (varchar, (@minDate % (@minDate / 1000000))) + ' ' +
    convert (varchar, @minTime / 10000) + ':' +
    convert (varchar, (@minTime % 10000)/100) + ':' +
    convert (varchar, (@minTime  % (@minTime / 100))) as datetime)

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

...