Oracle profiler without 3rd party software - oracle

I am trying to make something like T-SQL profiler with queries without any 3rd party software.
So first of all I have code for take currently executed queries:
select x.sid
,sql_text
from v$sqlarea sqlarea
,v$session x
where x.sql_hash_value = sqlarea.hash_value
and x.sql_address = sqlarea.address
and x.username = 'USERNAME';
Now I find two challenges:
When I put this code in while loop I am getting error:
DECLARE
x NUMBER := 0;
BEGIN
LOOP
select x.sid
,sql_text
from v$sqlarea sqlarea
,v$session x
where x.sql_hash_value = sqlarea.hash_value
and x.sql_address = sqlarea.address
and x.username = 'MAGICAPP';
EXIT WHEN x > 1;
END LOOP;
END;
Error report - ORA-06550: line 5, column 10: PLS-00428: an INTO clause
is expected in this SELECT statement
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Second challenge might be:
Even if this code above works it would keep refreshing old data with new data by SELECT statement. Would it be possible to append new data to old data with SELECT statement if new data is not found in old data?
How this should work?
Once executed this script should keep running while user not cancel it and than print all queries which it found.

For the error specifically you need an INTO to SELECT the values INTO variables, something like:
DECLARE
x NUMBER := 0;
txt VARCHAR2(4000);
BEGIN
LOOP
select x.sid,sql_text
INTO x, txt
from v$sqlarea sqlarea
,v$session x
where x.sql_hash_value = sqlarea.hash_value
and x.sql_address = sqlarea.address
and x.username = 'MAGICAPP';
EXIT WHEN x > 1;
END LOOP;
END;

Related

Execute PLSQL script file from RobotFramework DatabaseLibrary is throwing error

I am new to Robot Framework. I have requirement to do Data Setup in Oracle DB by running a PLSQL through "Execute Sql Script" keyword. When I execute it I am getting the following error.
Error:
*DatabaseError: ORA-06550: line 2, column 17:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
* & = - + ; < / > at in is mod remainder not rem
<an exponent (**)> <> or != or ~= >= <= <> and or like like2
like4 likec between || multiset member submultiset*
This is the Sample PLSQL I am using, when I execute the same PLSQL in SQL Developer I don't see any syntax error.
PLSQL Script:
DECLARE
x NUMBER := 100;
BEGIN
FOR i IN 1..10 LOOP
IF MOD(i,2) = 0 THEN
INSERT INTO temp VALUES (i, x, 'i is even');
ELSE
INSERT INTO temp VALUES (i, x, 'i is odd');
END IF;
x := x + 100;
END LOOP;
COMMIT;
END;
Robot Script
*** Test Cases ***
Data Setup In Oracle
Connect To Database cx_Oracle ${or-dbname} ${or-dbuser} ${or-dbpasswd} ${or-dbhost} ${or-dbport}
Execute Sql Script Resources/sampleplsql.sql
Disconnect From Database
Put a slash / to the end of the script:
DECLARE
x NUMBER := 100;
BEGIN
FOR i IN 1..10 LOOP
IF MOD(i,2) = 0 THEN
INSERT INTO temp VALUES (i, x, 'i is even');
ELSE
INSERT INTO temp VALUES (i, x, 'i is odd');
END IF;
x := x + 100;
END LOOP;
COMMIT;
END;
/ --> this
All,
I found a work around to make PLSQL work with DatabaseLibrary, I have used the keyword "Execute Sql String" instead of "Execute Sql Script" and passed the complete PLSQL as a string.
I kept the PLSQL as Python variable and passed the same as argument for Execute Sql String, and it worked like a champ.
Please find the code snippet.
PLSQL.py
TESTPLSQL="""DECLARE
x NUMBER := 100;
BEGIN
FOR i IN 1..10 LOOP
IF MOD(i,2) = 0 THEN
INSERT INTO temp VALUES (i, x, 'i is even');
ELSE
INSERT INTO temp VALUES (i, x, 'i is odd');
END IF;
x := x + 100;
END LOOP;
COMMIT;
END;"""
Robot Script:
*** Settings ***
Library DatabaseLibrary
Variables ../../Resources/plsql.py
*** Variables ***
${sql-string} ${TESTPLSQL}
*** Test Cases ***
Data Setup In Oracle
Connect To Database cx_Oracle ${or-dbname} ${or-dbuser} ${or-dbpasswd} ${or-dbhost} ${or-dbport}
Execute Sql String ${sql-string}
Disconnect From Database

Need help understanding Cursor for loop

I am trying to write a code for every stock value that is $75 or more
add a "*" in the STK_FLAG column. my error repots are: Error report -
ORA-06550: line 15, column 21: PLS-00201: identifier 'STK_FLG' must be
declared ORA-06550: line 15, column 5: PL/SQL: SQL Statement ignored
ORA-06550: line 23, column 7: PL/SQL: ORA-00904: "STK_FLG": invalid
identifier ORA-06550: line 17, column 5: PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Blockquote
SET SERVEROUTPUT ON
DECLARE
CURSOR CURR
IS
SELECT STK_FLAG
FROM MM_MOVIE
WHERE MOVIE_VALUE * MOVIE_QTY >= 75
FOR UPDATE;
BEGIN
OPEN CURR;
LOOP
FETCH CURR INTO STK_FLG;
UPDATE
MM_MOVIE
SET
STK_FLG= '*'
WHERE
CURRENT OF CURR;
EXIT
WHEN CURR%notfound;
END LOOP;
Commit;
CLOSE CURR;
END;
/
You didn't declare a cursor variable (so there's nowhere you can put values returned by the cursor). Don't name it as column name; use a prefix, such as v_ or l_ or whichever you want.
Furthermore, in UPDATE you referenced a non-existent column. Cursor suggests its name is stk_flag, not stk_flg
Therefore, code that might be OK is
DECLARE
CURSOR curr IS
SELECT stk_flag
FROM mm_movie
WHERE movie_value * movie_qty >= 75
FOR UPDATE;
l_stk_flag mm_movie.stk_flag%TYPE; --> this
BEGIN
OPEN curr;
LOOP
FETCH curr INTO l_stk_flag;
EXIT WHEN curr%NOTFOUND;
UPDATE mm_movie
SET stk_flag = '*' --> this
WHERE CURRENT OF curr;
END LOOP;
COMMIT;
CLOSE curr;
END;
/
Why use a pl/sql anonymous block? Even if there is an "external" requirement for the functionality wrapped into pl/sql why use a cursor and loop? Using code that might be OK (from #Littlefoot) you retrieve a single column meeting your condition, iterate the resulting record set fetching that column but otherwise do nothing with it, and update a single row on every iteration of the loop with a literal value. SQL is designed for processing entire sets of rows at a time. Your processing can be done in a single update statement. Assuming there is an external requirement for a pl/sql block your code reduces to:
BEGIN
UPDATE mm_movie
SET stk_flag = '*'
WHERE movie_value * movie_qty >= 75;
COMMIT;
END;
Take away: When working with SQL stop thinking in terms of iterating (loops). Instead think of the commonality (set) of all objects to be processed. A different way of looking at problems and their corresponding solutions to be sure. Getting used to thinking that way will take some time, but in the long run your SQL and procedures will greatly improve because of it. Both in performance and clarity.

PLSQL ignore compilation error which is not an error

I came accross interesting error where I am not sure about best way how to fix it. Given following block:
DECLARE
v_column_exists number := 0;
host_column_exists number := 0;
i number;
BEGIN
Select count(*) into v_column_exists from user_tab_cols where column_name = 'CONNECTIONDESCRIPTION' and table_name = 'NODES';
if (v_column_exists = 1) then
Select count(*) into host_column_exists from user_tab_cols where column_name = 'HOST' and table_name = 'NODES';
if (host_column_exists = 0) then
execute immediate 'alter table NODES add (Host varchar2(255))';
for item in (select connectiondescription, code from nodes) loop
... LOOP STUFF ...
end loop;
end if;
end if;
END;
I get following result:
PL/SQL: ORA-00904: "CONNECTIONDESCRIPTION": invalid identifier
ORA-06550: line 40, column 20: PL/SQL: SQL Statement ignored
ORA-06550: line 41, column 20: PLS-00364: loop index variable 'ITEM'
use is invalid
any ideas how to get rid of this error? Problem is occuring when column NODES.CONNECTIONDESCRIPTION is not present in database, however in such case for loop won't execute in runtime. I would need to disable these errors, but haven't found any way to do it. I have tried using ALTER SESSION SET PLSQL_WARNINGS='DISABLE:00904', but it had no effect.
Thanks
Correct approach was to use another dynamic query which bulk collects items to an array and then loop through this array.

How to run Oracle in SQLFiddle

I am new to Oracle sql. I got a piece of code from the web, and paste it into sqlfiddle (http://sqlfiddle.com/):
For the schema, I created a temp table, which will be used in the sql query:
CREATE Global Temporary TABLE temp
(id number
,x number)
,y CHAR(50))
ON COMMIT DELETE ROWS;
I clicked build schema, which tells me "Schema Ready".
Then I paste the following query which is from Oracle official website on the right pane:
-- available online in file 'sample1'
DECLARE
x NUMBER := 100;
BEGIN
FOR i IN 1..10 LOOP
IF MOD(i,2) = 0 THEN -- i is even
INSERT INTO temp VALUES (i, x, 'i is even');
ELSE
INSERT INTO temp VALUES (i, x, 'i is odd');
END IF;
x := x + 100;
END LOOP;
COMMIT;
END;
When I press run sql, and it returns errors:
ORA-06550: line 3, column 18: PLS-00103: Encountered the symbol
"end-of-file" when expecting one of the following: * & = - + ; < / >
at in is mod remainder not rem <> or != or ~= >= <=
<> and or like like2 like4 likec between || multiset member
submultiset
You need to change default query terminator([;]) to sth else than ; and you may need to add this separator and new line between blocks of code:
SqlFiddleDemo
DECLARE
x NUMBER := 100;
BEGIN
FOR i IN 1..10 LOOP
IF MOD(i,2) = 0 THEN
INSERT INTO temp VALUES (i, x, 'i is even');
ELSE
INSERT INTO temp VALUES (i, x, 'i is odd');
END IF;
x := x + 100;
END LOOP;
COMMIT;
END;
What's up with that [ ; ] button under each panel?
This obscure little button determines how the queries in each of the panels get broken up before they are sent off to the database.
This button pops open a dropdown that lists different "query
terminators." Query terminators are used as a flag to indicate (when
present at the end of a line) that the current statement has ended.
The terminator does not get sent to the database; instead, it merely
idicates how I should parse the text before I execute the query.
Oftentimes, you won't need to touch this button; the main value this feature will have is in
defining stored procedures. This is because it is often the case that
within a stored procedure's body definition, you might want to end a
line with a semicolon (this is often the case). Since my default query
terminator is also a semicolon, there is no obvious way for me to see
that your stored procedure's semicolon isn't actually the end of the
query. Left with the semicolon terminator, I would break up your
procedure definition into incorrect parts, and errors would certainly
result. Changing the query terminator to something other than a
semicolon avoids this problem.

PLS-00103: Encountered the symbol "END"

I'm new to the Oracle PL/SQL and I'm getting error mentioned in the title, exactly at line 30, when I try to run this code in Oracle APEX.
Here's the code:
CREATE OR REPLACE PROCEDURE enter_student_grade
(p_num_grade IN class_assessments.numeric_grade%TYPE,
p_class_assessment_id IN class_assessments.class_assessment_id%TYPE,
p_class_id IN class_assessments.class_id%TYPE,
p_stu_id IN class_assessments.stu_id%TYPE,
p_assessment_id class_assessments.assessment_id%TYPE,
p_date_turned_in IN DATE := SYSDATE) IS
v_max_id class_assessments.class_assessment_id%TYPE := 0;
v_max_attempts NUMBER(1,0):= 0;
BEGIN
SELECT max(class_assessment_id)+1 INTO v_max_id
FROM class_assessments;
SELECT count(stu_id) INTO v_max_attempts FROM class_assessments WHERE stu_id = p_stu_id AND assessment_id = p_assessment_id
IF v_max_attempts < 3 THEN
INSERT INTO class_assessments
(class_assessment_id,date_turned_id,numeric_grade,letter_grade,class_id,stu_id,assessment_id)
VALUES
(v_max_id,p_date_turned_in,p_num_grade,convert_grade(p_num_grade),p_class_id,p_stu_id,p_assessment_id);
commit;
ELSE
dbms_output.put_line('ERROR: Current student has reached maximum number of attempts for this assessment');
END IF;
END enter_student_grade;
I have no idea, where can be the source of this error.
Any help is appreciated.
Thanks
Symbol ; is missing after second SELECT statement (before IF).

Resources