> On Saturday, 14 September, 2013 07:19, Yuriy Kaminskiy said: > Keith Medcalf wrote: > >> On Thu, 12 Sep 2013 14:01:04 +0100 > >> Simon Davies <simon.james.dav...@gmail.com> wrote: > >> > >>> Why not > >>> SELECT * FROM "entry" WHERE > >>> bankdate >= date('now','start of month') > >>> AND bankdate < date('now','start of month','+1 month') > >> The half-open interval strikes again! :-) > > > > And you are using UTC ... > > > > Notwithstanding the timezone you want to use, > > > > explain select * > > from entry > > where bankdate >= date('now', 'start of month') > > and bankdate < date('now', 'start of month', '-1 day'); > > > > will generate the following code: > > And there are another pitfall in this query: date('now') is *RACY*. That > is, if you execute this query *exactly* at midnight at month boundary, first > and second DATE() invocation may refer to *different* months. > And if your query return several rows, and there will be month boundary > between sqlite3_step(), your query also can return data from two month. > You can easily reproduce this problem if you switch unit from month to > millisecond, e.g. > SELECT * FROM t WHERE strftime('%f') <> strftime('%f'); > will non-deterministically return rows. > IMO, correct [= least surprise] behavior should be "timestamp used for > 'now' should cached on first row step, and reused in all following calls > [until SQLITE_OK/SQLITE_DONE returned]", but fixing that won't be easy :-|.
That would require a change to SQLite itself. Without doing that I believe this will solve those problems by using only one 'now', and also only running each date() call once (even my previous solutions could suffer from race conditions since they retrieved 'now' multiple times): sqlite> explain select * ...> from entry, ...> (select bdate, (select date(bdate, '+1 month')) as edate ...> From (select date('now', 'localtime', 'start of month') as bdate) as ttemp limit 1) as tstamp ...> where bankdate >= bdate ...> and bankdate < edate; SELECT item[0] = {0:0} AS bankdate item[1] = {1:0} AS bdate item[2] = {1:1} AS edate FROM {0,*} = entry {1,*} = SELECT item[0] = {2:0} item[1] = (SELECT FUNCTION:date(item[0] = {2:0} item[1] = '+1 month') LIMIT 1 END) AS edate FROM {2,*} = SELECT FUNCTION:date(item[0] = 'now' item[1] = 'localtime' item[2] = 'start of month') END (tabname=sqlite_subquery_56DA50_) (AS ttemp) LIMIT 1 END (tabname=sqlite_subquery_56F8D0_) (AS tstamp) WHERE AND(GE({0:0},{1:0}),LT({0:0},{1:1})) END addr opcode p1 p2 p3 p4 p5 comment ---- ------------- ---- ---- ---- ------------- -- ------------- 0 Trace 0 0 0 00 1 Integer 33 1 0 00 2 Once 0 33 0 00 3 Goto 0 50 0 00 4 Goto 0 14 0 00 5 OpenPseudo 2 4 1 01 6 Integer 0 3 0 01 7 String8 0 5 0 now 00 8 String8 0 6 0 localtime 00 9 String8 0 7 0 start of month 00 10 Function 7 5 4 date(-1) 03 11 Yield 2 0 0 00 12 Integer 1 3 0 00 13 Yield 2 0 0 00 14 OpenEphemeral 1 2 0 00 15 Integer 1 8 0 00 16 Integer 4 2 0 00 17 Yield 2 0 0 00 18 If 3 33 0 00 19 Column 2 0 9 00 20 Null 0 11 0 00 21 Integer 1 12 0 00 22 Column 2 0 14 00 23 String8 0 15 0 +1 month 00 24 Function 2 14 13 date(-1) 02 25 Move 13 11 0 00 26 IfZero 12 27 -1 00 27 SCopy 11 10 0 00 28 MakeRecord 9 2 16 00 29 NewRowid 1 17 0 00 30 Insert 1 16 17 08 31 IfZero 8 33 -1 00 32 Goto 0 17 0 00 33 Return 1 0 0 00 34 OpenRead 0 2 0 1 00 35 Rewind 1 48 0 00 36 Rewind 0 47 0 00 37 Column 0 0 18 00 38 Column 1 0 19 00 39 Lt 19 46 18 collseq(BINARY) 6a 40 Column 1 1 20 00 41 Ge 20 46 18 collseq(BINARY) 6a 42 Column 0 0 21 00 43 Column 1 0 22 00 44 Column 1 1 23 00 45 ResultRow 21 3 0 00 46 Next 0 37 0 01 47 Next 1 36 0 01 48 Close 0 0 0 00 49 Halt 0 0 0 00 50 Transaction 0 0 0 00 51 VerifyCookie 0 1 0 00 52 TableLock 0 2 0 entry 00 53 Goto 0 4 0 00 sqlite> It is a bit complicated though. It would be much simpler to do the date calculation in the host language and pass the boundary values as parameters to the query. Of course, you could also do the following: Select * from entry where bankdate like (select substr(date('now', 'localtime'), 7) + '%'); But of course this will always do a table/index scan that cannot be optimized away ... _______________________________________________ sqlite-users mailing list sqlite-users@sqlite.org http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users