[英]Converting SQL Select Query to PL/SQL Anonymous Block (ORACLE)
我已经编写了一个标准的SQL Select查询来选择其中销售量最大的邮政编码。 现在,我需要将其转换为匿名PL / SQL块,但是我对PL / SQL仍然很“绿色”,对于如何完成此操作确实没有太多想法。 另外,我需要将LIMIT合并到PL / SQL匿名块中,该块仅在出现领带时显示最低的邮政编码。
这是带有一些数据的表:
CREATE TABLE CUSTOMERS
(customerID INT PRIMARY KEY,
customerZip VARCHAR(15) NOT NULL);
CREATE TABLE SALES
(saleID INT PRIMARY KEY,
customerID INT,
CONSTRAINT SALES_FK1 FOREIGN KEY (customerID) REFERENCES CUSTOMERS(customerID));
INSERT INTO CUSTOMERS (customerID, customerZIP) VALUES (1, '20636');
INSERT INTO CUSTOMERS (customerID, customerZIP) VALUES (2, '20619');
INSERT INTO CUSTOMERS (customerID, customerZIP) VALUES (3, '20670');
INSERT INTO CUSTOMERS (customerID, customerZIP) VALUES (4, '20670');
INSERT INTO CUSTOMERS (customerID, customerZIP) VALUES (5, '20636');
INSERT INTO SALES (saleID, customerID) VALUES (1, 1);
INSERT INTO SALES (saleID, customerID) VALUES (2, 2);
INSERT INTO SALES (saleID, customerID) VALUES (3, 3);
INSERT INTO SALES (saleID, customerID) VALUES (4, 4);
INSERT INTO SALES (saleID, customerID) VALUES (5, 5);
这是我编写的SQL查询:
SELECT C.customerZip, COUNT (*) AS "MOST_SALES_byZIP"
FROM SALES S
INNER JOIN CUSTOMERS C
ON S.customerID = C.customerID
GROUP BY C.customerZip
HAVING COUNT (*) >= ALL
(SELECT COUNT(*)
FROM SALES S
INNER JOIN CUSTOMERS C
ON S.customerID = C.customerID
GROUP BY C.customerZip)
ORDER BY C.customerZip;
基本上,我首先需要知道如何将其“转换”为PL / SQL匿名块。 然后,我需要知道如何限制结果,以仅在两个或多个之间存在联系时才显示最低的邮政编码。
如果有帮助,我在此处构建了一个SQL提琴模式: http : //sqlfiddle.com/#!4/ca18bf/2
谢谢!
好的PL / SQL编程中有80%是好的SQL编码。
您遇到的问题:首先,在SQL中,要从与大多数销售额相关的数字中选择最低的数字邮政编码,您可以进行联接,然后像以前一样通过邮政编码进行聚合-然后使用聚合LAST函数。 像这样:
select min(customerzip) keep (dense_rank last order by count(*)) as selected_zip
from sales inner join customers using (customerid)
group by customerzip
;
SELECTED_ZIP
---------------
20636
现在,很容易在匿名块中使用它(如果有必要-无论出于何种原因)。 SET SERVEROUTPUT ON不属于PL / SQL代码; 它是接口程序的命令,用于指示它在屏幕上显示输出缓冲区的内容。
set serveroutput on
declare
selected_zip integer;
begin
select min(customerzip) keep (dense_rank last order by count(*))
INTO selected_zip -- this is the PL/SQL part!
from sales inner join customers using (customerid)
group by customerzip
;
dbms_output.put_line('Selected zip is: ' || selected_zip);
end;
/
PL/SQL procedure successfully completed.
Selected zip is: 20636
这是一个选择。 创建一个函数,因为匿名块只能打印到STDOUT,它不能将某些内容返回到变量中
Haveing子句被删除,只需按count,zip排序即可,这样就可以按顺序赢取top count,然后再进行top count + top zip的排序。 在fetch first 1 rows ONLY
添加仅仅获取1行,然后从函数中将其返回。
SQL> CREATE OR REPLACE FUNCTION getlowest RETURN NUMBER AS
l_ret NUMBER;
BEGIN
FOR r IN (
SELECT
c.customerzip,
COUNT(*) AS "MOST_SALES_byZIP"
FROM
sales s
INNER JOIN customers c ON s.customerid = c.customerid
GROUP BY
c.customerzip
order by
COUNT(*), c.customerzip
fetch first 1 rows ONLY
) LOOP
l_ret := r.customerzip;
END LOOP;
RETURN l_ret;
END;
/
SQL> show errors;
SQL>
SQL> select getlowest from dual
2 /
20619
SQL>
如果目标是返回结果集,那么执行该操作的PL / SQL块将是
-- [Declare the host ref cursor according to the calling tool/language]
-- e.g. in SQL*Plus
var resultset refcursor
begin
open :resultset for
select c.customerzip, count(*) as most_sales_byzip
from sales s
join customers c on s.customerid = c.customerid
group by c.customerzip
having count(*) >= all
( select count(*) from sales s
join customers c on s.customerid = c.customerid
group by c.customerzip )
order by c.customerzip;
end;
从Oracle 12.1开始,您可以使用隐式结果集 :
declare
rc sys_refcursor;
begin
open rc for
open :resultset for
select c.customerzip, count(*) as most_sales_byzip
from sales s
join customers c on s.customerid = c.customerid
group by c.customerzip
having count(*) >= all
( select count(*) from sales s
join customers c on s.customerid = c.customerid
group by c.customerzip )
order by c.customerzip;
dbms_sql.return_result(rc);
end;
但是,我们已经有SQL可以执行此操作,因此似乎没有意义。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.