James,

I'm very impressed by your solution. My SQL knowledge is not yet good
enough to understand what you proposed, but I hope one day that I will be
able to understand and replicate myself the code you wrote. I started of
with a join on the table itself as well, but I got stuck. I'll study your
code and I'll grow.
That is the beauty of groups like this: hobby developers like me get advice
from experts on problems we're facing. Very helpful, not just the code, but
also the on-problem training!
Thanks for your work, all!

gert

2013/3/3 James K. Lowden <jklow...@schemamania.org>

> On Sat, 2 Mar 2013 14:46:40 +0100
> Gert Van Assche <ger...@datamundi.be> wrote:
>
> > All, I don't know how to achieve this: I need to put the cumulative
> > sum in a field, and create a group as soon as that cumulative sum is
> > over a breakpoint value (10).
>
> This was a bit of a challenge because the group definition is IMO a
> little strange: The first value *after* the breakpoint is included in
> the group.  That made the SQL more convoluted than it would be
> otherwise.
>
> That said, the attached SQL does the job in one statement.  No triggers
> are needed.
>
> $ sqlite3 db < running_sum.sql
> TextField   ValueField  CumulativeValue  BreakPoint  GroupName
> ----------  ----------  ---------------  ----------  ----------
> A           2           2                10          1
> B           3           5                10          1
> C           2           7                10          1
> D           4           11               10          1
> E           5           5                10          2
> F           1           6                10          2
> G           1           7                10          2
> H           5           12               10          2
> I           11          11               10          3
> J           8           8                10          4
> K           2           10               10          4
>
> This lets you define the results in terms of the base data instead of
> keeping a table of derived values.  No updates required, just a view.
> Unless you have data-warehouse rowcounts or a very limited machine, it
> should perform just fine, despite what one might guess, because the I/O
> is limited to one table.  It should also outperform any per-row
> solution.
>
> Two bits of advice if I may.
>
> Be careful of using triggers to maintain data consistency.  Triggers
> are very good for enforcing referential integrity in situations that
> DRI can't handle. Beyond that they get very complex and error prone.
>
> Using triggers to compute derived values signals redundancy in the
> database.  That redundancy often is not as desirable as the
> denormalize-for-performance crowd thinks.  Better to compute derived
> values on demand (as in a view).  If that's demonstrated to be too
> slow, a periodic update in a cron job or similar should provide better
> thoughput than recomputing on every insert/update/delete.  You'll also
> do yourself a favor by segregating derived values in a different table
> that can be regenerated at will.
>
> My other suggestion is to eschew abstract nouns in column names.  Words
> like data, field, and value add no meaning.  After all, it's a
> database.  If it's not a value, what is it?
>
> This table,
>
> CREATE TABLE [Test]
>         ( Name
>         , Value
>         , RunningSum
>         , Breakpoint /* (one word, small 'p') */ DEFAULT 10
>         , GroupName
>         , primary key (Name)
>         );
>
> is at least  as clear, wouldn't you say?
>
> HTH.
>
> --jkl
>
> P.S. In case the listserv strips attachments, here it is in plain
> text.
>
> [SQL]
> select   A.TextField, A.ValueField
>        , A.total - coalesce(C.GroupTotal, 0) as CumulativeValue
>        , A.Breakpoint
> --       , coalesce(C.GroupTotal, 0) as GroupTotal
>        , coalesce(B.GroupName, A.GroupName) as GroupName
> from (
>         select   a.*, sum(b.ValueField) as total
>                , 1 + sum(b.ValueField) / (1+a.Breakpoint) as GroupName
>         from Test as a join Test as b
>         on a.TextField >= b.TextField
>         group by a.TextField
>                 , a.ValueField
>                 , a.CumulativeValue
>                 , a.BreakPoint
> ) as A
> left join (
>         select   a.*, sum(b.ValueField) as total
>                , 1 + sum(b.ValueField) / (1 + a.Breakpoint) as GroupName
>         from Test as a join Test as b
>         on a.TextField >= b.TextField
>         group by a.TextField
>                 , a.ValueField
>                 , a.CumulativeValue
>                 , a.BreakPoint
> ) as B
> on B.TextField = (select max(TextField) from Test where TextField <
> A.TextField) left join (
>         select    1 + T.GroupName as GroupName
>                 , max(T.total) as GroupTotal
>         from (
>                 select    A.TextField
>                         , A.ValueField
>                         , A.total
>                         , coalesce(B.GroupName, 1) as GroupName
>                 from (
>                         select   a.*, sum(b.ValueField) as total
>                                , 1 + sum(b.ValueField) / (1 +
> a.Breakpoint) as GroupName from Test as a join Test as b
>                         on a.TextField >= b.TextField
>                         group by  a.TextField
>                                 , a.ValueField
>                                 , a.CumulativeValue
>                                 , a.BreakPoint
>                                 ) as A
>                 left join (
>                         select   a.*, sum(b.ValueField) as total
>                                , 1 + sum(b.ValueField) / (1 +
> a.Breakpoint) as GroupName from Test as a join Test as b
>                         on a.TextField > b.TextField
>                         group by  a.TextField
>                                 , a.ValueField
>                                 , a.CumulativeValue
>                                 , a.BreakPoint
>                 ) as B
>                 on B.TextField = ( select max(TextField)
>                                    from Test
>                                    where TextField <= A.TextField  )
>         ) as T
>         group by GroupName
>         ) as C
> on B.GroupName = C.GroupName
> ;
> [LQS]
> >
> > This is an example table:
> >
> > CREATE TABLE [Test] (TextField, ValueField, CumulativeValue,
> > BreakPoint DEFAULT 10, GroupName);
> > insert into [Test] values('A', '2', null, '10');
> > insert into [Test] values('B', '3', null, '10');
> > insert into [Test] values('C', '2', null, '10');
> > insert into [Test] values('D', '4', null, '10');
> > insert into [Test] values('E', '5', null, '10');
> > insert into [Test] values('F', '1', null, '10');
> > insert into [Test] values('G', '1', null, '10');
> > insert into [Test] values('H', '5', null, '10');
> > insert into [Test] values('I', '11', null, '10');
> > insert into [Test] values('J', '8', null, '10');
> > insert into [Test] values('K', '2', null, '10');
> >
> > I'd like to end up with a table that looks like this:
> >
> > ?TextField ValueField CumulativeValue BreakPoint GroupName
> > A 2 2 10 1
> > B 3 5 10 1
> > C 2 7 10 1
> > D 4 11 10 1
> > E 5 5 10 2
> > F 1 6 10 2
> > G 1 7 10 2
> > H 5 12 10 2
> > I 11 11 10 3
> > J 8 8 10 4
> > K 2 2 10 4
> >
> > I spent hours trying to update the CumulativeValue field untill the
> > BreakPoint value is crossed, and restarting the cumulative counter,
> > but I have too little sql knowledge to do this.
> >
> > Could anyone help me?
> >
> > thanks
> >
> > gert
> > _______________________________________________
> > sqlite-users mailing list
> > sqlite-users@sqlite.org
> > http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users
>
> _______________________________________________
> sqlite-users mailing list
> sqlite-users@sqlite.org
> http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users
>
>
_______________________________________________
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to