Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Получить записи, где год находится между двух дат, или без одной из дат.  [new]
viktor zelenin
Member

Откуда:
Сообщений: 185
Скажите пожалуйста. как получить записи, где год находится в диапазоне между begindate и enddate. Проблема в том, что begindate и enddate не обязательные поля. Т.е. если в записи не указана дата в enddate, то это означает, по настоящее время.

таблица:
declare @t as table(id int, begindate smalldatetime, enddate smalldatetime)
insert into @t(id,begindate,enddate) 
select 1,'20010101','20090101' union all 
select 2,'20080515',NULL union all 
select 3,NULL,'20090909'

запрос:
select * from @t where '2007' between begindate and enddate;
запрос должен вернуть записи 1 и 3, т.к. 2007 год входит в диапазон 20010101-20090909(первая запись), и от 0-20090909(третья запись)

если запросить '20090505', то нужно чтоб вернулись записи 2 и 3, так как этот период входит в диапазон 20080515-по н.в.(вторая запись), и в третью запись диапазон с 0 по 20090909

как можно решить этот вопрос?
9 авг 09, 02:45    [7514830]     Ответить | Цитировать Сообщить модератору
 Re: Получить записи, где год находится между двух дат, или без одной из дат.  [new]
Гавриленко Сергей Алексеевич
Member

Откуда: Moscow
Сообщений: 36801
('2007' between begindate and enddate)
or (begindate  is null and '2007' < enddate)
or (enddate is null and '2007' > begindate )
9 авг 09, 04:41    [7514858]     Ответить | Цитировать Сообщить модератору
 Re: Получить записи, где год находится между двух дат, или без одной из дат.  [new]
viktor zelenin
Member

Откуда:
Сообщений: 185
чёрт побери, как оказалось, запрос не совсем верен,
не возвращается первая запись почему-то в таком варианте:
declare @t as table(id int, begindate smalldatetime, enddate smalldatetime)
insert into @t(id,begindate,enddate) 
select 1,'20080901',NULL union all 
select 2,'20070501',NULL 

запрос:
SELECT DISTINCT *
FROM @t
WHERE ('2008' BETWEEN YEAR(begindate) AND YEAR(enddate) OR (begindate  IS NULL AND '2008' < YEAR(enddate)) 
OR (enddate is null and '2008' > YEAR(begindate)))

возвращает только вторую запись! но, ведь первая запись тоже содержит '2008' год.
как исправить запрос, чтобы получить и первую запись?
15 авг 09, 23:01    [7542912]     Ответить | Цитировать Сообщить модератору
 Re: Получить записи, где год находится между двух дат, или без одной из дат.  [new]
iljy
Member

Откуда:
Сообщений: 8711
viktor zelenin,

и что вас смущает? по вашему условие
enddate is null and '2008' > YEAR(begindate)

должно выполняться для begindate = '20080901'?
16 авг 09, 00:17    [7543043]     Ответить | Цитировать Сообщить модератору
 Re: Получить записи, где год находится между двух дат, или без одной из дат.  [new]
viktor zelenin
Member

Откуда:
Сообщений: 185
iljy, нет, я бы хотел чтобы условие выполнялось для
'2008' BETWEEN YEAR(begindate) AND YEAR(enddate)
16 авг 09, 00:35    [7543063]     Ответить | Цитировать Сообщить модератору
 Re: Получить записи, где год находится между двух дат, или без одной из дат.  [new]
Roman S. Golubin
Member

Откуда: 140002
Сообщений: 11541
Hint: Что бы не мучаться с IS NULL, вместо NULL используй максимально возможную дату для даты окончания периода и минимально возможную - для даты начала периода.
16 авг 09, 00:37    [7543067]     Ответить | Цитировать Сообщить модератору
 Re: Получить записи, где год находится между двух дат, или без одной из дат.  [new]
Roman S. Golubin
Member

Откуда: 140002
Сообщений: 11541
Roman S. Golubin
Hint: Что бы не мучаться с IS NULL, вместо NULL используй максимально возможную дату для даты окончания периода и минимально возможную - для даты начала периода.


То есть, 19000101 и 20790706.

И тогда поиск по году будет примерно такой:

where '20081231' >= begindate and '20080101' <= enddate
16 авг 09, 00:43    [7543074]     Ответить | Цитировать Сообщить модератору
 Re: Получить записи, где год находится между двух дат, или без одной из дат.  [new]
viktor zelenin
Member

Откуда:
Сообщений: 185
Roman S. Golubin, это где вы предлагаете использовать максимальную дату?
в таблице?
тогда получится, что, если я забил месяц назад максимальную дату, и мне сейчас надо получить процесы которые не завершёны на текущий запрос, то я таких процессов не получу.
16 авг 09, 00:44    [7543076]     Ответить | Цитировать Сообщить модератору
 Re: Получить записи, где год находится между двух дат, или без одной из дат.  [new]
Roman S. Golubin
Member

Откуда: 140002
Сообщений: 11541
viktor zelenin
Roman S. Golubin, это где вы предлагаете использовать максимальную дату?
в таблице?
тогда получится, что, если я забил месяц назад максимальную дату, и мне сейчас надо получить процесы которые не завершёны на текущий запрос, то я таких процессов не получу.

Почему не получите? Вместо where enddate is null надо будет искать where enddate = '20790706'.
16 авг 09, 00:51    [7543081]     Ответить | Цитировать Сообщить модератору
 Re: Получить записи, где год находится между двух дат, или без одной из дат.  [new]
viktor zelenin
Member

Откуда:
Сообщений: 185
хорошо. спасибо за хинт. покумекаю, может быть, он может что-то хорошего принести.

а что по поводу битвина? как 1-ую запись-то вернуть?
16 авг 09, 01:00    [7543087]     Ответить | Цитировать Сообщить модератору
 Re: Получить записи, где год находится между двух дат, или без одной из дат.  [new]
Roman S. Golubin
Member

Откуда: 140002
Сообщений: 11541
viktor zelenin
хорошо. спасибо за хинт. покумекаю, может быть, он может что-то хорошего принести.

С датой слегка ошибся. Для smalldatetime это 20790606, а не 20790706, но сути это не меняет.
16 авг 09, 01:03    [7543092]     Ответить | Цитировать Сообщить модератору
 Re: Получить записи, где год находится между двух дат, или без одной из дат.  [new]
Roman S. Golubin
Member

Откуда: 140002
Сообщений: 11541
viktor zelenin
а что по поводу битвина? как 1-ую запись-то вернуть?

if object_id('tempdb..#t') is not null drop table #t
go
create table #t(id int, begindate smalldatetime, enddate smalldatetime)
go
insert #t (id,begindate,enddate) 
select 1,'20080901',NULL union all 
select 2,'20070501',NULL 
go
SELECT *
FROM #t
WHERE (begindate < '20090101' AND enddate >= '20080101')
union all
SELECT *
FROM #t
WHERE (begindate is null AND enddate >= '20080101')
union all
SELECT *
FROM #t
WHERE (begindate < '20090101' AND enddate is null)
16 авг 09, 01:21    [7543102]     Ответить | Цитировать Сообщить модератору
 Re: Получить записи, где год находится между двух дат, или без одной из дат.  [new]
Roman S. Golubin
Member

Откуда: 140002
Сообщений: 11541
А с датами, как я говорил выше, будет так:

if object_id('tempdb..#t') is not null drop table #t
go
create table #t(id int not null primary key identity, begindate datetime not null, enddate datetime not null)
go
create index ix_t1 on #t (begindate,enddate)
go
declare @min_date datetime, @max_date datetime
select @min_date = '17530101', @max_date = '99991231'
insert #t (begindate,enddate) 
select '20080901',@max_date union all 
select '20070501',@max_date union all
select @min_date, @max_date union all
select '20050101', '20071231'
go
declare @min_date datetime, @max_date datetime
select @min_date = '17530101', @max_date = '99991231'
SELECT id,nullif(begindate,@min_date),nullif(enddate,@max_date)
FROM #t
WHERE (begindate < '20090101' AND enddate >= '20080101')
16 авг 09, 01:49    [7543117]     Ответить | Цитировать Сообщить модератору
 Re: Получить записи, где год находится между двух дат, или без одной из дат.  [new]
viktor zelenin
Member

Откуда:
Сообщений: 185
о, большое спасибо, сработало,
однако, не могли бы подсказать, как прибавить к году один год?
@YEAR + 1 так не выходит:
DECLARE @YEAR char(4)

SET @YEAR = '2008'

SELECT DISTINCT m.id_models, m.model_name 
FROM models AS m INNER JOIN 
submodels AS sm ON m.id_models = sm.id_models 
WHERE (m.id_vendors = 100) AND (sm.begin_date < @YEAR + 1 AND sm.end_date >= @YEAR)
UNION ALL
SELECT DISTINCT m.id_models, m.model_name 
FROM models AS m INNER JOIN 
submodels AS sm ON m.id_models = sm.id_models
WHERE (m.id_vendors = 100) AND (sm.begin_date is null AND sm.end_date >= @YEAR)
union all
SELECT DISTINCT m.id_models, m.model_name 
FROM models AS m INNER JOIN 
submodels AS sm ON m.id_models = sm.id_models
WHERE (m.id_vendors = 100) AND (sm.begin_date < @YEAR + 1 AND sm.end_date is null)

и может можно сократить запрос? может убрать юнионы, заменив их на AND/OR в условии? или это влияет на "тяжесть" для сервера?
16 авг 09, 02:36    [7543142]     Ответить | Цитировать Сообщить модератору
 Re: Получить записи, где год находится между двух дат, или без одной из дат.  [new]
Roman S. Golubin
Member

Откуда: 140002
Сообщений: 11541
viktor zelenin
может убрать юнионы, заменив их на AND/OR в условии? или это влияет на "тяжесть" для сервера?

Там, на самом деле еще одного union'a не хватает - когда обе даты is null. А с OR'ами скан таблицы будет. Если записей совсем мало ожидается, то дерзайте:

SELECT id,begindate,enddate
FROM #t
WHERE ((begindate < '20090101' OR begindate is null) AND (enddate >= '20080101' OR enddate is null))

viktor zelenin
как прибавить к году один год?


DATEADD
16 авг 09, 02:52    [7543146]     Ответить | Цитировать Сообщить модератору
 Re: Получить записи, где год находится между двух дат, или без одной из дат.  [new]
iljy
Member

Откуда:
Сообщений: 8711
viktor zelenin
iljy, нет, я бы хотел чтобы условие выполнялось для
'2008' BETWEEN YEAR(begindate) AND YEAR(enddate)


тогда сделайте так:
2008 between isnull(YEAR(begindate), 1900) and isnull(YEAR(enddate), 2076)


но такое построение условия не дает серверу использовать индексы если они на этих колонках есть.
viktor zelenin

однако, не могли бы подсказать, как прибавить к году один год?
@YEAR + 1 так не выходит

сделайте @YEAR типа int
16 авг 09, 11:01    [7543307]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить