2015-03-26 4 views
0

Мне нужно выбрать всех клиентов, у которых есть день рождения в недельный интервал, это своего рода триггер, который каждую неделю выбирает клиентов с днями рождения на этой неделе. Так вот что я сделал (я работаю в PL/SQL):Выбор исторических данных по датам за определенную неделю

select customers_id 
    from customer_table 
where to_char(cust_birth_dt,'DDD') between to_char(sysdate,'DDD') 
             and to_char(sysdate,'DDD') + 7; 

Он работает хорошо, но когда выбор клиента от високосного года, я получаю в беду из-за количества дней.

У кого-нибудь есть идея, которая может мне помочь?

+0

Вы знаете, что это не работает в високосные годы?Кажется, он добавляет 7 дней к текущему дню, который, я считаю, должен правильно обрабатывать високосные годы. –

+0

пример: когда я выбираю клиентов только с сегодняшнего дня, то есть 85 дней в году, я получаю за годы (2012,2008,2004 и т. Д.) Клиентов, у которых были дни рождения вчера. Он работает, но не дает мне результат мне нужен – Alexandru

+0

Почему вы конвертируете даты в символы перед добавлением 7 семи дней? Каков тип этих полей? – pablomatico

ответ

0

Вы заметили, что годы, которые дают вам проблемы, - это високосные годы? Проблема заключается в том, что число дней, следующего за 1 марта любого не-високосного года, будет меньше, чем число, указанное в тот же день в високосный год.

Один из способов рассчитать один и тот же день в течение многих лет - это хеш каждый день года в значение, которое в тот же день каждого года, прыжок и не-прыжок, будет иметь такое же значение и хэш 29 февраля будет между 28 февраля и 1 марта и не столкнется с каким-либо другим хэшем. Самый простой способ сделать это - умножить месяц на значение> 31 (количество дней в наибольшем месяце) и добавить день месяца. Любое значение> = 31 будет делать - даже круглое число, как 100. Это не красиво и не sargable:

Select Customer_Id, cust_birth_dt 
From Customers 
Where (Extract(Month From cust_birth_dt * 100 + Extract(Day From cust_birth_dt) 
      >= Extract(Month From SysDate) * 100 + Extract(Day From Sysdate)) 
    and (Extract(Month From cust_birth_dt * 100 + Extract(Day From cust_birth_dt) 
      < Extract(Month From SysDate + 7) * 100 + Extract(Day From SysDate + 7)); 

Использование 100 позволяет быстро вычислить хэш только с первого взгляда на дата: 2/15/yyyy = 215, 10/25/yyy = 1025.

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

create table Birthday_info(
    Cust_ID int not null, 
    B_Date date not null, 
    B_Hash int not null, 
    constraint PK_Birthday_info primary key(Cust_ID), 
    constraint FK_Birthday_Customer foreign key(Cust_ID) 
     references Customers(customers_id) 
); 

Простой запрос может заполнить его на начальном этапе:

insert into Birthday_info 
select customers_id, cust_birth_dt, 
     Extract(Month From cust_birth_dt) * 100 + Extract(Day From cust_birth_dt) 
from Customers; 

Чтобы обеспечить хорошую производительность:

create index IX_Birthday_Hash_ID on Birthday_info(B_Hash); 

An "после вставки, обновления, удаления" триггер таблицы Customers может держать новая таблица обновлена.

Тогда ваш запрос будет:

Select Cust_Id, Birth_Dt 
From Birthday_Info 
Where B_Hash >= Extract(Month From Sysdate) * 100 + Extract(Day From SysDate) 
    And B_Hash < Extract(Month From Sysdate + 7) * 100 + Extract(Day From SysDate + 7); 

Теперь sargable, но до сих пор не очень красиво. Тем не менее, вы можете создать функцию хеширования:

Select Cust_Id, Birth_Dt 
From Birthday_Info 
Where B_Hash >= Hash_pkg.Date_Hash(SysDate) 
    And B_Hash < Hash_pkg.Date_Hash(SysDate + 7); 

Гораздо лучше.

+0

Спасибо, ребята, что помогли мне, я решил проблему. – Alexandru

+0

Спасибо, ребята, что помогли мне, я решил проблему. Прежде всего, извините, мой английский. Моя проблема была в високосный год после 29 февраля, потому что день текущего года отличался от числа дней високосного года – Alexandru

+0

Ну, не держите нас в напряжении - как вы решили проблему? – TommCatt

0

Представление даты без года части, таким образом, сохраняет сортировочного, должно сделать трюк:

select customers_id 
from customer_table 
where to_number(to_char(cust_birth_dt,'MMDD')) between 
     to_number(to_char(sysdate ,'MMDD')) and 
     to_number(to_char(sysdate + 6,'MMDD')) 

Строго говоря to_char не является обязательным, но если вы собираетесь попробовать добавить FUNCTION- основанный на:

(to_number(to_char(cust_birth_dt,'MMDD','MMDD'))) 

... тогда он будет держать это немного меньше.

Смежные вопросы