我正在尝试从几个数据库表生成报告。简化版本看起来像这样

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 数据库...

有什么建议么?

有帮助吗?

解决方案

这是我第一次尝试。一旦我对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'

其他提示

Bill Karwin提到了这一点,但我认为这一点值得非常明确地指出:

SQL 不能满足您的要求,因此您获得的任何“解决方案”都将是一个拼凑的结果。

如果你 知道, ,当然,它总是会在 Oracle 10 上运行,那么当然,Walter Mitty 的交叉表可能会做到这一点。正确的方法是在查询和应用程序代码中使用最简单的排序顺序组合,以正确布局。

  • 它适用于其他数据库系统,
  • 它不会带来任何其他层崩溃的风险(例如,我记得 MySQL 在 >255 列时遇到问题。你确定你 接口库 以及数据库本身也能应对?)
  • (通常)没那么难。

如果您需要的话,您可以直接询问 Content_Row_ID首先,然后询问您需要的任何行,排序依据 CampaignID, ContentRowID, ,这将为您提供从左到右、逐行顺序的每个(填充的)单元格。


诗。

有很多现代人认为 SQL 应该拥有/做的事情实际上并不存在。这是一个,生成范围是另一个,递归闭包,参数化 ORDER BY, ,标准化编程语言...这样的例子不胜枚举。(不过,无可否认,有一个技巧 ORDER BY)

如果您没有动态列数且数据集不是太大,则可以执行此操作...

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

要在标准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或应用程序代码中重新格式化它可能更容易。

Bill Karwin和Anders Eurenius是正确的,没有任何解决方案是直截了当的,当预先不知道结果列值的数量时,也没有任何解决方案。 Oracle 11g使用 PIVOT运算符,但是这些列仍然必须提前知道,并且不符合您问题的10g标准。

如果您需要动态数量的列,我不相信这可以在标准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

如果你有“Oracle,完整参考资料”,寻找一个标题为“在桌子旁边转动桌子”的部分。这给出了执行数据透视的详细示例和说明,尽管我的版本并没有将其称为支点。

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

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

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

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

再次,如果你真的想在SQL中使用“Oracle,完整参考”,那么应该帮助你。

如果你不知道前面的列数,只需带回正常的sql查询并使用我在此处列出的服务器端代码:填充Datagrid和Sql查询

我用这个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
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top