我编写了一个标准的SQL Select Query来选择销售数量最多的邮政编码。我现在需要将它转换为一个匿名的PL / SQL块,但我仍然非常"绿色"使用PL / SQL并且对于如何实现这一点并不是很有想法。此外,我需要在PL / SQL匿名块中加入 LIMIT ,只有在平局时才会显示最低的数字邮政编码。
以下是带有一些数据的表格:
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
谢谢!
答案 0 :(得分:1)
80%的优秀PL / SQL编程都是很好的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
答案 1 :(得分:1)
这是一个选项。创建一个函数,因为匿名块只能打印到STDOUT,它不能将某些内容返回到变量中
has子句是删除,只需按计数,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>
答案 2 :(得分:0)
如果目标是返回结果集,那么执行该操作的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开始,您可以使用implicit result sets:
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来做这个,所以看起来有点没用。