Very interesting, Ryan. Thanks for sharing. If I would like to use these ranking techniques in SQLite, can I do this with an extension? Has nobody created a Windowing.dll yet? Just asking. My short term need has been solved, but now that I know this, I'm sure I'd like to use this technique later. But I like to stick to SQLite.
Gert Op ma 25 jun. 2018 om 01:00 schreef R Smith <ryansmit...@gmail.com>: > > On 2018/06/24 9:30 PM, Gert Van Assche wrote: > > whaw... I could never come up with solutions like this. Will this work > with > > SQLite? > > Where can I read more about this? > > I've only shown that query since Dan asked about it - it's not an SQLite > query. > > To answer/comment on your questions: > > 1. Sure you can come up with it if you have read about it and understand > what it is intended for - There is nothing you can't know, only things > you don't know yet. :) > > 2. This will not work in SQLite currently - it's part of a group of > functions called "Windowing" functions built into the bigger DB engines > which do not care about their "Liteness". > "Windowing functions" is basically a set of functions that treats the > current ROW and its immediate preceding or acceding rows, or set of > grouped rows within a bigger query (grouping by whatever common aspect > you choose) as a unit and can return localized aggregates over them. > The ranking/row position functions prove especially handy when wanting > queries to easily produce row orders, ranks, etc. - but I promise you, > they all are very possible in SQLite without Windowing functions, just > not quite as obvious (as this thread has shown). More difficult to do > are things like Percentile or Running-Total, though those too can be > accomplished with a self-join or correlated sub-query in SQLite. > The example in the original mail is from MSSQL, but similar queries work > in Postgres, Oracle, etc. > > 3. You can read more by Googling "RDBMS Windowing functions" - or just > click here: http://google.com/?q=RDBMS+windowing+functions > > > Quick intro to Windowing in SQL (Apologies to all, the following is NOT > for SQLite [yet]): > > Say I have a list of students in three classrooms and their test scores, > and I would like to show the listing ranked by their scores, per class. > > > Sorting makes part of the problem easy: > > SELECT class, student, score > FROM students > ORDER BY class, student, score DESC > ; -- This works in SQLite > > This might produce a list like: > > class, student, score > A5, Ann, 94 > A5, Able, 88 > A5, Adrian, 67 > B5, James, 92 > B5, Jenny, 88 > B5, John, 87 > B5, Joan, 74 > C5, Sloan, 98 > C5, Sean, 79 > > Now a common thing is to want to put a rank integer number in front of > every classmate so it is easy to see position, like this (spaced for > legibility only): > > rank, class, student, score > 1, A5, Ann, 94 > 2, A5, Able, 88 > 3, A5, Adrian, 67 > > 1, B5, James, 92 > 2, B5, Jenny, 88 > 3, B5, John, 87 > 4, B5, Joan, 74 > > 1, C5, Sloan, 98 > 2, C5, Sean, 79 > > And for that the query will have to produce the whole list (no overall > grouping) but then group these students by "class" to figure out the > rank within every class "window" of the larger query. > > You could say in English: We need to show the RANK *over* every window > (aka "set of records") that is *partitioned by* the "class" field, where > the rank within each "class" is determined by the value of the "score" > field in a *descending order*. That's easy enough to understand (I hope!). > > All that remains is to translate that to SQL. Looking at the English > phrase above and the SQL below should quickly clarify how it all fits > together: > > SELECT RANK() OVER (PARTITION BY class ORDER BY score DESC) as rank, > class, student, score > FROM students > ORDER BY class, student, score DESC > ; -- This example is MSSQL format > > > If you don't care about the rank, and simply wish to number the rows in > some order (student name for example), you could opt for something like: > > SELECT ROW_NUMBER() OVER (PARTITION BY class ORDER BY student) as > student_no, class, student, score > FROM students > ORDER BY class, student > ; -- MSSQL again > > which will output this: > > student_no, class, student, score > 1, A5, Able, 88 > 2, A5, Adrian, 67 > 3, A5, Ann, 94 > 1, B5, James, 92 > 2, B5, Jenny, 88 > 3, B5, Joan, 74 > 4, B5, John, 87 > 1, C5, Sean, 79 > 2, C5, Sloan, 98 > > Of course the aggregate doesn't need to be a rank or row number, it can > simply be a count() or Avg() or any aggregate function you fancy. > > Lastly, if I now want to only see the top 2 ranked students of every > class (which is like your original question in this thread), I can > simply have the RANK query above as an inner query and in the outer > query add "... WHERE rank <= 2; "[1]. > > rank, class, student, score > 1, A5, Ann, 94 > 2, A5, Able, 88 > 1, B5, James, 92 > 2, B5, Jenny, 88 > 1, C5, Sloan, 98 > 2, C5, Sean, 79 > > > Now you know. :) > Cheers, > Ryan > > > [1] - Rank is only useful as a value if the order-by is of a unique > field (or combination of fields). Consider if the top 5 students had > scores like 95, 88, 88, 88 and 75. The RANK() function over them would > produce ranks 1, 2, 2, 2, 5 - because technically the 3 middle scores > are all the same and so all ranked equally 2nd, while the 5th score is > 3rd highest and will be ranked either 5th or 3rd based on whether you > use RANK() [5th] or DENSE_RANK() [3rd] functions. > > To change this to a solid numbered list, it is best to use ROW_NUMBER() > which forces unique follow-on integers without "holes" in them to once > again produce 1,2,3,4 and 5. > > > _______________________________________________ > sqlite-users mailing list > sqlite-users@mailinglists.sqlite.org > http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users > _______________________________________________ sqlite-users mailing list sqlite-users@mailinglists.sqlite.org http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users