根据特定周的日期选择历史记录

时间:2015-03-26 16:31:14

标签: sql oracle date

我需要选择所有在一周内有生日的客户,这是一种触发器,每周选择那个星期生日的客户。所以这就是我所做的(我在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;

它运作良好,但是当它从闰年中选择客户时,我因为天数而陷入困境。

任何人都有想法可以帮助我吗?

2 个答案:

答案 0 :(得分:0)

您是否注意到给您带来麻烦的岁月是闰年?问题是,任何非闰年3月1日及之后的日期数将比闰年中同一日期的日数少一个。

计算一年中同一天的一种方法是将一年中的每一天哈希值变为一个值,使得每年的同一天,即跳跃和非跳跃,将具有相同的值,并且2月29日的哈希将是在2月28日至3月1日之间,不会与任何其他哈希冲突。最简单的方法是将月份乘以值> = 31(最大月份的天数)并添加月份的日期。任何值> = 31都可以 - 甚至是一个很好的整数,就像100那样。它不漂亮而且不可思议:

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 );

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 );

现在它可以了,但还不是很漂亮。但是,您可以创建散列函数:

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 );

好多了。

答案 1 :(得分: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是可选的,但是如果您打算尝试添加基于函数的索引:

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

...然后它会保持那么小。