SQL Server 2008 выбирает данные только между месяцем и годом

#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 — на моем сервере a 10/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