9

次のような単一のテーブルがあります。

表の抜粋

    Owner   | Attribute | value
----------------------------------------------------
    10      | COLOR     | BLUE
    10      | COLOR     | RED
    10      | COLOR     | GREEN
    10      | SIZE      | BIG
    20      | COLOR     | GREEN
    20      | SIZE      | MEDIUM
    20      | MEMORY    | 16G
    20      | MEMORY    | 32G
    30      | COLOR     | RED
    30      | COLOR     | BLUE
    30      | MEMORY    | 64G

すべての属性と単一のインデックスの組み合わせを計算する SQL はありますか (結果の最後の列):

Owner   | Attribute | Value | Rule_No
10      | COLOR     | BLUE  | 1
10      | SIZE      | BIG   | 1
10      | COLOR     | RED   | 2
10      | SIZE      | BIG   | 2
10      | COLOR     | GREEN | 3
10      | SIZE      | BIG   | 3
20      | COLOR     | GREEN | 1
20      | SIZE      | MEDIUM| 1
20      | MEMORY    | 16G   | 1
20      | COLOR     | GREEN | 2
20      | SIZE      | MEDIUM| 2
20      | MEMORY    | 32G   | 2
30      | COLOR     | BLUE  | 1
30      | MEMORY    | 64G   | 1
30      | COLOR     | RED   | 2
30      | MEMORY    | 64G   | 2

ルール番号は所有者ごとに一意です (所有者「10」のルール「1」は、所有者「20」のルール「1」とは関係ありません。

SQLクロス結合を使用しようとしましたが、属性の数が固定されていないため、使用できません(属性ごとに1つのクロス結合が必要です)。組み合わせを新しい列ではなく新しい行にしたいです。

私はそれを実行しようとしTalend Open Studio - Data Integrationていますが、SQL のみを使用するソリューションの方が適しています。

4

5 に答える 5

6

質問で指定された形式のデータが本当に必要ですか (最も可能性の高い状況で役立つようにするには、さらに集計が必要にRule_Noなります)、それとも最終的にピボットしようとしていますか? つまり、ルールは次のように結合されます (各属性が独自の列になります)。

+--------+-------+-------+--------+--------+
| | Rule_いいえ | 所有者 | カラー | サイズ | メモリー |
+--------+-------+-------+--------+--------+
| | 1 | 10 | ブルー | ブルー | 大きい | ヌル |
| | 2 | 10 | 赤 | 赤 | 大きい | ヌル |
| | 3 | 10 | グリーン | 大きい | ヌル |
| | 1 | 20 | グリーン | ミディアム | 16G |
| | 2 | 20 | グリーン | ミディアム | 32G |
| | 1 | 30 | 赤 | 赤 | ヌル | 64G |
| | 2 | 30 | ブルー | ブルー | ヌル | 64G |
+--------+-------+-------+--------+--------+

次のように、クエリを使用してそのようなデータをピボットできます。

SELECT   @t:=IF(Owner=@o,@t,0)+1 AS Rule_No,
         @o:=Owner AS Owner,
         `COLOR`,`SIZE`,`MEMORY`
FROM     (SELECT DISTINCT Owner, @t:=0 FROM my_table) t0

  LEFT JOIN (
    SELECT Owner, value AS `COLOR`
    FROM   my_table
    WHERE  Attribute='COLOR'
  ) AS `t_COLOR` USING (Owner)

  LEFT JOIN (
    SELECT Owner, value AS `SIZE`
    FROM   my_table
    WHERE  Attribute='SIZE'
  ) AS `t_SIZE` USING (Owner)

  LEFT JOIN (
    SELECT Owner, value AS `MEMORY`
    FROM   my_table
    WHERE  Attribute='MEMORY'
  ) AS `t_MEMORY` USING (Owner)

ORDER BY Owner, Rule_No

属性リストは動的であるため、クエリを使用して上記の SQL を構築し、そこからステートメントを準備して実行できます。

SELECT CONCAT('
         SELECT   @t:=IF(Owner=@o,@t,0)+1 AS Rule_No,
                  @o:=Owner AS Owner,
                  ', GROUP_CONCAT(DISTINCT CONCAT(
                    '`',REPLACE(Attribute,'`','``'),'`'
                  )), '
         FROM     (SELECT DISTINCT Owner, @t:=0 FROM my_table) t0
       ', GROUP_CONCAT(DISTINCT CONCAT('
           LEFT JOIN (
             SELECT Owner, value AS `',REPLACE(Attribute,'`','``'),'`
             FROM   my_table
             WHERE  Attribute=',QUOTE(Attribute),'
           ) AS `t_',REPLACE(Attribute,'`','``'),'` USING (Owner)
         ') SEPARATOR ''), '
         ORDER BY Owner, Rule_No
       ') INTO @sql
FROM   my_table;

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

sqlfiddleで参照してください。

于 2013-01-17T17:06:50.227 に答える
2

わかりましたので、まず何かを書く前に: このクエリは 1 つの SQL 選択で実行できますが、お勧めしません。この小さなサンプル テーブルに対しては実行できますが、大きなテーブルに対する現実的な解決策にはなりません。ストアド プロシージャを使用することで、より適切な (より高速でクリーンな) 方法で解決できます。

また、ここでは午前 2 時 10 分ではないため、完全には終了しませんでした。これにはすでに数時間の作業があります。既存のクエリに基づいて SQL リライトをコピー アンド ペーストします。

思考回路をサンプルデータとともにペーストビンに投稿しました

基本的なプロセスは次のとおりです。

  1. 所有者の可能な順列 (N) を数えます
  2. 1..(N*number_of_attributes) から数値を生成する SQL クエリを作成します。
  3. すべての行
    1. N に基づいて属性を選択する
    2. N に基づいて属性の値を選択する

このアルゴリズムは、任意の数の属性または値に対する一般的なソリューションです。

于 2013-01-18T01:19:32.563 に答える
0

SQL Serverに対するfthiellaの回答は次のとおりです(最終ではありません):

If  Object_ID('tempdb..#test') Is Not Null Drop Table #test;

Select '10' As Owner,'COLOR' Attribute,'BLUE' Value Into #test
Union
Select '10','COLOR','RED'
Union
Select '10','COLOR','GREEN'
Union
Select '10','SIZE','BIG'
Union
Select '20','a','1'
Union
Select '20','a','2'
Union
Select '20','b','111'
Union
Select '20','b','222'
Union
Select '20','COLOR','GREEN'
Union
Select '20','SIZE','MEDIUM'
Union
Select '20','MEMORY','16G'
Union
Select '20','MEMORY','32G'
Union
Select '30','COLOR','RED'
Union
Select '30','COLOR','BLUE'
Union
Select '30','MEMORY','64G';



Select 
    Owner, Attribute, Value,
    RuleNo = Row_Number() Over (Partition By Owner, Attribute Order By Owner, Attribute)
From
    (Select Base.Owner, Base.Attribute, Base.Value
    From
        #Test As Base
        Inner Join
            (Select Owner, Attribute
             From #Test
             Group By Owner, Attribute
             Having Count(*) > 1) As MultipleValue
        On Base.Owner = MultipleValue.Owner
        And Base.Attribute = MultipleValue.Attribute
        Union All
        Select Sing.Owner, Sing.Attribute, Sing.Value
        From
            (Select Owner, Attribute, Value = Min(Value)
            From #Test
            Group by Owner, Attribute
            Having Count(*) = 1) As Sing
        Inner Join
            (Select Owner, Attribute
            From #Test
            Group by Owner, Attribute
            Having Count(*) > 1) As Mult
            On Sing.Owner = Mult.Owner
        Inner Join #Test As Comp
        On Mult.Owner = Comp.Owner And Mult.Attribute = Comp.Attribute) As Vals
Order By 
    Owner, RuleNo, Attribute, Value
于 2013-01-16T20:08:56.120 に答える
0

私はこれを試してみました (そして、あまりにも多くの時間を費やしました)。私には解決策があると思いました-それは、指定されたデータに対して期待される結果(正確ではありませんが、許容できると思います)を生成します。残念ながら、より多くのデータが追加されると、それは持ちこたえません。

おそらく、他の誰かがこれに基づいて実用的な解決策を見つけることができます。

SELECT DISTINCT a.`owner`, a.`attribute`, a.`value`, a.`index` * b.`index` AS `Rule_No`
FROM (
  SELECT `owner`, `attribute`, `value`,  
    IF(
      `owner` = @_owner AND `attribute` = @_attribute,
      @_row := @_row + 1,
      @_row := 1 AND (@_owner := `owner`) AND (@_attribute := `attribute`)
    ) + 1 AS `index`
  FROM `attributes`, (SELECT @_owner := '', @_attribute := '', @_row := 0) x
  ORDER BY `owner`, `attribute`
  ) a
INNER JOIN (
  SELECT `owner`, `attribute`, `value`,  
    IF(
      `owner` = @_owner AND `attribute` = @_attribute,
      @_row := @_row + 1,
      @_row := 1 AND (@_owner := `owner`) AND (@_attribute := `attribute`)
    ) + 1 AS `index`
  FROM `attributes`, (SELECT @_owner := '', @_attribute := '', @_row := 0) x
  ORDER BY `owner`, `attribute`
  ) b
ON a.`owner` = b.`owner` AND a.`attribute` <> b.`attribute`
ORDER BY `owner`, `Rule_No`, `attribute`, `value`

SQLFiddle-作業中

SQLFiddle - 壊れています (より多くのデータが追加されました)

于 2013-01-17T20:22:36.307 に答える
0

これは完全にはほど遠いですが、私が持っていた時間でできる最善のことでした. 多分それは他の誰かにアイデアを与えるでしょうか?具体的には、このデータセットに対して間違った順序で正しい行数を取得します。

select a.owner, a.attribute, a.value
from test1 a
    join (
        select owner, attribute, count(distinct attribute, value) - 1 as total
        from test1
        group by owner, attribute
    ) b
        on a.owner = b.owner
            and a.attribute = b.attribute
    join (
        select owner, max(total) as total from (
            select owner, attribute, count(distinct attribute, value) as total
            from test1
            group by owner, attribute
        ) t group by owner
    ) c
        on a.owner = c.owner
    join (
        select @rownum:=@rownum+1 as num
        from test1,
            (select @rownum:=0 from dual) r
    ) temp
        on num <= c.total - b.total
order by a.owner asc
;
于 2013-01-17T20:24:03.830 に答える