2008-10-17 35 views
4

我正在尝试从几个数据库表生成报表。简化版本看起来像这样在SQL中“旋转”一个表(即交叉制表/交叉制表)

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(价值(A))的意思是“找到一个行已给定的CampaignID和ContentRowId “A”,然后拿到ContentValue该行的”

从本质上讲,我有‘支点’(我认为这是正确的术语)的行转换成列...

这是一个Oracle 10g数据库...

有什么建议吗?

+0

你能不能给我们一些样本数据或告诉我们更多关于限制?例如,对于给定的campaignid,是否只有两行? – 2008-10-17 19:32:53

+0

contentid和contentrowid有什么区别? – 2008-10-17 19:43:51

+0

我刚刚发布了一个应该希望清楚的例子...让我知道如果这没有帮助... – Kivus 2008-10-17 20:00:13

回答

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' 
+0

将答案中添加额外的内容表信息,因为我不认为我可以继续格式化评论...现在写... – Kivus 2008-10-17 19:48:20

0

如果你有“甲骨文,完整的参考”题为神色一节,“打开一个表在其一侧”。这给出了执行枢纽的详细示例和说明,尽管我拥有的版本并没有将它称为支点。

“旋转桌子”的另一个术语是交叉制表。

用于执行交叉制表的最简单的工具之一是MS Access。如果你有MS Access,并且你可以建立一个从Access数据库到你的源表的链接,你已经到了一半了。

此时,您可以启动“查询向导”,并要求它为您构建交叉表查询。它真的像回答向导问你的问题一样简单。这个解决方案的不幸的一面是,如果在SQL视图中查看生成的查询,您会看到SQL的Access方言特有的一些SQL,并且通常不能在其他平台上使用。

您也可以从Oracle网站下载一些简单的分析工具,然后使用其中一种工具为您执行交叉制订。

再一次,如果你真的想用SQL来做,“Oracle,Complete Reference”应该可以帮到你。

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重复子查询。

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或应用程序代码中更简单地获取数据并重新格式化可能更容易。

2

比尔Karwin提到这一点,但我认为这值得指出的很清楚:

SQL不会做你问什么,所以任何“解决方案”你得到的是将是一个杂牌。

如果您知道,可以肯定,它总是会在Oracle 10运行,那么肯定的是,沃尔特·米蒂的交叉表可能做到这一点。正确的做法是在查询和应用程序代码中使用最简单的排序顺序组合来正确布置它。

  • 它适用于其它的数据库系统,
  • 它不会冒任何其他层crapping出来(我记得有与> 255列,例如一个问题的MySQL,你确定你接口库作为COPES以及数据库本身?)
  • 它(通常)并不那么难。

如果需要,你可以索要Content_Row_ID第一个,然后问你需要什么行,由CampaignIDContentRowID有序的,这将让你在左到右各(填充)细胞,逐行命令。


Ps。

有一堆东西,现代人认为SQL应该有/做的只是不存在。这是一个,生成的范围是另一个,递归闭包,参数ORDER BY,标准化编程语言......这个列表继续。 (虽然,有一个技巧ORDER BY

1

比尔卡尔文和安德斯Eurenius是正确的,没有解决方案是直接的,也没有任何解决方案时,所产生的列值的数量是不知道的。 Oracle 11g在某种程度上可以用the PIVOT operator来简化它,但这些列仍然需要事先知道,并且不符合您的问题的10g标准。

0

如果你不知道列数了前面只是带回一个普通的SQL查询,并使用服务器端代码像我这里列出:Filling Datagrid And Sql Query

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