25

次のような結果のSQLクエリがあります。

value | count
------+------
foo   |     1
bar   |     3
baz   |     2

countここで、これを拡張して、1より大きい各行が複数回発生するようにします。また、これらの行に番号を付ける必要があります。だから私は得るでしょう:

value | count | index
------+-------+------
foo   |     1 |     1
bar   |     3 |     1
bar   |     3 |     2
bar   |     3 |     3
baz   |     2 |     1
baz   |     2 |     2

これをすべての主要なデータベース(Oracle、SQL Server、MySQL、PostgreSQLなど)で機能させる必要があります。したがって、さまざまなデータベースで機能するソリューションが理想的ですが、どのデータベースでも機能させるための賢い方法がありがたいです。

4

9 に答える 9

32

あなたは数字の表を使うことができます

SELECT value, count, number
FROM table
    JOIN Numbers 
        ON table.count >= Numbers.number

これがMSSQLを使用したSQLFiddleです

于 2012-05-03T01:01:39.887 に答える
25

MySQLの場合、ビューを介して実行される貧乏人のgenerate_seriesを使用します。MySQLは、 CTE機能を持たないビッグ4の中で唯一のRDBMSです。

実際には、ビューをサポートするデータベースでこの手法を使用できます。つまり、これは事実上すべてのデータベースです

ここで提供されるジェネレーター手法:http://use-the-index-luke.com/blog/2011-07-30/mysql-row-generator#mysql_generator_code

私たちが行った唯一の小さな変更は、元の手法からビット単位(左シフトビット単位または)の手法を、それぞれ単なる乗算と加算に置き換えることです。SQLServerとOracleには左シフト演算子がないためです。

この抽象化は、Oracleを除くすべてのデータベースで機能することが99%保証されています。OracleSELECTはテーブルなしでは機能できません。これを行うには、ダミーテーブルから選択する必要があります。Oracleはすでにテーブルを提供しています。これはDUALテーブルと呼ばれます。データベースの移植性は夢のようなものです:-)

これは、すべてのRDBMSで機能する抽象化されたビューであり、ビット単位の操作(このシナリオでは実際には必要ではありません)と、すべての主要なデータベースの特徴のニュアンス(PostgresqlとMySQLのみがサポートします)OR REPLACEを欠いています。CREATE VIEW

Oracleの警告:FROM DUALSELECT式の後に置く

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;

次に、次のクエリを使用します。

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

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

于 2012-05-03T13:09:37.367 に答える
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

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

于 2012-05-03T02:18:23.130 に答える
7

あなたはdbにとらわれない解決策を求めました、そして@Justinはあなたに素晴らしい解決策を与えました。
あなたも求めました

任意のデータベースで機能させるための賢い方法

PostgreSQLgenerate_series()用の1つがあります:箱から出してあなたが求めたことをします:

SELECT val, ct, generate_series(1, ct) AS index
FROM   tbl;

ところで、私は列名として使用valueしたくありません。予約語を識別子としてcount使用することはお勧めできません。代わりにとを使用します。valct

于 2012-05-03T08:07:32.030 に答える
4

数値テーブルを作成します-その定義はプラットフォームによってわずかに異なる場合があります(これはSQL Server用です):

CREATE TABLE Numbers(Number INT PRIMARY KEY);

INSERT Numbers 
SELECT TOP 1000 ROW_NUMBER() OVER (ORDER BY name)
FROM sys.all_columns;

現在、この臨時雇用者はSQL Serverでもありますが、指定したRDBMS全体で有効である必要がある結合構文を示しています(ただし、使用しないため、テストできません)。

DECLARE @foo TABLE(value VARCHAR(32), [count] INT);

INSERT @foo SELECT 'foo', 1
UNION ALL SELECT 'bar', 3
UNION ALL SELECT 'baz', 2;

SELECT f.value, f.[count], [index] = n.Number
FROM @foo AS f, Numbers AS n
WHERE n.Number <= f.[count];

結果(ここでも、SQL Server):

value | count | index
------+-------+------
foo   |     1 |     1
bar   |     3 |     1
bar   |     3 |     2
bar   |     3 |     3
baz   |     2 |     1
baz   |     2 |     2
于 2012-05-03T01:06:24.460 に答える
2

感謝の気持ちだけのために、SQLServer2005以降はこれを再帰的に処理できます。

declare @Stuff as Table ( Name VarChar(10), Number Int )
insert into @Stuff ( Name, Number ) values ( 'foo', 1 ), ( 'bar', 3 ), ( 'baz', 2 )

select * from @Stuff

; with Repeat ( Name, Number, Counter ) as (
  select Name, Number, 1
    from @Stuff
    where Number > 0
  union all
  select Name, Number, Counter + 1
    from Repeat
    where Counter < Number
  )
select *
  from Repeat
  order by Name, Counter -- Group by name.
  option ( maxrecursion 0 )
于 2012-05-03T02:31:11.733 に答える
1

簡単JOINに、レコードをn回繰り返すという目的に到達できます。
次のクエリは、各レコードを20回繰り返します。

SELECT  TableName.*
FROM    TableName
JOIN    master.dbo.spt_values on type = 'P' and number < 20


master.dbo.spt_values on type = 'P'
このテーブルは、条件によってハードコードされた一連の数値を取得するために使用されますtype='P'

于 2017-01-22T10:42:08.153 に答える
0

あなたはCTEを使うことができます:

WITH Numbers(Num) AS
(
    SELECT 1 AS Num
    UNION ALL 
    SELECT Num + 1
    FROM   Numbers c
    WHERE  c.Num < 1000
)

SELECT VALUE,COUNT, number
FROM   TABLE
       JOIN Numbers
            ON  TABLE.count >= Numbers.Num
OPTION(MAXRECURSION 1000)
于 2018-01-13T11:46:47.950 に答える
0

LEVELOracleでは、との組み合わせを使用できますCROSS JOIN

  SELECT *
    FROM yourtable
         CROSS JOIN (    SELECT ROWNUM index_t
                           FROM DUAL
                     CONNECT BY LEVEL <= (SELECT MAX (count_t) FROM yourtable))
   WHERE index_t <= count_t
ORDER BY VALUE, index_t;

デモ

于 2018-02-06T13:39:51.663 に答える