1

У меня есть столбец INT в моей таблице. Этот столбец сохраняет дату в специальном формате. Я пытаюсь преобразовать этот столбец в тип DATE.Преобразование числа на дату в SQL Server с исключением в конце месяца

Например, мы сохраняем '2016-03-14' как 20160314.

Исключение составляет, в течение последнего месяца, мы не храним день. Итак, для '2016-03-31' мы храним 201603, и я должен рассмотреть, является ли число less than 999999 или нет, чтобы указать число, которое представляет собой конец месяца или другие дни в месяце.

До сих пор, у меня есть 2 запросов для достижения этой задачи:

Запрос 1:

Это все математические формулы.

declare @k int = 20160321 
--declare @k int = 201603 
select 
    IIF(@k < 999999 
     , EOMONTH(DATEFROMPARTS(@k /100, @k % 100, 1), 0) 
     , DATEFROMPARTS(@k /10000, (@k/100) % 100, @k % 100) 
    ) 

Запрос 2: Это один использует манипуляции со строками.

declare @k int = 20160321 
--declare @k int = 201603 

select 
    IIF(@k < 999999 
     , EOMONTH(cast(LEFT(@k, 4) + '-' + RIGHT(@k, 2) + '-01' as date), 0) 
     , cast(LEFT(@k, 4) + '-' + RIGHT(LEFT(@k, 6), 2) + '-' + RIGHT(@k, 2) as date) 
    ) AS DateColumn 

мне нужно сделать формулы преобразования в WHERE п. Что-то вроде:

SELECT K, Dt, Name -- and more fields 
FROM tbl 
WHERE IIF(K < 999999 
      , EOMONTH(DATEFROMPARTS(K /100, K % 100, 1), 0) 
      , DATEFROMPARTS(K /10000, (K/100) % 100, K % 100) 
     ) < GetDate() 

И performance is important

Вопрос: Есть ли лучший способ сделать это? Возможно, что SQL Server может использовать кластерный индекс, который у меня есть в столбце K.

+0

@ hvd Он не является. Он использует функцию EOMONTH(), которая возвращает дату последнего дня месяца. –

+0

@hvd - я думаю, что он получил это, называя функцию 'EOMONTH' –

+0

Да, ребята. могут быть некоторые другие способы, очень похожие на то, что я сделал. случай зверя будет делать это, поэтому SQL Server может использовать кластерный индекс для столбца K. Я добавляю это к вопросу. – FLICKER

ответ

1

Я бы ожидал, что Query 1 будет работать лучше, но вам нужно будет проверить его, чтобы быть уверенным. Я понятия не имею, что такое производительность datefromparts() и datetimefromparts() есть. Они относительно новые, поэтому меня это не шокировало бы, если бы они были магически ужасны без уважительной причины. Вы сравниваете производительность строковых манипуляций и литье типов по сравнению с производительностью арифметики и типом. Я предполагаю, что это в основном стирка, но эта арифметика, вероятно, быстрее.

Возможные варианты решения для решения: a) Добавьте столбец datetime в таблицу. b) Добавьте вычисленный столбец в таблицу. Если вы сделаете столбец PERSISTED, вы даже можете создать на нем индекс. c) Создайте представление (индексированное представление, если вы можете перепрыгнуть через обручи требований). d) Создайте новую таблицу с полем datetime и обновите ее.

Оба (a) и (d) дублируют данные, поэтому они не так велики, как только они появляются.

Я всегда находил вычисляемые столбцы немного грубыми, но они работают достаточно хорошо. Если вы создадите представление, вам нужно будет INNER JOIN его обратно, чтобы использовать его, но в большинстве систем JOINS очень быстрые.

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


Вы могли бы попробовать этот запрос:

SELECT CASE 
     WHEN @K < 999999 THEN EOMONTH(TRY_CONVERT(date, CAST(@K * 100 + 1 AS VARCHAR(10)))) 
     ELSE TRY_CONVERT(date, CAST(@K AS VARCHAR(10))) 
    END AS K_Date 

Причиной этого может работать в том, что YYYYMMDD является одним из форматов даты ISO. Я бы попробовал TRY_CONVERT() до CONVERT(), потому что механизм запроса может решить оценить все CONVERT, не глядя на CASE условные ошибки и ошибки броска.

+0

Спасибо @Bacon. Значит, вы не знаете, какая другая формула/запрос отличается от того, что я реализовал? – FLICKER

+0

@FLICKER О, право. См. Мое обновление. –

+0

Я попробую это и посмотрю, как он будет работать. Я также исправил ошибку синтаксиса в вашем запросе – FLICKER