SQL:多次重复结果行,并对行进行编号

cyg*_*gri 24 mysql sql sql-server oracle postgresql

我有一个SQL查询,结果如下:

value | count
------+------
foo   |     1
bar   |     3
baz   |     2
Run Code Online (Sandbox Code Playgroud)

现在我想扩展它,以便每次count大于1的行多次出现.我还需要对这些行进行编号.所以我会得到:

value | count | index
------+-------+------
foo   |     1 |     1
bar   |     3 |     1
bar   |     3 |     2
bar   |     3 |     3
baz   |     2 |     1
baz   |     2 |     2
Run Code Online (Sandbox Code Playgroud)

我必须在所有主要数据库(Oracle,SQL Server,MySQL,PostgreSQL以及更多)上完成这项工作.因此,跨不同数据库工作的解决方案将是理想的,但是可以通过巧妙的方式使其适用于任何数据库.

Jus*_*ony 32

你可以使用数字表

SELECT value, count, number
FROM table
    JOIN Numbers 
        ON table.count >= Numbers.number
Run Code Online (Sandbox Code Playgroud)

这是一个使用MSSQL的SQLFiddle


Mic*_*uen 21

对于MySQL,使用穷人的generate_series,这是通过视图完成的.MySQL是四大中唯一没有任何CTE功能的RDBMS .

实际上,您可以在支持视图的数据库上使用此技术.所以这几乎都是数据库

源于此的发电机技术:http://use-the-index-luke.com/blog/2011-07-30/mysql-row-generator#mysql_generator_code

我们做的唯一一个小修改是我们分别用乘法和加法替换原始技术中的按位(左移按位或)技术; 因为Sql Server和Oracle没有左移操作符.

除了Oracle之外,这种抽象保证99%适用于所有数据库; Oracle SELECT无法在没有任何表的情况下运行,为了做到这一点,需要从虚拟表中选择,Oracle已经提供了一个,它叫做DUALtable.数据库可移植性是一个白日梦:-)

下面是对所有RDBMS作品抽象的观点,没有位操作(这是不是一个真正的必要性反正在这种情况下)和功能的细微差别(除去OR REPLACECREATE VIEW所有主要的数据库中,仅PostgreSQL和MySQL支持他们).

Oracle警告:只需FROM DUAL在每个SELECT表达式之后添加

CREATE VIEW generator_16
AS 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_256
AS SELECT ( ( hi.n * 16 ) + lo.n ) AS n
     FROM generator_16 lo, generator_16 hi;

CREATE VIEW generator_4k
AS SELECT ( ( hi.n * 256 ) + lo.n ) AS n
     FROM generator_256 lo, generator_16 hi;

CREATE VIEW generator_64k
AS SELECT ( ( hi.n * 256 ) + lo.n ) AS n
     FROM generator_256 lo, generator_256 hi;

CREATE VIEW generator_1m
AS SELECT ( ( hi.n * 65536 ) + lo.n ) AS n
     FROM generator_64k lo, generator_16 hi;
Run Code Online (Sandbox Code Playgroud)

然后使用此查询:

SELECT t.value, t.cnt, i.n
FROM tbl t
JOIN generator_64k i 
ON i.n between 1 and t.cnt
order by t.value, i.n
Run Code Online (Sandbox Code Playgroud)

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

MySQL:http://www.sqlfiddle.com/#!2/ 78f5b/1


Mic*_*uen 7

MySQL实际上是数据库世界的IE,它在标准和功能方面是如此坚持.

适用于除MySQL之外的所有主要RDBMS:

with 
-- Please add this on Postgresql:
-- RECURSIVE
tbl_populate(value, cnt, ndx) as
(
  select value, cnt, 1 from tbl

  union all

  select t.value, t.cnt, tp.ndx + 1
  from tbl t
  join tbl_populate tp 
  on tp.value = t.value  
  and tp.ndx + 1 <= t.cnt
)
select * from tbl_populate
order by cnt, ndx
Run Code Online (Sandbox Code Playgroud)

SQL Server : http://www.sqlfiddle.com/#!6/911a9/1

Oracle : http://www.sqlfiddle.com/#!4/198cd/1

Postgresql: http://www.sqlfiddle.com/#!1/0b03d/1

  • +1表示"*数据库世界的IE*".你让我今天一整天都感觉很好 (2认同)

Erw*_*ter 6

您要求提供与数据库无关的解决方案,@ Justin为您提供了一个很好的解决方案.
你也要求了

聪明的方法使它适用于任何数据库

有一个用于PostgreSQL:generate_series()你提出的开箱即用:

SELECT val, ct, generate_series(1, ct) AS index
FROM   tbl;
Run Code Online (Sandbox Code Playgroud)

顺便说一句,我宁愿不使用valuecount作为列名.使用保留字作为标识符是不好的做法.使用valct代替.