Oracle SQL Developer-不带聚合函数的透视表
我有下表(根据实际情况简化) 基本上,我有多个项目(由Oracle SQL Developer-不带聚合函数的透视表,sql,oracle,pivot,Sql,Oracle,Pivot,我有下表(根据实际情况简化) 基本上,我有多个项目(由ID列区分),在表中由4个属性列描述 它的工作方式是,对于每个AttributeName列,都有一个值,由AttributeValue列表示。每个属性都根据其类型分开(有string、int、bool等。为了简化问题,我只显示2) 当我说AttributeName时,它的意思是第2列或第4列。每个项目(ID列)都在多行中描述,其中每行只能包含一个属性(另一个属性为空)。因此,同一行中可能没有2个AttributeName。此外,并非所有对象都
ID
列区分),在表中由4个属性列描述
它的工作方式是,对于每个AttributeName
列,都有一个值,由AttributeValue
列表示。每个属性都根据其类型分开(有string、int、bool等。为了简化问题,我只显示2)
当我说AttributeName
时,它的意思是第2列或第4列。每个项目(ID
列)都在多行中描述,其中每行只能包含一个属性(另一个属性为空)。因此,同一行中可能没有2个AttributeName
。此外,并非所有对象都具有所有现有属性(ID 3具有所有属性,而1和2不具有所有属性);但是,在任一类型的AttributeName
中执行DISTINCT SELECT
,将选择所有AttributeName
可能性
我的目标如下(解释如下):
如您所见,我希望每个属性,无论其类型(int、string等)如何,都是一列,并且结果位于每个项目的对应行中。此外,还有50多个不同的属性,它们可以随时间变化,因此动态变化的属性是最好的
我已经尝试了PIVOT
函数,但是,首先,我认为它不起作用,因为没有聚合,其次,我不想要空列。我的查询也不起作用,因为有一个“缺少表达式”
这是:
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')
这里有一个使用条件聚合的选项:
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
这里有一个使用条件聚合的选项:
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
使用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>
使用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>
我想到了这一点,但是属性有很多可能性(大约50个),它们可能会随着时间而改变,也可能不会。这就是为什么我要研究一个动态查询,使用
selectdistinct
来设置列。然而,我要补充一个事实,即在实际情况中,这个问题有许多属性。谢谢我想到了这一点,但是属性有很多可能性(大约50个),它们可能会随着时间而改变,也可能不会。这就是为什么我要研究一个动态查询,使用selectdistinct
来设置列。然而,我要补充一个事实,即在实际情况中,这个问题有许多属性。谢谢这是可怕的实体属性值反模式。如果您正在使用的系统尚未投入生产,请停止并认真考虑重新设计它。您将面临大量过于复杂的查询、有限的引用完整性和糟糕的性能。如果您已经提交,请参阅此链接,了解使用Oracle数据盒带接口的动态pivot
功能。我在生产中使用过它,效果很好。@Matthew McPeak:你忘了包括链接?我想看看:-)对不起。这里:可悲的是,我刚开始在这里工作,这个系统得到了深入的实施,所以没有办法回避它。谢谢你的链接,如果有用的话,我会提供更多的信息。谢谢这是可怕的实体属性值反模式。如果您正在使用的系统尚未投入生产,请停止并认真考虑重新设计它。您将面临大量过于复杂的查询、有限的引用完整性和糟糕的性能。如果您已经提交,请参阅此链接,了解使用Oracle数据盒带接口的动态pivot
功能。我在生产中使用过它,效果很好。@Matthew McPeak:你忘了包括链接?我想看看:-)对不起。这里:可悲的是,我刚开始在这里工作,这个系统得到了深入的实施,所以没有办法回避它。谢谢你的链接,如果有用的话,我会提供更多的信息。谢谢它编译时出现以下错误:1-7/11 PL/SQL:SQL语句被忽略
2-8/46 PL/SQL:ORA-01790:表达式必须与相应表达式具有相同的数据类型
3-16/5 PL/SQL:Statement被忽略
4-17/30 PLS-00364:循环索引变量“R”的使用是错误的无效
好吧,我通过将INT_ATTRIBUTEVALUE转换为varchar2(50)来修复它。那应该行,谢谢!它编译时出现以下错误:1-7/11 PL/SQL:SQL语句被忽略
2-8/46 PL/SQL:ORA-01790:表达式必须与相应表达式具有相同的数据类型
3-16/5 PL/SQL:Statement被忽略
4-17/30 PLS-00364:循环索引变量“R”的使用是错误的无效
好吧,我通过将INT_ATTRIBUTEVALUE转换为varchar2(50)来修复它。那应该行,谢谢!