英文:
PIVOT on TEXT Columns
问题
以下是我的SQL,如下所示。我想要按照计量器名称将OBSERVATION逐个转换为不同的列。由于OBSERVATION是文本字段,因此如果我写MIN(OBSERVATION),它会返回为空。
with x as (select '1000257' as ASSET_NUMBER,'GOOD' AS OBSERVATION,'CBMO_ASSESSMENT' AS METER_NAME from dual
UNION ALL
SELECT '1010257' AS ASSET_NUMBER,'BAD' AS OBSERVATION, 'SF6B_ASSESSMENT' as METER_NAME from dual
)
select METER_NAME_1_OBSERVATION,METER_NAME_2_OBSERVATION from x
PIVOT(
MIN(OBSERVATION) AS OBSERVATION
for METER_NAME in
(
'CBMO_ASSESSMENT' AS METER_NAME_1 , 'SF6B_ASSESSMENT' AS METER_NAME_2
)
)
我想要的输出如下所示。
如何实现这一点,因为我无法在文本字段上进行PIVOT MIN(OBSERVATION)。
我希望将此添加为1行而不是2行,因为对于相同的资产,我希望将其显示为1行而不是2行。
感谢您在以下问题上的帮助。
亲切的问候,
我想要将文本字段旋转到不同的列中,但返回为空记录。如何实现这一点,先生,因为它返回为空记录。
感谢您的帮助,先生?
英文:
The below is my SQL as shown below. I wanted to pivot OBSERVATION meter wise into different column. As OBSERVATION is text field Hence if I write MIN(OBSERVATION) it returns as a null.
with x as (select '1000257' as ASSET_NUMBER,'GOOD' AS OBSERVATION,'CBMO_ASSESSMENT' AS METER_NAME from dual
UNION ALL
SELECT '1010257' AS ASSET_NUMBER,'BAD' AS OBSERVATION, 'SF6B_ASSESSMENT' as METER_NAME from dual
)
select METER_NAME_1_OBSERVATION,METER_NAME_2_OBSERVATION from x
PIVOT(
MIN(OBSERVATION) AS OBSERVATION
for METER_NAME in
(
'CBMO_ASSESSMENT' AS METER_NAME_1 , 'SF6B_ASSESSMENT' AS METER_NAME_2
)
)
I wanted output as shown below
enter image description here
How can I achieve this as I am not able to PIVOT MIN(OBSERVATION) on a text field.
I wanted this to be added in 1 line instead of 2 lines as for the same asset. I wanted this to only show in 1 line instead of 2 lines.
Appreciate your help on the below.
KInd Regards,
I wanted to pivot a text field into a different column but returning as a null record . How can i achieve this sir as it is returning a null record.
Appreciate your help sir ?
答案1
得分: 1
你可以通过添加PROJECTION
信息来检查执行计划,该信息将显示数据库在每个步骤中请求的表达式是什么。
select *
from dbms_xplan.display_cursor(
format => '+PROJECTION +ALIAS'
)
正如你所看到的,HASH GROUP BY
操作(计划行 = 1)请求了三个表达式:一个常规列和两个PIVOT
列(也展示了如何在没有PIVOT
的情况下执行)。
"X"."ASSET_NUMBER"
MIN(CASE WHEN (INTERNAL_FUNCTION("METER_NAME")='CBMO_ASSESSMENT') THEN "OBSERVATION" END)
MIN(CASE WHEN (INTERNAL_FUNCTION("METER_NAME")='SF6B_ASSESSMENT') THEN "OBSERVATION" END)
ASSET_NUMBER
列在这两行中不同,但只要它没有被投影出来,输出可能会令人困惑。然而,这是文档化的:
> 相反,pivot_clause
执行一个隐式的 GROUP BY
。隐式分组基于pivot_clause
中未引用的所有列,以及在pivot_in_clause
中指定的值集合。
所以要获得你想要的结果,你可以选择以下方式之一:
- 使用子查询来减少
PIVOT
的输入列并仅保留所需列。
select meter_name_1_observation, meter_name_2_observation
from (
select observation, meter_name
from x
) x
pivot(
min(observation) as observation
for meter_name in (
'CBMO_ASSESSMENT' as meter_name_1 , 'SF6B_ASSESSMENT' as meter_name_2
)
)
- 通过显式
GROUP BY
使用aggregate_function(CASE WHEN pivot_in_col = 'EXPR' THEN pivot_for_col END)
手动构建PIVOT
表达式。
select
min(case meter_name when 'CBMO_ASSESSMENT' then observation end) as meter_name_1_observation,
min(case meter_name when 'SF6B_ASSESSMENT' then observation end) as meter_name_2_observation
from x
对于你的示例数据,这两种方法将返回相同的结果:
METER_NAME_1_OBSERVATION | METER_NAME_2_OBSERVATION |
---|---|
GOOD | BAD |
英文:
You may check the execution plan with the PROJECTION
information added, which will show you what expressions were requested by the database at each step.
select *
from dbms_xplan.display_cursor(
format => '+PROJECTION +ALIAS'
)
PLAN_TABLE_OUTPUT
:-----------------
SQL_ID 804p20bcdahaj, child number 0
-------------------------------------
with x as (select '1000257' as ASSET_NUMBER,'GOOD' AS
OBSERVATION,'CBMO_ASSESSMENT' AS METER_NAME from dual UNION ALL SELECT
'1010257' AS ASSET_NUMBER,'BAD' AS OBSERVATION, 'SF6B_ASSESSMENT' as
METER_NAME from dual ) select METER_NAME_1_OBSERVATION,METER_NAME_2_OBSE
RVATION from x PIVOT( MIN(OBSERVATION) AS OBSERVATION for
METER_NAME in ( 'CBMO_ASSESSMENT' AS METER_NAME_1 ,
'SF6B_ASSESSMENT' AS METER_NAME_2 ) )
Plan hash value: 3479842717
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 5 (100)| |
| 1 | HASH GROUP BY PIVOT| | 2 | 60 | 5 (20)| 00:00:01 |
| 2 | VIEW | | 2 | 60 | 4 (0)| 00:00:01 |
| 3 | UNION-ALL | | 2 | | 4 (0)| 00:00:01 |
| 4 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 |
| 5 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$16C51A37
2 - SET$1 / "X"@"SEL$1"
3 - SET$1
4 - SEL$2 / "DUAL"@"SEL$2"
5 - SEL$3 / "DUAL"@"SEL$3"
Column Projection Information (identified by operation id):
-----------------------------------------------------------
1 - (#keys=1) "X"."ASSET_NUMBER"[CHARACTER,7], MIN(CASE WHEN
(INTERNAL_FUNCTION("METER_NAME")='CBMO_ASSESSMENT') THEN "OBSERVATION"
END )[4], MIN(CASE WHEN (INTERNAL_FUNCTION("METER_NAME")='SF6B_ASSESSME
NT') THEN "OBSERVATION" END )[4]
2 - "X"."ASSET_NUMBER"[CHARACTER,7], "OBSERVATION"[VARCHAR2,4],
"METER_NAME"[CHARACTER,15]
3 - STRDEF[7], STRDEF[4], STRDEF[15]
As you may see, HASH GROUP BY
operation (plan line = 1) requests three expressions: one regular column and two PIVOT
ed columns (which also shows how to do it without PIVOT
).
"X"."ASSET_NUMBER"
MIN(CASE WHEN (INTERNAL_FUNCTION("METER_NAME")='CBMO_ASSESSMENT') THEN "OBSERVATION" END)
MIN(CASE WHEN (INTERNAL_FUNCTION("METER_NAME")='SF6B_ASSESSMENT') THEN "OBSERVATION" END)
ASSET_NUMBER
column is different for these two rows, but as long as it is not projected, the output may be confusing. However, this is documented:
> Instead, the pivot_clause
performs an implicit GROUP BY
. The implicit grouping is based on all the columns not referred to in the pivot_clause
, along with the set of values specified in the pivot_in_clause
.
So to get what you want, you may either:
- Use subquery to reduce input columns for
PIVOT
and keep only required ones.
select meter_name_1_observation,meter_name_2_observation
from (
select observation, meter_name
from x
) x
pivot(
min(observation) as observation
for meter_name in (
'CBMO_ASSESSMENT' as meter_name_1 , 'SF6B_ASSESSMENT' as meter_name_2
)
)
- Build
PIVOT
expressions manually viaaggregate_function(CASE WHEN pivot_in_col = 'EXPR' THEN pivot_for_col END)
with explicitGROUP BY
.
select
min(case meter_name when 'CBMO_ASSESSMENT' then observation end) as meter_name_1_observation,
min(case meter_name when 'SF6B_ASSESSMENT' then observation end) as meter_name_2_observation
from x
Both will return the same result for your sample data:
METER_NAME_1_OBSERVATION | METER_NAME_2_OBSERVATION |
---|---|
GOOD | BAD |
答案2
得分: 0
这是因为 ASSET_NUMBER
值不同(1000257 和 1010257)。
如果它们相同,您将得到您想要的结果:
SQL> WITH
2 x
3 AS
4 (SELECT '1010257' AS asset_number, --> 相同 ...
5 'GOOD' AS observation,
6 'CBMO_ASSESSMENT' AS meter_name
7 FROM DUAL
8 UNION ALL
9 SELECT '1010257' AS asset_number, --> ... ASSET_NUMBER 值相同!
10 'BAD' AS observation,
11 'SF6B_ASSESSMENT' AS meter_name
12 FROM DUAL)
13 SELECT asset_number, METER_NAME_1_OBSERVATION, METER_NAME_2_OBSERVATION
14 FROM x
15 PIVOT (MIN (OBSERVATION) AS OBSERVATION
16 FOR METER_NAME
17 IN ('CBMO_ASSESSMENT' AS METER_NAME_1, 'SF6B_ASSESSMENT' AS METER_NAME_2));
ASSET_N METE METE
------- ---- ----
1010257 GOOD BAD
SQL>;
另一种选项(条件聚合):
13 SELECT asset_number,
14 MAX (CASE WHEN meter_name = 'CBMO_ASSESSMENT' THEN observation END) meter_1,
15 MAX (CASE WHEN meter_name = 'SF6B_ASSESSMENT' THEN observation END) meter_2
16 FROM x
17 GROUP BY asset_number;
ASSET_N METE METE
------- ---- ----
1010257 GOOD BAD
SQL>;
英文:
That's because ASSET_NUMBER
values are different (1000257 and 1010257).
If they were the same, you'd get what you want:
SQL> WITH
2 x
3 AS
4 (SELECT '1010257' AS asset_number, --> same ...
5 'GOOD' AS observation,
6 'CBMO_ASSESSMENT' AS meter_name
7 FROM DUAL
8 UNION ALL
9 SELECT '1010257' AS asset_number, --> ... ASSET_NUMBER values!
10 'BAD' AS observation,
11 'SF6B_ASSESSMENT' AS meter_name
12 FROM DUAL)
13 SELECT asset_number, METER_NAME_1_OBSERVATION, METER_NAME_2_OBSERVATION
14 FROM x
15 PIVOT (MIN (OBSERVATION) AS OBSERVATION
16 FOR METER_NAME
17 IN ('CBMO_ASSESSMENT' AS METER_NAME_1, 'SF6B_ASSESSMENT' AS METER_NAME_2));
ASSET_N METE METE
------- ---- ----
1010257 GOOD BAD
SQL>
Another option (conditional aggregation):
<snip>
13 SELECT asset_number,
14 MAX (CASE WHEN meter_name = 'CBMO_ASSESSMENT' THEN observation END) meter_1,
15 MAX (CASE WHEN meter_name = 'SF6B_ASSESSMENT' THEN observation END) meter_2
16 FROM x
17 GROUP BY asset_number;
ASSET_N METE METE
------- ---- ----
1010257 GOOD BAD
SQL>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论