将SQL Select查询转换为PL / SQL匿名块(ORACLE)

时间:2018-02-08 14:26:25

标签: oracle plsql

我编写了一个标准的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

谢谢!

3 个答案:

答案 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来做这个,所以看起来有点没用。