在我的情况下,如何在 Oracle 中编写 SQL?

Posted

技术标签:

【中文标题】在我的情况下,如何在 Oracle 中编写 SQL?【英文标题】:How can I write SQL in Oracle in my case? 【发布时间】:2015-11-23 06:07:36 【问题描述】:

所以,这里是表格-

create table person (
id number,
name varchar2(50)
);

create table injury_place (
id number,
place varchar2(50)
);

create table person_injuryPlace_map (
person_id number,
injury_id number
);

insert into person values (1, 'Adam');
insert into person values (2, 'Lohan');
insert into person values (3, 'Mary');
insert into person values (4, 'John');
insert into person values (5, 'Sam');


insert into injury_place values (1, 'kitchen');
insert into injury_place values (2, 'Washroom');
insert into injury_place values (3, 'Rooftop');
insert into injury_place values (4, 'Garden');


insert into person_injuryPlace_map values (1, 2);
insert into person_injuryPlace_map values (2, 3);
insert into person_injuryPlace_map values (1, 4);
insert into person_injuryPlace_map values (3, 2);
insert into person_injuryPlace_map values (4, 4);
insert into person_injuryPlace_map values (5, 2);
insert into person_injuryPlace_map values (1, 1);

这里,表 person_injuryPlace_map 只会映射其他两个表。

我想显示数据的方式是 -

Kitchen   Pct      Washroom   Pct     Rooftop   Pct     Garden   Pct
-----------------------------------------------------------------------
1         14.29%   3          42.86%   1        14.29%   2        28.57%

这里,Kitchen, Washroom, Rooftop, Garden column 的值是发生的事件总数。 Pct 列将显示占总数的百分比。

如何在 Oracle SQL 中执行此操作?

【问题讨论】:

很高兴看到有人提供创建和插入语句。 【参考方案1】:

您需要使用标准的PIVOT查询。

根据您的 Oracle 数据库版本,您可以通过两种方式进行:

PIVOT 用于 11g 版 及更高版本:

SQL> SELECT *
  2  FROM
  3    (SELECT c.place place,
  4      row_number() OVER(PARTITION BY c.place ORDER BY NULL) cnt,
  5      (row_number() OVER(PARTITION BY c.place ORDER BY NULL)/
  6      COUNT(place) OVER(ORDER BY NULL))*100 pct
  7    FROM person_injuryPlace_map A
  8    JOIN person b
  9    ON(A.person_id = b.ID)
 10    JOIN injury_place c
 11    ON(A.injury_id = c.ID)
 12    ORDER BY c.place
 13    ) PIVOT (MAX(cnt),
 14             MAX(pct) pct
 15             FOR (place) IN ('kitchen' AS kitchen,
 16                             'Washroom' AS Washroom,
 17                             'Rooftop' AS Rooftop,
 18                             'Garden' AS Garden));

   KITCHEN KITCHEN_PCT   WASHROOM WASHROOM_PCT    ROOFTOP ROOFTOP_PCT     GARDEN GARDEN_PCT
---------- ----------- ---------- ------------ ---------- ----------- ---------- ----------
         1  14.2857143          3   42.8571429          1  14.2857143          2 28.5714286

MAXDECODE 用于 10g 版 及之前的版本:

SQL> SELECT MAX(DECODE(t.place,'kitchen',cnt)) Kitchen ,
  2    MAX(DECODE(t.place,'kitchen',pct)) Pct ,
  3    MAX(DECODE(t.place,'Washroom',cnt)) Washroom ,
  4    MAX(DECODE(t.place,'Washroom',pct)) Pct ,
  5    MAX(DECODE(t.place,'Rooftop',cnt)) Rooftop ,
  6    MAX(DECODE(t.place,'Rooftop',pct)) Pct ,
  7    MAX(DECODE(t.place,'Garden',cnt)) Garden ,
  8    MAX(DECODE(t.place,'Garden',pct)) Pct
  9  FROM
 10    (SELECT b.ID bid,
 11      b.NAME NAME,
 12      c.ID cid,
 13      c.place place,
 14      row_number() OVER(PARTITION BY c.place ORDER BY NULL) cnt,
 15      ROUND((row_number() OVER(PARTITION BY c.place ORDER BY NULL)/
 16      COUNT(place) OVER(ORDER BY NULL))*100, 2) pct
 17    FROM person_injuryPlace_map A
 18    JOIN person b
 19    ON(A.person_id = b.ID)
 20    JOIN injury_place c
 21    ON(A.injury_id = c.ID)
 22    ORDER BY c.place
 23    ) t;

   KITCHEN        PCT   WASHROOM        PCT    ROOFTOP        PCT     GARDEN        PCT
---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
         1      14.29          3      42.86          1      14.29          2      28.57

【讨论】:

【参考方案2】:

如果您使用 Oracle 11g 或更高版本,您可以使用数据透视函数来获得所需的输出。

SELECT *
FROM (
    SELECT id
        ,place
        ,round((
                cnt / sum(cnt) OVER (
                    ORDER BY NULL
                    )
                ) * 100, 2) AS pct
    FROM (
        SELECT a.id
            ,a.place
            ,count(a.id) AS cnt
        FROM injury_place a
        JOIN person_injuryPlace_map b ON a.id = b.injury_id
        GROUP BY a.id
            ,a.place
        )
    )
pivot(max(id) , max(pct) pct FOR place IN (
            'kitchen' AS kitchen
            ,'Washroom' Washroom
            ,'Rooftop' Rooftop
            ,'Garden' Garden
            ))

【讨论】:

【参考方案3】:

您必须首先在子查询中获取 count 和 pct,然后使用 max+decode 函数以所需的方式汇总它们 检查以下查询是否有帮助:

SELECT Max(Decode(i.place,'Kitchen',cnt)) AS "Kitchecn"
     , Max(Decode(i.place,'Kitchen',pct)) AS "Pct"
     , Max(Decode(i.place,'Washroom',cnt)) AS "Washroom"
     , Max(Decode(i.place,'Washroom',pct)) AS "Pct"
     , Max(Decode(i.place,'Rooftop',cnt)) AS "Rooftop"
     , Max(Decode(i.place,'Rooftop',pct)) AS "Pct"
     , Max(Decode(i.place,'Garden',cnt)) AS "Garden"
     , Max(Decode(i.place,'Garden',pct)) AS "Pct"
  FROM (SELECT i.place
             , Count(pim.injury_id) AS cnt
             , (Count(pim.injury_id)*100/(SELECT Count(*) FROM person_injuryPlace_map)) AS pct 
          FROM person_injuryPlace_map pim
         INNER JOIN injury_place i ON i.id = pim.injury_id
         GROUP BY i.place)

【讨论】:

使用列别名时出现语法错误。使用单引号使其成为字符串,而不是别名。 谢谢两位。更正了语法。【参考方案4】:

我是这样做的 -

select a."kitchen"
, round((100/"Total")*a."kitchen") "Pct"
, a."Garden"
, round((100/"Total")*a."Garden") "Pct"
, a."Washroom"
, round((100/"Total")*a."Washroom") "Pct"
, a."Rooftop"
, round((100/"Total")*a."Rooftop") "Pct"
from 
(

select 
sum(decode(ip.place, 'kitchen', 1, 0)) "kitchen"
, sum(decode(ip.place, 'Garden', 1, 0)) "Garden"
, sum(decode(ip.place, 'Washroom', 1, 0)) "Washroom"
, sum(decode(ip.place, 'Rooftop', 1, 0)) "Rooftop"
, sum(decode(ip.place, 'kitchen', 1, 0))
+ sum(decode(ip.place, 'Garden', 1, 0))
+ sum(decode(ip.place, 'Washroom', 1, 0)) 
+ sum(decode(ip.place, 'Rooftop', 1, 0)) "Total"
from 
person p
join person_injuryPlace_map pim on pim.person_id = p.id
join injury_place ip on ip.id = pim.injury_id
) a

【讨论】:

以上是关于在我的情况下,如何在 Oracle 中编写 SQL?的主要内容,如果未能解决你的问题,请参考以下文章

在 Oracle 中生成动态 SQL

java.sql.SQLException: Io 异常: Broken pipe 如何在不重启的情况下恢复?

如何在不进行分组的情况下在Oracle中向SQL结果添加虚拟行

在我的情况下,如何编写自定义 CrudRepository 方法(@Query)来过滤结果

ORACLE 为啥在我的情况下,别名 COUNTER 是无效 ID,计数器 > 0?

如何在不使用 GROUP BY 或 PARTITION BY 的情况下对 Oracle SQL 中的数据进行分组