#sql #sql-server-2008 #select #between #datepart
#sql #sql-server-2008 #выберите #между #datepart
Вопрос:
Я хотел бы выбрать данные между двумя датами, без дня
Пример ввода:
начальный месяц: 9, начальный год: 2011
, конечный месяц: 3, конечный год: 2012
Я думаю, что есть два способа сделать это.
Первый — преобразовать начальный месяц и начальный год в дату like 2011-09-01
и преобразовать последнюю дату в 2012-03-31
, но для этого требуется вычисление последнего дня конечного месяца. Получив эти даты, мы можем использовать функцию BEETWEN для предложения WHERE (но надежна ли функция CONVERT?)
Второе решение — использовать DATEPART
функцию, как в следующем коде:
Я пытаюсь объяснить: если конечный год равен начальному году, то месяц должен находиться между начальным и конечным месяцами; иначе, если последние месяцы больше начальных лет, если они отличаются от начального и последнего года, я беру все промежуточное; иначе, если последний год, месяцдолжно быть меньше или равно последнему месяцу, если начальный год, месяц должен быть больше или равен последнему месяцу
Можете ли вы помочь мне сделать это наилучшим образом? Правильно ли решение, которое я принял?
declare @IndDebitoCredito bit,@ProgTributo int,@mi as integer,@ai as integer,@mf as integer,@af as integer,@IDAnagrafica varchar(5)
select @mi = 01,@ai = 2011,@mf = 12,@af = 2011,@IDAnagrafica = 'DELEL',@IndDebitoCredito = 1
select distinct rrd.IDTributo
from TBWH_Delega d
--inner join TBWH_SezioneDelega sd on d.IDDelega = sd.IDDelega
inner join TBWH_Rigo rd on rd.IDDelega = d.IDDelega
inner join TBWH_RataRigo rrd on rrd.IDRigo = rd.IDRigo
where
(
DATEPART(MM,d.DataDelega)<=@mf and
DATEPART(MM,d.DataDelega)>=@mi and
DATEPART(YYYY,d.DataDelega)=@ai and
@af = @ai
)
OR
(
--anno finale magg. anno iniziale
@af > @ai AND
(
( -- delega nell'intervallo
DATEPART(YYYY,d.DataDelega)<@af AND
DATEPART(YYYY,d.DataDelega)>@ai
-- DATEPART(MM,d.DataDelega)>=@mi
)
OR
( -- delega limite destro
DATEPART(YYYY,d.DataDelega)=@af AND
DATEPART(MM,d.DataDelega)<=@mf
)
OR
( -- delega limite sinistro
DATEPART(YYYY,d.DataDelega)=@ai AND
DATEPART(MM,d.DataDelega)>=@mi
)
)
)
Вперед
Комментарии:
1. Сначала я думал, что последний ШАГ был за нами: «Вот в чем вопрос. Теперь .. ВПЕРЕД!» 🙂
Ответ №1:
Ваше первое решение почти готово, но оно сложнее, чем нужно, и все равно не будет работать. При этом будут пропущены все строки с последнего дня конечного месяца.
Вы можете добавить один месяц к end month
, а затем использовать BETWEEN первого числа каждого месяца. например.
start month: 9 , start year: 2011
end month: 3, end year: 2012
BETWEEN '2011-09-01' AND '2012-04-01'
или, как указывает JNK, это будет лучше:
DataDelega >= '2011-09-01' AND DataDelega < '2012-04-01'
Вам нужно будет добавить некоторую логику, чтобы иметь дело с end month
декабрем, но это выглядит как самый простой способ сделать это.
Комментарии:
1. Исключение
BETWEEN
включено, поэтому оно будет включать4/1/2012
.2. Вы правы — он будет включать любые строки из
'2012-04-01 00:00:000'
. Не видя рассматриваемых данных, я не знаю, является ли это проблемой или нет.3. В вопросе он говорит, что хочет включать данные только до конца последнего месяца.
Ответ №2:
Вы слишком усложняете это. Вам действительно нужно только два сравнения:
- Являются ли месяц и год после или равными начальному значению?
- Месяц и год предшествуют или равны конечному значению?
Попробуйте:
SELECT *
FROM MyTable
WHERE Datefield BETWEEN
CAST(@mi as varchar) '/1/' CAST(@ai as varchar)
-- first of first month
AND
DATEADD(DAY, -1, (DATEADD(Month, 1, (CAST(@mf as varchar) '/1/' CAST(@af as varchar)))))
-- Last day or final month
Комментарии:
1. Я бы рекомендовал использовать стандартный формат даты ISO-8601:
YYYYMMDD
поскольку это не зависит от каких-либо языковых / региональных настроек в SQL Server — на моем сервере a10/1/2011
будет интерпретироваться, например, как 10 января 2011 года…..2. @marc_s — хороший момент, это будет зависеть от региона, как написано
3. Из-за региональных настроек я не могу это проверить, но будут ли в него включены строки за последний день последнего месяца? Да, если
DateField
это дата, а не дата-время. Или если часть времени всегда установлена на полночь.
Ответ №3:
SELECT *
FROM Table
WHERE DateField
BETWEEN CONVERT(DATE, CONVERT(CHAR(4), @ai) RIGHT('00' CONVERT(VARCHAR(2), @mi), 2) '01', 112)
AND DATEADD(DD, -1, DATEADD(MM, 1, CONVERT(DATE, CONVERT(CHAR(4), @af) RIGHT('00' CONVERT(VARCHAR(2), @mf), 2) '01', 112)))
Избегайте использования выражений в столбцах DateField, так как это делает запрос невозможным.
Ответ №4:
Я бы использовал:
WHERE DateToCheck >= --- first day of StartMonth
DATEADD( mm, @StartMonth-1,
DATEADD( yy, @StartYear-2000, '2000-01-01')
)
AND DateToCheck < --- first day of next month (after EndMonth)
DATEADD( mm, @EndMonth,
DATEADD( yy, @EndYear-2000, '2000-01-01')
)
Ответ №5:
DECLARE @mi INT
, @ai INT
, @mf INT
, @af INT
SELECT @mi = 01
, @ai = 2011
, @mf = 12
, @af = 2011
--local variables to hold dates
DECLARE @i DATETIME
, @f DATETIME
--build strings to represent dates in YYYYMMDD format
--add a month to the @f date
SELECT @i = CONVERT(VARCHAR(4), @ai) RIGHT('0' CONVERT(VARCHAR(2), @mi),
2) '01'
, @f = DATEADD(month, 1,
CONVERT(VARCHAR(4), @af) RIGHT('0'
CONVERT(VARCHAR(2), @mf),
2) '01')
--select data where date >= @i, and < @f
SELECT *
FROM MyTable
WHERE DateField >= @i
AND DateField < @f