SQL: Repeat a result row multiple times, and number the rows
You could use a numbers table
SELECT value, count, numberFROM table JOIN Numbers ON table.count >= Numbers.number
For MySQL, use the poor man's generate_series, which is done via views. MySQL is the only RDBMS among big four that don't has any CTE feature.
Actually you can use this technique on database that supports view. So that's virtually all database
Generator technique sourced here: http://use-the-index-luke.com/blog/2011-07-30/mysql-row-generator#mysql_generator_code
The only minor modification we made is we replace the bitwise (shift left and bitwise or) technique from the original technique with mere multiplication and addition respectively; as Sql Server and Oracle has no shift left operator.
This abstraction is 99% guaranteed to work on all database, except Oracle; Oracle's SELECT
can't function without any table, in order to do this, one need to select from dummy table, Oracle provided one already, it's called DUAL
table. Database portability is a pipe dream :-)
Here's the abstracted views that works on all RDBMS, devoid of bitwise operations(which is not really a necessity anyway in this scenario) and feature nuances(we remove OR REPLACE
on CREATE VIEW
, only Postgresql and MySQL supports them) among all major database.
Oracle caveat: Just put FROM DUAL
after each SELECT
expression
CREATE VIEW generator_16AS SELECT 0 n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12 UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL SELECT 15;CREATE VIEW generator_256AS SELECT ( ( hi.n * 16 ) + lo.n ) AS n FROM generator_16 lo, generator_16 hi;CREATE VIEW generator_4kAS SELECT ( ( hi.n * 256 ) + lo.n ) AS n FROM generator_256 lo, generator_16 hi;CREATE VIEW generator_64kAS SELECT ( ( hi.n * 256 ) + lo.n ) AS n FROM generator_256 lo, generator_256 hi;CREATE VIEW generator_1mAS SELECT ( ( hi.n * 65536 ) + lo.n ) AS n FROM generator_64k lo, generator_16 hi;
Then use this query:
SELECT t.value, t.cnt, i.nFROM tbl tJOIN generator_64k i ON i.n between 1 and t.cntorder by t.value, i.n
Postgresql: http://www.sqlfiddle.com/#!1/1541d/1
Oracle: http://www.sqlfiddle.com/#!4/26c05/1
Sql Server: http://www.sqlfiddle.com/#!6/84bee/1
You asked for a db-agnostic solution and @Justin gave you a nice one.
You also asked for
clever ways to make it work on any database
There is one for PostgreSQL: generate_series()
does what you asked for out of the box:
SELECT val, ct, generate_series(1, ct) AS indexFROM tbl;
BTW, I'd rather not use value
and count
as column names. It's bad practice to use reserved words as identifiers. Using val
and ct
instead.