我正在尝试从几个数据库表生成报告。简化版看起来像这样
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数据库......
有什么建议吗?
答案 0 :(得分:2)
SQL不能满足您的要求,因此您获得的任何“解决方案”都将成为一个障碍。
如果您知道,当然,它总是会在Oracle 10上运行,那么确定,Walter Mitty的交叉制作可能会这样做。正确的方法是在查询和应用程序代码中使用最简单的排序顺序组合来正确排列。
如果您需要,您可以先询问Content_Row_ID
,然后询问您需要的行,按CampaignID
,ContentRowID
排序,这会给您每个(填充)单元格从左到右,逐行排列。
的PS。
有一堆现代人认为SQL应该拥有/做的东西就是不存在。这是一个,生成的范围是另一个,递归闭包,参数ORDER BY
,标准化编程语言......列表继续。 (不过,诚然,ORDER BY
)
答案 1 :(得分:1)
这是我第一次尝试。一旦我对Content表的内容有了更多的了解,就会出现细化。
首先,您需要一个临时表:
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'
答案 2 :(得分: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;
为每个additonal Content_Row_ID重复子查询。
答案 3 :(得分: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或应用程序代码中重新格式化它可能更容易。
答案 4 :(得分:1)
Bill Karwin和Anders Eurenius是正确的,没有任何解决方案是直截了当的,当预先不知道结果列值的数量时,也没有任何解决方案。 Oracle 11g确实使用the PIVOT operator对其进行了一些简化,但是这些列仍然必须提前知道,并且不符合您问题的10g标准。
答案 5 :(得分: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
答案 6 :(得分:0)
如果您有“Oracle,完整参考”,请查找标题为“转动表格”的部分。这给出了执行数据透视的详细示例和说明,尽管我的版本并没有将其称为支点。
“旋转表格”的另一个术语是交叉制表。
用于执行交叉制表的最简单工具之一是MS Access。如果您有MS Access,并且可以建立从Access数据库到源表的表链接,那么您已经在那里了一半。
此时,您可以启动“查询向导”,并要求它为您构建交叉表查询。这真的就像回答向导问你的问题一样简单。这个解决方案的不幸之处在于,如果在SQL视图中查看结果查询,您将看到一些SQL的Access方言所特有的SQL,并且通常不能在其他平台上使用。
您也可以从Oracle网站下载一些简单的分析工具,并使用其中一种工具为您执行交叉制表。
再一次,如果你真的想在SQL中做到这一点,“Oracle,完整参考”应该会帮助你。
答案 7 :(得分:0)
如果你不知道前面的列数,只需带回正常的sql查询并使用我在此处列出的服务器端代码:Filling Datagrid And Sql Query
答案 8 :(得分:0)
我用这个SQL做了一个解决方案。我需要行是类的数量,列是每个每个classe的sumary,所以,第一列是行的sumary,每个ohters列是每个月的sumary,最后一行是sumary完整列的逐月。
祝你好运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