2010-02-24 18 views
5

tôi có một loạt các hàng timestamped (bằng cách sử dụng 'datetime' kiểu dữ liệu)select * from bàn nơi datetime trong tháng (mà không vi phạm index)

Tôi muốn chọn tất cả các hàng có một dấu thời gian đó là trong vòng một tháng cụ thể.

Cột được lập chỉ mục để tôi không thể thực hiện MONTH (dấu thời gian) = 3 vì điều đó sẽ làm cho chỉ mục này không thể sử dụng được.

Nếu tôi có các biến năm và tháng (trong perl), là có một chút khủng khiếp của SQL Tôi có thể sử dụng như:

timestamp BETWEEN DATE($year, $month, 0) AND DATE($year, $month, 31); 

Nhưng đẹp hơn, và thực sự hoạt động?

+0

Tôi có thể giả định rằng bạn muốn tất cả các hàng của một tháng nhất định trong _all_ năm? – Arthur

+0

Một tháng cụ thể. – aidan

Trả lời

11

Tôi thực sự sẽ đi với ý tưởng bạn đã đề xuất; có lẽ với một sự khác biệt nhỏ:

select * 
from your_table 
where date_field >= '2010-01-01' 
    and date_field < '2010-02-01' 

(Tất nhiên, tùy thuộc vào bạn sử dụng $year$month đúng)


Lưu ý phần < '2010-02-01': bạn có thể phải xem xét việc này, nếu bạn có ngày bao gồm thời gian. Ví dụ:

Ví dụ: nếu bạn có một dòng có ngày như '2010-01-31 12:53:12', bạn có thể muốn chọn dòng đó - và, theo mặc định, '2010-01-31' có nghĩa là '2010-01-31 00:00:00'.


Có thể điều này trông không đẹp mắt; nhưng nó sẽ hoạt động; và sử dụng chỉ mục ... Đó là loại giải pháp mà tôi thường sử dụng khi tôi có loại vấn đề đó.

+0

+1 để đề xuất khoảng thời gian nửa mở. – dalle

1

Nếu bạn cần cùng tháng mỗi năm chỉ số bạn có sẽ không giúp bạn và không có số lượng SQL cú pháp thủ đoạn gian trá sẽ giúp bạn

Mặt khác nếu bạn cần một tháng của một năm cụ thể sau đó bất kỳ truy vấn có phạm vi ngày phải làm điều đó

1

Một giải pháp thay thế khác là thêm một cột phụ vào bảng lưu trữ tháng, được precomputed. Đó sẽ chỉ là một cột int đơn giản và không quan trọng để lập chỉ mục. Trừ khi bạn đang đối phó với một hàng kajillion, không gian thêm cho một int nhỏ unsigned là không thể tin được (một byte + db trên mỗi hàng).

Cần một chút công việc để tiếp tục đồng bộ hóa với cột dấu thời gian, nhưng đó là những gì gây nên.

2

Đây là substantively Pascal MARTIN của answer, nhưng tránh được việc phải biết một cách rõ ràng trong năm tới/tháng là những gì (vì vậy bạn không cần phải tăng năm và quấn xung quanh $month, khi $month == 12):

my $sth = $mysql_dbh->prepare(<<__EOSQL); 
SELECT ... 
    FROM tbl 
WHERE ts >= ? AND ts < (? + INTERVAL 1 MONTH) 
__EOSQL 

my $yyyymm = $year . '-' . sprintf('%02d', $month); 

$sth->execute($yyyymm, $yyyymm); 

Đối với tiền thưởng fugly điểm, bạn cũng có thể làm điều này:

... WHERE ts BETWEEN ? AND (? + INTERVAL 1 MONTH - INTERVAL 1 SECOND) 

Đó - INTERVAL 1 SECOND sẽ ép buộc các ranh giới trên từ một NGÀY thành một kiểu DATETIME/dấu thời gian thiết lập để giây cuối cùng của quảng cáo ay, đó là, như Pascal chỉ ra, những gì bạn muốn trên ràng buộc trên.

+0

Tôi thích nó! ..... – aidan

-1

Làm thế nào về WHERE MONTH(`date`) = '$month' AND YEAR(`date`) = '$year'

+2

không. điều đó sẽ làm mất hiệu lực chỉ mục. – aidan

Các vấn đề liên quan