提高 pl/sql 的性能,想要对 Q1 的结果执行 Q2
CREATE or REPLACE PROCEDURE TEST(
activationStartDate IN DATE,
activationEndDate IN DATE,
deActivationStartDate IN DATE,
deActivationEndDate IN DATE
)
AS
FirstNameListTable LIST_TABLE;
{--COMMENT :LIST_TABLE is nested table :create or replace TYPE "LIST_TABLE" as table of varchar2(20);-----Nested Table Declaration
/
}
totalSameFirstName NUMBER;
j NUMBER := 1;
BEGIN
SELECT first_name BULK COLLECT INTO FirstNameListTable FROM Employee where start_date between activationStartDate AND activationEndDate
MINUS
SELECT first_name FROM Employee where start_date between deActivationStartDate AND deActivationEndDate
FOR i IN FirstNameListTable.FIRST .. FirstNameListTable.LAST LOOP
SELECT count(*) INTO totalSameFirstName FROM Employee where start_date between activationStartDate AND activationEndDate AND first_name=FirstNameListTable(i)
IF totalSameFirstName > 2 THEN
---business logic
END IF;
END LOOP;
实际上有两个查询,如上面提到的,
假设这个查询为 Q1:
SELECT first_name BULK COLLECT INTO FirstNameListTable FROM Employee where start_date between activationStartDate AND activationEndDate
MINUS
SELECT first_name FROM Employee where start_date between deActivationStartDate AND deActivationEndDate
这个查询为 Q2:
SELECT count(*) INTO totalSameFirstName FROM Employee where start_date between activationStartDate AND activationEndDate AND first_name=FirstNameListTable(i)
在这两个 qyery 中,我正在扫描完整的表,我认为没有必要。我正在迭代 Q1 的结果,然后再次扫描表以计算类似的名字。如果特定的名字出现两次以上,我会编写业务逻辑。
我可以组合这两个查询吗?意味着我想将 Q1 的结果存储在某些 PL/SQL 数据结构中,并希望对 Q1 的结果执行 Q2。
我想将 Q1 修改为
SELECT * BULK COLLECT INTO FirstNameListTable FROM Employee where start_date between activationStartDate AND activationEndDate
MINUS
SELECT * FROM Employee where start_date between deActivationStartDate AND deActivationEndDate
但是如何在 pl/sql dataStructure 中存储“select *”结果以及如何将这些记录传递给第二个查询..你能告诉我我的代码是什么样子吗? 试着说得更清楚,我在这个 PL/SQL 中缺乏想法,即使它听起来像一个经典:我花了几个小时尝试解决这个问题,但一无所获
@Ollie 我按照u的建议更改了代码,但出现了一些错误并且无法解决它们
CREATE or REPLACE PROCEDURE TEST(
activationStartDate IN DATE,
activationEndDate IN DATE,
deActivationStartDate IN DATE,
deActivationEndDate IN DATE,
Out_Entity OUT TEST1.RefCsr
)
AS
FirstNameListTable CRITERIA_LIST_TABLE;
out NUMBER;
j NUMBER := 1;
CURSOR main_cur
IS
WITH include_rec
AS (SELECT first_name,COUNT(1) OVER (PARTITION BY first_name) name_count FROM employee where start_date between activationStartDate AND activationEndDate
MINUS
SELECT first_name FROM employee where start_date between deActivationStartDate AND deActivationEndDate)
SELECT first_name FROM include_rec WHERE name_count > 2;
BEGIN
OPEN main_cur;
FETCH main_cur BULK COLLECT INTO FirstNameListTable;
CLOSE main_cur;
OPEN Out_Entity FOR SELECT * FROM TABLE(
CAST (
FirstNameListTable AS LIST_TABLE
)
) Nos;
END;
/
错误1:PL/SQL:SQL语句被忽略{指示:“WITH include_rec”行} 错误 2:PL/SQL:ORA-01789:查询块的结果列数不正确{指示行:“AS (SELECT first_name,COUNT(1) OVER (PARTITION BY first_name)”} 提前致谢 等待你的回复
CREATE or REPLACE PROCEDURE TEST(
activationStartDate IN DATE,
activationEndDate IN DATE,
deActivationStartDate IN DATE,
deActivationEndDate IN DATE
)
AS
FirstNameListTable LIST_TABLE;
{--COMMENT :LIST_TABLE is nested table :create or replace TYPE "LIST_TABLE" as table of varchar2(20);-----Nested Table Declaration
/
}
totalSameFirstName NUMBER;
j NUMBER := 1;
BEGIN
SELECT first_name BULK COLLECT INTO FirstNameListTable FROM Employee where start_date between activationStartDate AND activationEndDate
MINUS
SELECT first_name FROM Employee where start_date between deActivationStartDate AND deActivationEndDate
FOR i IN FirstNameListTable.FIRST .. FirstNameListTable.LAST LOOP
SELECT count(*) INTO totalSameFirstName FROM Employee where start_date between activationStartDate AND activationEndDate AND first_name=FirstNameListTable(i)
IF totalSameFirstName > 2 THEN
---business logic
END IF;
END LOOP;
Actually there are two queries as mensioned above
Letsay this query as Q1:
SELECT first_name BULK COLLECT INTO FirstNameListTable FROM Employee where start_date between activationStartDate AND activationEndDate
MINUS
SELECT first_name FROM Employee where start_date between deActivationStartDate AND deActivationEndDate
and this query as Q2 :
SELECT count(*) INTO totalSameFirstName FROM Employee where start_date between activationStartDate AND activationEndDate AND first_name=FirstNameListTable(i)
In both the qyery i am scanning complete table,which i think there is no need. I am iterating result of Q1 and then again scanning the table to count similar first_name. If a particular firstName occur more than two times i wrote business logic.
Can i combine both the queries,Means i want to store result of Q1 in some PL/SQL dataStructure and want to perform Q2 on result of Q1.
I want to modify Q1 as
SELECT * BULK COLLECT INTO FirstNameListTable FROM Employee where start_date between activationStartDate AND activationEndDate
MINUS
SELECT * FROM Employee where start_date between deActivationStartDate AND deActivationEndDate
But how to store 'select *' result in pl/sql dataStructure and How to pass these records to second query..Can u tell me how my code will look like?
try to be more clear, i'm in lack of ideas in this PL/SQL, even it sounds like a classic :I have spend hours trying to play around with this but have got nowhere
@Ollie
I changed the code as suggested by u but getting some error and not able to solve them
CREATE or REPLACE PROCEDURE TEST(
activationStartDate IN DATE,
activationEndDate IN DATE,
deActivationStartDate IN DATE,
deActivationEndDate IN DATE,
Out_Entity OUT TEST1.RefCsr
)
AS
FirstNameListTable CRITERIA_LIST_TABLE;
out NUMBER;
j NUMBER := 1;
CURSOR main_cur
IS
WITH include_rec
AS (SELECT first_name,COUNT(1) OVER (PARTITION BY first_name) name_count FROM employee where start_date between activationStartDate AND activationEndDate
MINUS
SELECT first_name FROM employee where start_date between deActivationStartDate AND deActivationEndDate)
SELECT first_name FROM include_rec WHERE name_count > 2;
BEGIN
OPEN main_cur;
FETCH main_cur BULK COLLECT INTO FirstNameListTable;
CLOSE main_cur;
OPEN Out_Entity FOR SELECT * FROM TABLE(
CAST (
FirstNameListTable AS LIST_TABLE
)
) Nos;
END;
/
Error 1: PL/SQL: SQL Statement ignored {Indicating : "WITH include_rec" Line}
Error 2 : PL/SQL: ORA-01789: query block has incorrect number of result columns {Indicating line : "AS (SELECT first_name,COUNT(1) OVER (PARTITION BY first_name)"}
thanks in advance
waiting for ur reply
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我想警告一下,我没有太多时间来处理这个问题,所以可能会有一些错误,但它应该给你我想告诉你的要点:
我会还要说,如果您期望一个大的结果集,那么也将 BULK COLLECT 放入循环中以减少内存需求。
在理想情况下,您可以将变量activationStartDate、activationEndDate、deActivationStartDate 和deActivationEndDate 作为游标参数传递到游标中,以保持游标模块化,但这取决于您。 ;-)
希望这有帮助...
奥利。
编辑:
为了回答有关使用记录从表中选择*的问题,您可以根据游标列声明一个关联数组,对于上面的示例,如果您想从 EMPLOYEE 选择多个列,那么在WITH子句之后您将选择您想要的 EMPLOYEE 中的命名列,而不是:
将关联数组类型和变量声明为:
这为您提供了一个灵活的数组,它将自动保存光标 (main_cur) 中选择的列。
您可以使用 BULK COLLECT: 将记录收集到此数组中,
并使用以下命令循环它们:
至于将结果集返回到 Java,我不是 Java 专家,您需要在另一个论坛中询问或用以下标记来标记此问题Java 标签,希望 Java 人员能够找到它并为您解答。
I'd like to caveat this by saying that I haven't had a lot of time to work on this so there may be a few errors but it should give you the gist of what i'm trying to tell you:
I'd also say that if you are expecting a large resultset then put the BULK COLLECT into a loop too to reduce your memory requirements.
In an ideal world, you'd pass the variables activationStartDate, activationEndDate, deActivationStartDate and deActivationEndDate into the cursor as cursor parameters to keep the cursor modular but that's up to you. ;-)
Hope this helps...
Ollie.
EDIT:
In response to your question about using records to select * from the table, you can declare an associative array based on the cursor columns, for the example above if you wanted to select more than one column from EMPLOYEE then after the WITH clause you would select the named columns from EMPLOYEE you want and instead of:
declare the associative array type and variable as:
This gives you a flexible array that will automatically hold the columns selected in your cursor (main_cur).
You would collect the records into this array with the BULK COLLECT:
and loop through them with:
as for returning your resultset to Java, well I'm no java expert and you'll need to ask that in another forum or tag this question with the Java tag and hope a Java person picks it up and answers it for you.
你能用 SQL 做到这一点吗?
例如,也许可以使用这样的WITH:
如果您可以在SQL 中完成它,那么您可以随时将其嵌入到PL/SQL 中(如果您需要的话)。
Can you do this in SQL?
E.g. maybe using a WITH like this:
If you can do it in SQL you can always embed it in PL/SQL afterwards if you need to.