【问题标题】:Oracle SQL Developer - Pivot table without aggregation function [duplicate]Oracle SQL Developer - 没有聚合函数的数据透视表[重复]
【发布时间】:2018-11-27 17:41:10
【问题描述】:

我有下表(从现实中简化)。

 | ID | String_AttributeName | String_AttributeValue | Int_AttributeName | Int_AttributeValue |
 |----|----------------------|-----------------------|-------------------|--------------------|
 | 1  | Name                 | Object1               |                   |                    |
 | 1  | (null)               | (null)                | Age               | 5                  |
 | 2  | Name                 | Object2               |                   |                    |
 | 2  | Location             | Canada                | (null)            | (null)             |
 | 2  | (null)               | (null)                | Quantity          | 2                  |
 | 3  | Name                 | Object3               |                   |                    |
 | 3  | (null)               | (null)                | Age               | 3                  |
 | 3  | (null)               | (null)                | Quantity          | 4                  |

基本上,我有多个项目(由 ID 列区分)在表中由 4 个属性列描述。

它的工作方式是,对于每个AttributeName 列,都有一个值,由AttributeValue 列表示。每个属性根据其类型进行分隔(有string、int、bool等。为了简化问题,我只显示2个)。

当我说AttributeName 时,它表示第 2 列或第 4 列。每个项目(ID 列)用多行描述,其中每一行可能只包含 一个 属性(另一个将为空)。因此,同一行中可能没有 2 个AttributeName。此外,并非所有对象都具有所有现有属性(ID 3 具有所有属性,而 1 和 2 没有);但是,在任一类型的 AttributeName 中执行 DISTINCT SELECT 将选择每个 AttributeName 可能性

我的目标如下(解释如下):

+----+---------+--------+----------+
| ID | Name    | Age    | Quantity |
+----+---------+--------+----------+
| 1  | Object1 | 5      | (null)   |
+----+---------+--------+----------+
| 2  | Object2 | (null) | 2        |
+----+---------+--------+----------+
| 3  | Object3 | 3      | 4        |
+----+---------+--------+----------+

如您所见,我希望每个属性,无论其类型(int、string 等)是一列,并且结果位于每个项目的相应行中。此外,有超过 50 种不同的属性,它们会随着时间而变化,因此动态变化的属性是最好的。

我已经尝试过PIVOT 函数,但是,首先,我认为它不会起作用,因为没有聚合,其次,我不想要一个空列。我的查询也不起作用,因为有一个"missing expression"

这里是:

SELECT  *
FROM   
(
    SELECT  ID
            ,STRING_ATTRIBUTENAME
    FROM    PIVOTTABLE
)
PIVOT
(
    COUNT(STRING_ATTRIBUTENAME)
    FOR STRING_ATTRIBUTENAME IN (SELECT DISTINCT PIVOTTABLE.STRING_ATTRIBUTENAME     FROM PIVOTTABLE)
)
ORDER BY PARTNUMBER; 

我上次做SQL开发已经有一段时间了(我以前做过SQL Server),所以有点生疏。我只是不知道还有什么可以尝试的,我目前正在寻找是否有办法通过选择 AttributeName 列来执行一些动态 SQL。

任何线索也会有所帮助。谢谢!

------------ 这是重新创建起始表:

CREATE TABLE PIVOTTABLE 
(
  ID NUMBER NOT NULL 
, STRING_ATTRIBUTENAME VARCHAR2(50) 
, STRING_ATTRIBUTEVALUE VARCHAR2(50) 
, INT_ATTRIBUTENAME VARCHAR2(50) 
, INT_ATTRIBUTEVALUE NUMBER 
);

INSERT INTO TestTable VALUES('1','Name','Object1','','')
INSERT INTO TestTable VALUES('1','','','Age','5')
INSERT INTO TestTable VALUES('2','Name','Object2','','')
INSERT INTO TestTable VALUES('2','','','Quantity','2')
INSERT INTO TestTable VALUES('3','Name','Object3','','')
INSERT INTO TestTable VALUES('3','','','Age','3')
INSERT INTO TestTable VALUES('3','','','Quantity','4')

【问题讨论】:

  • 这是可怕的实体-属性-值反模式。如果您正在开发的这个系统尚未投入生产,请停止并认真考虑重新设计它。您正在处理大量过于复杂的查询、有限的引用完整性和糟糕的性能。如果您已经提交,请参阅此链接以获取使用 Oracle 数据盒接口的动态 pivot 函数。我已经在生产环境中使用它并且效果很好。
  • @Matthew McPeak :您忘记包含链接了?我希望看到它:-)
  • 对不起。这里:technology.amis.nl/2006/05/24/…
  • 很遗憾,我刚开始在这里工作,这个系统已经深入实施,所以没有办法躲避它。感谢您的链接,如果它有效,我将提供更多信息。谢谢!

标签: sql oracle pivot


【解决方案1】:

这是使用conditional aggregation的一个选项:

select id, 
       max(case when string_attributename = 'Name' then string_attributevalue end) as Name,
       max(case when int_attributename = 'Age' then int_attributevalue end) as Age,
       max(case when int_attributename = 'Quantity' then int_attributevalue end) as Quantity
from pivottable
group by id 

【讨论】:

  • 我想到了,但属性有很多可能性(大约 50 个),它们可能会或可能不会随时间变化。这就是为什么我正在研究使用SELECT DISTINCT 来设置列的动态查询。但是,我将添加一个事实,即真实案例中有许多属性到问题中。谢谢!
【解决方案2】:

使用 PL/SQL 和动态查询 -

CREATE OR REPLACE PROCEDURE TMP_C(P OUT SYS_REFCURSOR)AS
    QRY VARCHAR2(1024) := 'SELECT ID ';
    C SYS_REFCURSOR;

BEGIN

FOR R IN (SELECT DISTINCT STRING_ATTRIBUTENAME FROM (
            SELECT ID, STRING_ATTRIBUTENAME, STRING_ATTRIBUTEVALUE
            FROM TABLE1
            WHERE STRING_ATTRIBUTENAME IS NOT NULL
            UNION
            SELECT ID, INT_ATTRIBUTENAME, INT_ATTRIBUTEVALUE
            FROM TABLE1
            WHERE INT_ATTRIBUTENAME IS NOT NULL))
LOOP
    QRY := QRY ||REPLACE(', MAX(DECODE(STRING_ATTRIBUTENAME,''$X'',STRING_ATTRIBUTEVALUE)) AS $X '
                       ,'$X',R.STRING_ATTRIBUTENAME );

END LOOP;
QRY := QRY ||' FROM ((
SELECT ID, STRING_ATTRIBUTENAME, STRING_ATTRIBUTEVALUE
FROM TABLE1
WHERE STRING_ATTRIBUTENAME IS NOT NULL
UNION
SELECT ID, INT_ATTRIBUTENAME, INT_ATTRIBUTEVALUE
FROM TABLE1
WHERE INT_ATTRIBUTENAME IS NOT NULL)) GROUP BY ID ';

OPEN P FOR QRY;

END;
/

执行 -

SQL> variable x refcursor
SQL> exec tmp_c(:x);

PL/SQL procedure successfully completed.

SQL> print x

        ID QUANTIT LOCATIO AGE     NAME
---------- ------- ------- ------- -------
         1                 5       Object1
         2 2       Canada          Object2
         3 4               3       Object3

SQL>

【讨论】:

  • 编译时出现以下错误:1- 7/11 PL/SQL: SQL Statement ignored 2- 8/46 PL/SQL: ORA-01790: expression must have same datatype as corresponding expression 3- 16/5 PL/SQL: Statement ignored 4- 17/30 PLS-00364: loop index variable 'R' use is invalid
  • 好吧,我通过将 INT_ATTRIBUTEVALUE 转换为 varchar2(50) 来修复它。应该可以,非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多