过程过滤视图并提供新视图

时间:2017-06-10 10:09:17

标签: oracle stored-procedures

我遇到PL / SQL问题。我想要一个程序或功能(我不知道在这种情况下哪个更好),这在调用后会给我一个来自另一个视图的过滤视图。

视图:( Regal = shelf,Lager =仓库)

 SELECT p.produkt_id, p.NAME AS produktname, p.typ, r.NAME AS regalname, l.NAME AS lagername
FROM produkt p, regal r, lager l, lagerort_produkt p2
WHERE p2.produkt_id = p.produkt_id
AND r.regal_id = p2.regal_id
AND l.lager_id = r.lager_id
ORDER BY p.produkt_id DESC

这是我的程序,它给了我ORA-01422& ORA-06512错误:

create or replace PROCEDURE PROZ_FILTER_VIEW (
pid IN INTEGER,
pname IN varchar2,
ptyp IN varchar2,
pregal IN varchar2,
plager IN varchar2
) 
IS
tablout view_produktlist%ROWTYPE;
BEGIN
    SELECT PRODUKT_ID, PRODUKTNAME, TYP, REGALNAME, LAGERNAME 
    INTO tablout
    FROM view_produktlist
    WHERE TO_CHAR(produkt_id) LIKE '%'||PID||'%'
    AND produktname LIKE '%'||PNAME||'%'
    AND typ LIKE '%'||PTYP||'%'
    AND regalname LIKE '%'||PREGAL||'%'
    AND lagername LIKE '%'||PLAGER||'%';
END PROZ_FILTER_VIEW;

如果变量为空,该怎么办?这仍然适用于" '%' || PID ||'%' &#34 ;? 我应该添加什么才能获得此过滤后的视图?

是否可以从绑定的Java应用程序中调用此过程?

1 个答案:

答案 0 :(得分:0)

您提供的程序接近功能,只有一些事情在当前状态下停止它。

我将在下面的示例中进行一些调整,以获得将返回过滤数据的内容。要了解有关PROCEDURE vs FUNCTION的第一个问题,对于此类操作,我建议不要使用PROCEDURE

在下面的这个例子中,我将使用TABLE FUNCTION这种函数可以在java app中的JDBC中调用,并且可以根据需要使用绑定变量,ORM附件等。

我将在示例结尾处包含一些有希望得到关于NULL的问题的数据。

首先创建表格:

CREATE TABLE PRODUKT(PRODUKT_ID NUMBER PRIMARY KEY, NAME VARCHAR2(64), TYP VARCHAR2(64));
CREATE TABLE LAGER(LAGER_ID NUMBER PRIMARY KEY , NAME VARCHAR2(64));
CREATE TABLE REGAL(REGAL_ID NUMBER PRIMARY KEY , LAGER_ID NUMBER REFERENCES LAGER, NAME VARCHAR2(64));
CREATE TABLE LAGERORT_PRODUKT(PRODUKT_ID NUMBER REFERENCES PRODUKT, REGAL_ID NUMBER REFERENCES REGAL);

然后加载一些数据。在这个数据集中,我们将在行之间有一些共享的单词,因此我们可以搜索类似的项目。 (我不知道什么会导致REGAL名称,因此只使用了一些占位符地理名称)

INSERT INTO PRODUKT VALUES (1,'Walkman','Electronics');
INSERT INTO PRODUKT VALUES (2,'Discman','Electronics');
INSERT INTO PRODUKT VALUES (3,'MiniDisc','Electronics');
INSERT INTO PRODUKT VALUES (4,'Tennis Racquet','Sporting Goods');
INSERT INTO PRODUKT VALUES (5,'Squash Racquet','Sporting Goods');
INSERT INTO PRODUKT VALUES (6,'Tennis Ball','Sporting Goods');
INSERT INTO PRODUKT VALUES (7,'Squash Ball','Sporting Goods');

INSERT INTO LAGER VALUES (1, 'North Warehouse');
INSERT INTO LAGER VALUES (2, 'East Warehouse');
INSERT INTO LAGER VALUES (3, 'South Warehouse');
INSERT INTO LAGER VALUES (4, 'West Warehouse');

INSERT INTO REGAL VALUES (1,1,'Bratislava');
INSERT INTO REGAL VALUES (2,1,'Brinstar');
INSERT INTO REGAL VALUES (3,1,'Norfair');
INSERT INTO REGAL VALUES (4,2,'Jeju');
INSERT INTO REGAL VALUES (5,2,'Hokkaido');
INSERT INTO REGAL VALUES (6,3,'Sakhalin');
INSERT INTO REGAL VALUES (7,3,'Svalbard');
INSERT INTO REGAL VALUES (8,4,'Hammerfest');

INSERT INTO LAGERORT_PRODUKT VALUES (1,1);
INSERT INTO LAGERORT_PRODUKT VALUES (1,2);
INSERT INTO LAGERORT_PRODUKT VALUES (1,5);
INSERT INTO LAGERORT_PRODUKT VALUES (2,1);
INSERT INTO LAGERORT_PRODUKT VALUES (2,3);
INSERT INTO LAGERORT_PRODUKT VALUES (2,7);
INSERT INTO LAGERORT_PRODUKT VALUES (3,4);
INSERT INTO LAGERORT_PRODUKT VALUES (3,3);
INSERT INTO LAGERORT_PRODUKT VALUES (4,7);
INSERT INTO LAGERORT_PRODUKT VALUES (4,8);
INSERT INTO LAGERORT_PRODUKT VALUES (5,1);
INSERT INTO LAGERORT_PRODUKT VALUES (5,2);
INSERT INTO LAGERORT_PRODUKT VALUES (6,6);
INSERT INTO LAGERORT_PRODUKT VALUES (6,8);

现在我们应该在不同PRODUKT s的多个REGAL中有多个LAGER

然后创建视图:

CREATE OR REPLACE VIEW VIEW_PRODUKTLIST
  AS
SELECT P.PRODUKT_ID, P.NAME AS PRODUKTNAME, P.TYP, R.NAME AS REGALNAME, L.NAME AS LAGERNAME
FROM PRODUKT P, REGAL R, LAGER L, LAGERORT_PRODUKT P2
WHERE P2.PRODUKT_ID = P.PRODUKT_ID
      AND R.REGAL_ID = P2.REGAL_ID
      AND L.LAGER_ID = R.LAGER_ID
ORDER BY P.PRODUKT_ID DESC;

测试一下:

SELECT * FROM VIEW_PRODUKTLIST FETCH FIRST 5 ROWS ONLY;

PRODUKT_ID  PRODUKTNAME     TYP             REGALNAME   LAGERNAME        
6           Tennis Ball     Sporting Goods  Hammerfest  West Warehouse   
6           Tennis Ball     Sporting Goods  Sakhalin    South Warehouse  
5           Squash Racquet  Sporting Goods  Bratislava  North Warehouse  
5           Squash Racquet  Sporting Goods  Brinstar    North Warehouse  
4           Tennis Racquet  Sporting Goods  Svalbard    South Warehouse  

现在我们可以测试我们的功能了。原始的PROCEDURE不会有几个原因:它试图选择一个单一记录类型的集合,这是不允许的,它没有办法返回选择的结果,甚至如果成功的话。

首先创建一个TYPE的返回COLLECTION,我们可以选择多个项目并将其返回。

CREATE OR REPLACE TYPE PRODUKT_VIEW_REC IS OBJECT(PRODUKT_ID NUMBER, PRODUKTNAME VARCHAR2(64), TYP VARCHAR2(64), REGALNAME VARCHAR2(64), LAGERNAME VARCHAR2(64));
/

CREATE OR REPLACE TYPE PRODUKT_VIEW_TAB IS TABLE OF PRODUKT_VIEW_REC;
/

然后是功能。我原来在这里改变了一点点;只需COLLECT然后RETURN新的TYPE

CREATE OR REPLACE FUNCTION PROZ_FILTER_VIEW(
  PID    IN INTEGER,
  PNAME  IN VARCHAR2,
  PTYP   IN VARCHAR2,
  PREGAL IN VARCHAR2,
  PLAGER IN VARCHAR2
)
  RETURN PRODUKT_VIEW_TAB
IS
  V_PRODUKT_VIEW_RESULT PRODUKT_VIEW_TAB;
  BEGIN
    V_PRODUKT_VIEW_RESULT := PRODUKT_VIEW_TAB();
    SELECT PRODUKT_VIEW_REC(
      PRODUKT_ID,
      PRODUKTNAME,
      TYP,
      REGALNAME,
      LAGERNAME)
    BULK COLLECT
    INTO V_PRODUKT_VIEW_RESULT
    FROM VIEW_PRODUKTLIST
    WHERE TO_CHAR(PRODUKT_ID) LIKE '%' || PID || '%'
          AND PRODUKTNAME LIKE '%' || PNAME || '%'
          AND TYP LIKE '%' || PTYP || '%'
          AND REGALNAME LIKE '%' || PREGAL || '%'
          AND LAGERNAME LIKE '%' || PLAGER || '%';
    RETURN V_PRODUKT_VIEW_RESULT;
  END PROZ_FILTER_VIEW;
/

Function PROZ_FILTER_VIEW compiled

现在我们可以测试一下。
首先,让我们非常狭隘地了解位于 North Warehouse {的 Bratislava PRODUKT中的 Squash Racquet REGAL {1}}(我们知道此记录存在,因为它出现在我们上面的视图中)

LAGER

结果:

SELECT * FROM TABLE(PROZ_FILTER_VIEW(5,'Squash Racquet','Sporting Goods','Bratislava','North Warehouse'));

现在让我们尝试通过提供部分名称来练习PRODUKT_ID PRODUKTNAME TYP REGALNAME LAGERNAME 5 Squash Racquet Sporting Goods Brinstar North Warehouse

LIKE

现在它与SELECT * FROM TABLE(PROZ_FILTER_VIEW(5,'Squash','Sporting','Brat','North')); 匹配以获得结果。

LIKE

Squash Racquet Tennis Racquet 是完全不同的PRODUKT_ID PRODUKTNAME TYP REGALNAME LAGERNAME 5 Squash Racquet Sporting Goods Bratislava North Warehouse s。要搜索任何类型的球拍,你确实可以依靠REGAL - 处理帮助。

在这里,我们只会在NULL

中搜索任何 Racquet
REGAL/LAGER/PRODUKT

返回包括所有壁球拍网球拍

SELECT * FROM TABLE(PROZ_FILTER_VIEW(NULL,'Racquet','Sporting',NULL,NULL));

如果您只是按PRODUKT_ID PRODUKTNAME TYP REGALNAME LAGERNAME 5 Squash Racquet Sporting Goods Bratislava North Warehouse 5 Squash Racquet Sporting Goods Brinstar North Warehouse 4 Tennis Racquet Sporting Goods Svalbard South Warehouse 4 Tennis Racquet Sporting Goods Hammerfest West Warehouse 搜索,那也可以:

PRODUKT_ID

希望这会引发关于SELECT * FROM TABLE(PROZ_FILTER_VIEW(5,NULL,NULL,NULL,NULL)); PRODUKT_ID PRODUKTNAME TYP REGALNAME LAGERNAME 5 Squash Racquet Sporting Goods Brinstar North Warehouse 5 Squash Racquet Sporting Goods Bratislava North Warehouse NULL的第二组问题。

总结一下,我还有其他一些建议:

  • 如上所述,这是区分大小写的,因此如下所示:

    LIKE

如果您不喜欢不区分大小写,可以考虑在SELECT * FROM TABLE(PROZ_FILTER_VIEW(NULL,'racquet',NULL,NULL,NULL));比较中UPPER

  • 您可以考虑使用可选参数。

  • 根据您的索引策略和数据量,这种具有大量LIKE的查询可能无法扩展,并且数据库成本高昂。我建议针对超大型测试数据集进行基准测试,并考虑LIKE索引,参数限制,重新考虑双TEXT任意类匹配等,如果需要。