我遇到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应用程序中调用此过程?
答案 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
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
任意类匹配等,如果需要。