4

いくつかのデータベース テーブルからレポートを生成しようとしています。簡易版はこんな感じ

Campaign
----------
CampaignID

Source
-----------------------
Source_ID | Campaign_ID

Content
---------------------------------------------------------
Content_ID | Campaign_ID | Content_Row_ID | Content_Value

レポートは次のように読む必要があります。

CampaignID - SourceID - ContentRowID(Value(A)) - ContentRowID(Value(B))

ContentRowID(Value(A)) は、「指定された CampaignID と ContentRowId が「A」である行を検索し、その行の ContentValue を取得する」ことを意味します。

基本的に、行を列に「ピボット」する必要があります(正しい用語だと思います)...

それはOracle 10gデータベースです...

助言がありますか?

4

9 に答える 9

2

ビル・カーウィンはこれについて言及していますが、これは非常に明確に指摘する価値があると思います:

SQLはあなたが求めていることをしないので、あなたが得た「解決策」は無駄になります。

確かに、それは常にOracle 10で実行されることを知っているなら、確かに、Walter Mittyのクロス集計はそれを行うかもしれません. これを行う正しい方法は、クエリとアプリケーション コードで並べ替え順序を最も簡単に組み合わせて、正しく配置することです。

  • 他のデータベースシステムでも動作します。
  • 他のレイヤーが壊れるリスクはありません(たとえば、MySQLが255列を超える問題を抱えていたことを覚えています。インターフェイスライブラリとdb自体が対応していると確信していますか?)
  • (通常)それほど難しくありません。

必要な場合は、Content_Row_ID最初に s を要求してから、必要な行を , で並べ替えて要求することができます。これによりCampaignIDContentRowID各 (入力された) セルが左から右の行ごとに表示されます。


Ps。

現代人が SQL が持っている/するべきだと考えているものがたくさんありますが、それはそこにはありません。これは 1 つであり、生成された範囲は別の、再帰クロージャ、パラメトリックORDER BY、標準化されたプログラミング言語です... リストは続きます。(ただし、確かに、にはトリックがありますORDER BY

于 2008-10-18T01:32:39.790 に答える
1

動的な数の列がなく、データセットが大きすぎない場合は、これを行うことができます...

SELECT CampaignID, SourceID, 
   (SELECT Content_Value FROM Content c 
      WHERE c.Campaign_ID=s.Campaign_ID 
      AND Content_Row_ID = 39100 
      AND rownum<=1) AS Value39100,
   (SELECT Content_Value FROM Content c 
      WHERE c.Campaign_ID=s.Campaign_ID 
      AND Content_Row_ID = 39200 
      AND rownum<=1) AS Value39200
FROM Source s;

追加の Content_Row_ID ごとにサブクエリを繰り返します。

于 2008-10-17T20:35:07.707 に答える
1

標準 SQL でこれを行うには、Content_Row_ID の個別の値をすべて把握し、個別の値ごとに結合を行う必要があります。次に、Content_Row_ID の個別の値ごとに列が必要です。

SELECT CA.Campaign_ID, 
  C1.Content_Value AS "39100",
  C2.Content_Value AS "39200",
  C3.Content_Value AS "39300"
FROM Campaign CA
  LEFT OUTER JOIN Content C1 ON (CA.Campaign_ID = C1.Campaign_ID 
    AND C1.Content_Row_ID = 39100)
  LEFT OUTER JOIN Content C2 ON (CA.Campaign_ID = C2.Campaign_ID 
    AND C2.Content_Row_ID = 39200)
  LEFT OUTER JOIN Content C3 ON (CA.Campaign_ID = C3.Campaign_ID 
    AND C3.Content_Row_ID = 39300);

個別の値の数が増えると、このクエリはコストがかかりすぎて効率的に実行できなくなります。おそらく、データをより簡単にフェッチして、PL/SQL またはアプリケーション コードで再フォーマットする方が簡単です。

于 2008-10-17T20:35:29.280 に答える
1

これは私の最初の刺し傷です。コンテンツ テーブルの内容についてさらに理解が深まれば、改良が行われます。

まず、一時テーブルが必要です。

CREATE TABLE pivot (count integer);
INSERT INTO pivot VALUES (1);
INSERT INTO pivot VALUES (2);

これで、クエリを実行する準備が整いました。

SELECT campaignid, sourceid, a.contentvalue, b.contentvalue
FROM content a, content b, pivot, source
WHERE source.campaignid = content.campaignid
AND pivot = 1 AND a.contentrowid = 'A'
AND pivot = 2 AND b.contentrowid = 'B'
于 2008-10-17T19:39:32.170 に答える
1

Bill Karwin と Anders Eurenius は、単純な解決策はなく、結果の列値の数が事前にわからない場合の解決策もまったくないという点で正しいです。Oracle 11g はPIVOT operatorを使用して多少簡略化していますが、列は事前に知っておく必要があり、質問の 10g 基準を満たしていません。

于 2008-10-18T02:12:53.907 に答える
0

私はこのSQLで解決策を見つけました。行はクラスの数であり、列は月ごとの各クラスの合計である必要がありました。したがって、最初の列は行の合計であり、各列は各月の合計であり、最後の行は合計です。月ごとの完全な列の。

幸運を

Select DS.Cla,
Sum(case
when (Extract(year from DS.Data) =:intYear) then DS.PRE
else 0
end) as ToTal,
Sum(case
when (Extract(month from DS.Data) =1) then DS.PRE
else 0
end) as Jan,
Sum(case
when (Extract(month from DS.Data) =2) then DS.PRE
else 0
end) as FEV,
Sum(case
when (Extract(month from DS.Data) =3) then DS.PRE
else 0
end) as MAR,
Sum(case
when (Extract(month from DS.Data) =4) then DS.PRE
else 0
end) as ABR,
Sum(case
when (Extract(month from DS.Data) =5) then DS.PRE
else 0
end) as MAI,
Sum(case
when (Extract(month from DS.Data) =6) then DS.PRE
else 0
end) as JUN,
Sum(case
when (Extract(month from DS.Data) =7) then DS.PRE
else 0
end) as JUL,
Sum(case
when (Extract(month from DS.Data) =8) then DS.PRE
else 0
end) as AGO,
Sum(case
when (Extract(month from DS.Data) =9) then DS.PRE
else 0
end) as SETE,
Sum(case
when (Extract(month from DS.Data) =10) then DS.PRE
else 0
end) as OUT,
Sum(case
when (Extract(month from DS.Data) =11) then DS.PRE
else 0
end) as NOV,
Sum(case
when (Extract(month from DS.Data) =12) then DS.PRE
else 0
end) as DEZ
from Dados DS
Where DS.Cla > 0
And Extract(Year from DS.Data) = :intYear
group by DS.CLA

Union All

Select 0*count(DS.cla),  0*count(DS.cla),
Sum(case
when (Extract(month from DS.Data) =1) then DS.PRE
else 0
end) as JAN,
Sum(case
when (Extract(month from DS.Data) =2) then DS.PRE
else 0
end) as FEV,
Sum(case
when (Extract(month from DS.Data) =3) then DS.PRE
else 0
end) as MAR,
Sum(case
when (Extract(month from DS.Data) =4) then DS.PRE
else 0
end) as ABR,
Sum(case
when (Extract(month from DS.Data) =5) then DS.PRE
else 0
end) as MAI,
Sum(case
when (Extract(month from DS.Data) =6) then DS.PRE
else 0
end) as JUN,
Sum(case
when (Extract(month from DS.Data) =7) then DS.PRE
else 0
end) as JUL,
Sum(case
when (Extract(month from DS.Data) =8) then DS.PRE
else 0
end) as AGO,
Sum(case
when (Extract(month from DS.Data) =9) then DS.PRE
else 0
end) as SETE,
Sum(case
when (Extract(month from DS.Data) =10) then DS.PRE
else 0
end) as OUT,
Sum(case
when (Extract(month from DS.Data) =11) then DS.PRE
else 0
end) as NOV,
Sum(case
when (Extract(month from DS.Data) =12) then DS.PRE
else 0
end) as DEZ
from Dados DS
Where DS.Cla > 0
And Extract(Year from DS.Data) = :intYear
于 2010-07-07T17:28:18.113 に答える
0

前もって列の数がわからない場合は、通常のSQLクエリを元に戻し、ここにリストされているようなサーバー側のコードを使用してください:データグリッドとSQLクエリの入力

于 2008-12-03T12:58:46.890 に答える
0

「Oracle, the Complete Reference」をお持ちの場合は、「Turning a Table on its side」というタイトルのセクションを探してください。これは、ピボットを実行するための詳細な例と手順を示していますが、私が持っているエディションではピボットとは呼ばれていません。

「テーブルのピボット」の別の用語は、クロス集計です。

クロス集計を実行するための最も簡単なツールの 1 つは、MS Access です。MS Access を使用していて、Access データベースからソース テーブルへのテーブル リンクを確立できる場合は、すでにその道半ばです。

その時点で、「クエリ ウィザード」を起動して、クロス集計クエリを作成するように依頼できます。ウィザードが尋ねる質問に答えるのと同じくらい簡単です。このソリューションの残念な側面は、結果のクエリを SQL ビューで見ると、SQL の Access ダイアレクトに特有の SQL が表示され、一般に他のプラットフォームでは使用できないことです。

また、Oracle の Web サイトからいくつかの簡単な分析ツールをダウンロードし、それらのツールの 1 つを使用してクロス集計を実行することもできます。

もう一度言いますが、本当に SQL でやりたいのであれば、「Oracle, the Complete Reference」が役に立ちます。

于 2008-10-17T20:23:05.453 に答える
0

動的な数の列が必要な場合、これが標準 SQL で実行できるとは思えません。残念ながら、これは私の知識を超えています。しかし、それを可能にする Oracle の機能があります。私はいくつかのリソースを見つけました:

http://www.sqlsnippets.com/en/topic-12200.html

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:124812348063#41097616566309

于 2008-10-17T20:09:30.863 に答える