Change the parameter each time and run the sql script - sql

I am quite new to sql and have been trying to work on the following script to parameterize it.
This is my code:
select
dc.deviceid,
dc.kernel_time,
dc.crash_time,
dc.crash_process,
dps.start_time,
dps.end_time,
dps.start_kernel_time,
dps.end_kernel_time,
case
when dc.kernel_time between dps.start_kernel_time and dps.end_kernel_time then 1
when dc.crash_time between dps.start_time and dps.end_time then 2
else 3
end as flag,
ROW_NUMBER () over (partition by dc.deviceid, dc.kernel_time,
dc.crash_time, dc.crash_process order by flag) row_num
from dummy.dummy_crashes dc
left outer join (select *
from dummy.dummy_power) as dps
on dc.deviceid = dps.deviceid
and ((dc.kernel_time between (dps.start_kernel_time + 10000) and (dps.end_kernel_time + 10000)) or (dc.crash_time between dps.start_time and dps.end_time))
order by dc.crash_time;
I need to test this script by changing the start_kernel_time and end_kernel_time with a certain int parameter value (in this example shown: 10000) every time. So, instead of modifying it in the code, I would like to create a function with the int parameter of choice and run this script. Would that be possible?
I am really clueless as to how to achieve that.
My ideal idea would be something like this:
get_crashes(10000); <-- get records with adding int parameter (in start_kernel_time and end_kernel_time) as 10000
get_crashes(30000); <-- get records with adding int parameter as 30000
get_crashes(80000); <-- get records with adding int parameter as 80000
I am really trying to understand how I could achieve this?

I can't write a comment because i don't have 50rep, but here is my answer:
You can create a temp table with values that you want to pass and call cursor with simple query like:
SELECT [value] FROM *temptable*
After that, inside cursor just write script with single value from above temp table
UPDATE
DECLARE
cur CURSOR FOR select col1 from tempTable;
test_cur RECORD;
BEGIN
open cur;
LOOP
fetch cur into test_cur;
exit when test_cur = null;
if test_cur.col1 IS NOT NULL then
return next test_cur.col1;
end if;
END LOOP;
close cur;
END;
One note - I never write PostgreSQL, just have knowledge about SQL and find code on internet, so maybe you need to check documentation.

Related

How to select distinct in esql?

I have a subflow in esql (IBM Websphere Message Broker) where I need to achieve something similar to select distinct functionality.
Some background: I have a table in an Oracle database group_errcode_ref. This table is pretty much a fixed link/mapping of ERROR_CODE and ID. ERROR_CODE is unique, but ID can be duplicated. For example error code 4000 and 4001 can both be linked to ID 1.
In my esql subflow, I have an array of error codes that varies based on the current data coming into the flow.
So what I need to do is I need to take the input error code array, and select the ID for all the error codes in the array from my table group_errcode_ref
What I have now:
declare db rows;
set db.rows[] = (select d.ID from Database.group_errcode_ref as d where d.ERROR_CODE in (select D from errCodes.Code[] as D);
errCodes is the array of error codes from the input. row is an array of all IDs that correspond to the error codes.
This is fine, but I want to remove duplicates from the db.rows[] array.
I'm not certain the best way to do this in esql, but it does not support distinct. group by, or order by
If you are using the PASSTHRU statement, then all the functionality of your database manager is supported, so distinct as well.
The only thing you have to overcome is that you cannot directly mix database and messagetree queries in PASSTHRU, everything you pass to it goes directly to the database.
So your original solution would look something like this:
set db.rows[] = PASSTHRU 'select distinct d.ID from SCHEMA.group_errcode_ref as d where d.ERROR_CODE in ' || getErrorCodesFromInput(errCodes) TO Database.DSN1;
Here getErrorCodesFromInput is a function that returns character, which contains the error codes in your input, formatted correctly for the query, e.g. (ec1, ec2, ...)
My work around ended up not doing select distinct or sorting at all but another work around.
Basically I iterate through the entire array of ERROR_CODEs, then I query for the ID that corresponds to the error_code, then I select count(*) in a table I insert them to.
This works for my particular application only because I insert the ID/Issue pairs.
Basically it looks like:
for x as errs.Error[] do
declare db row;
set db.rows[] = passthru('select ID from my_static_map_table where error_code = ?;' values(x.Code));
declare db2 row;
set db2.rows[] = passthru('select count(*) from my_table_2 where guid = ? and id = ?;' values(guid, db.ID));
if db2.COUNT == 0 then
-- Here I do an insert into my_table_2 with ID and a few other values
end if;
end for;
Not really a proper answer, but it works for my specific application. Basically loop through every error code and select one at a time, rather than sending in the entire array. Then doing an insert into another database while avoiding duplicates by another select to see if it's already been inserted.
I'll still wait a week to see if there's a better answer and accept that one.
UPDATE
I've changed my code to match Attila's solution - which is much better and what I was looking for originally
Only thing I will add is my function that formats the error codes - which is really simple:
create function FlattenErrorCodesArray(in err row) returns char begin
declare idx int 1;
declare ret char;
for x as errs.Error[] do
if idx = 1 then
set ret = '(' || cast(x.Code as char);
else
set ret = ret || ',' || cast(x.Code as char);
end if;
set idx = idx + 1;
end for;
set ret = ret || ')';
end;

Matching and updating two table

I am going to fetch every row from one table and find the equivalent in another table. Then i am going to update the rows of the second table by using the id which i have already gotten.
I tried to run my script but i had some problems.
I actually tried to make a loop and then put the id of every row in a variable to use them for my update statement but Pl shows me an error which tells me "not data found"
My unfinished script
DECLARE
tbl1Count number(4);
counter number(4);
MyO66ID number(8);
Begin
select Count(*) INTO tbl1Count from crbank ;
<<my_loop>>
For counter IN 1..tbl1Count-1 Loop
select O66ID INTO MyO66ID from crbank where rownum=counter;
End loop my_loop;
End;
You have written a strange logic in this scenario
This should work:
DECLARE
tbl1Count number(4) :=0;
MyO66ID number(8);
Begin
-- select Count(*) INTO tbl1Count from crbank; -- not needed at all
For myItems IN (select O66ID, ROWNUM, whatever_columns_you_need from crbank) Loop
MyO66ID := myItems.O66ID;
tbl1Count := tbl1Count + 1; -- this will serve you better than the first select if you are concerned of the number of rows you have.
/*
Do your logic here for the values you have in the myItems object
EX: update yourTable set yourColumn = myItems.otherColumn where id= myItems.something
You dont need variables to be defined if you noticed as in the above example.
*/
End loop;
End;
Hints:
You are getting the count, then looping on the count you get and matching it with rownum!, which is not a best practice; hitting your database twice, for count and for select, although you can do it in once loop, and no need for the first select
rownum will be different for each select statement, depending on the order you specified, so is it wise to use it?
You have mentioned in your question
I am going to fetch every row from one table and find the equivalent in another table
Oracle just have a workaround for this type of conditions. MERGE statement is very useful in these typical scenarios. Consider the below illustrated snippet. Let me know if this helps.
Whenever it is possible try to use pure SQL over PL/SQL
MERGE INTO <Update_table> USING <LOOKUP_TABLE>
ON
(UPDATE_TABLE.COLUMN_NAME = LOOKUP_TABLE.COLUMN_NAME)
WHEN MATCHED THEN
UPDATE SET
<UPDATE_TABLE.COLUMN_NAME> = <Update_value>
;
Try this one using cursor in sql.
Declare #id bigint
DECLARE CUR CURSOR FOR
select data from table1
open CUR
Fetch next from cur into #id
while ##FETCH_STATUS=0
begin
update table2 set columnname=value where id=#id
Fetch next from cur into #id
end
CLOSE CUR
DEALLOCATE CUR

PL/SQL block and LOOP exercise

I have to create a PL/SQL block to insert 10 to 100 multiples of 10 in a table called TEN_MULTIPLES that I have to create... (SCHEMA -> TEN_MULTIPLES(numbervalue)). I will have to insert inside the table only 10,20,30,...,100 but exluding 50 and 90. So far I have done this... is it correct?
DECLARE
CREATE TABLE ten_multiples
(numbervalue NUMBER (3));
BEGIN
FOR i IN 9..101 LOOP
IF (i = 50 OR i = 90) THEN
ELSIF (i%10 = 0) THEN
INSERT INTO ten_multiples
VALUE (i);
END IF;
END LOOP;
END;
When I use 10..100 are 10 and 100 included and evaluated as 'i' in the loop?
I need also to find the MAXIMUM number from that table using a cursor, so in this case 100, store it in a variable 'num' declared in the DECLARE part and print it out...
DECLAR
CURSOR my_cursor IS
SELECT MAX(v_number) FROM ten_multiples;
num NUMBER;
BEGIN
OPEN my_cursor;
FETCH my_cursor INTO (num);
DBMS_OUTPUT.PUT_LINE(‘Maximum number is ‘ | num);
CLOSE my_cursor;
END;
Is this right?
I really thank you in advance :)
Why is so much PL/SQL coursework consists of exercises in how not to use PL/SQL?
insert into ten_multiples
with data as ( select level*10 as mult
from dual
connect by level <=10)
select * from data
where mult not in (50,90)
/
First part:
You cannot execute the CREATE TABLE statement directly in a PL/SQL
context. You must use the DBMS_DDL package or dynamic SQL via the
EXECUTE IMMEDIATE command, if you must execute within PL/SQL context.
Yes number literals in the for loop are included.
Second part:
Use DECLARE not DECLAR.
Your SELECT member must be a column of the table, not v_number.
Your single quote character is incorrect, use ', not ‘.
Use double pipe for concatenation, not single.
Finally:
Actually run these commands through SQL*Plus and listen to the tool.
Trying is your friend.

HSQL Iterated FOR Statement not working

Using HSQL 2.2.5 I need to shudder process one row at a time in a stored procedure, so I thought the "Iterated FOR" statement might do the trick for me. Unfortunately I don't seem to be able to make it work. It's supposed to look something like:
FOR SELECT somestuff FROM sometable DO
some random SQL statements
END FOR;
That leaves off a bit of the syntax, but it's close enough for now.
The problem seems to be that the statements inside the loop never execute. I've verified that my SELECT statement does indeed return something.
So let's get concrete. When I execute this stored procedure:
CREATE PROCEDURE b()
MODIFIES SQL DATA
BEGIN ATOMIC
DECLARE count_var INTEGER;
SET count_var = 0;
WHILE count_var < 10 DO
INSERT INTO TTP2 VALUES(count_var);
SET count_var = count_var + 1;
END WHILE;
END;
I get 10 rows inserted into table TTP2, with values 0 through 9. (TTP2 has just one column defined, of type INTEGER.)
But when I substitute a FOR statement for the WHILE like so:
CREATE PROCEDURE c()
MODIFIES SQL DATA
BEGIN ATOMIC
DECLARE count_var INTEGER;
SET count_var = 0;
FOR SELECT id FROM ttp_by_session FETCH 10 ROWS ONLY DO
INSERT INTO TTP2 VALUES(count_var);
SET count_var = count_var + 1;
END FOR;
END;
I get nothing inserted into TTP2. (I have verified that the SELECT statement returns 10 rows, one column of integers.)
When I leave the FETCH clause off I still get no results. ttp_by_session is a view, but the same thing happens with a bare table.
What am I doing wrong?
Thanks for the help.
This works fine with the latest version of HSQLDB. Try with the 2.3.0 release candidate snapshot from the HSQLDB web site.
When the FOR statement was initially added about two years ago, it had limited functionality. The functionality was extended in later versions.

Viewing query results with a parameters in Oracle

I need to run big queries (that was a part of SP) and look at their results (just trying to find a bug in a big SP with many unions. I want to break it into parts and run them separately).
How can I do that if this SP have few parameters? I don't want to replace them in code, it would be great just to add declare in a header with a hardcode for this parameter.
I've tried something like this:
DECLARE
p_asOfDate DATE := '22-Feb-2011';
BEGIN
SELECT * from myTable where dateInTable < p_asOfDate;
END
But it says that I should use INTO keyword. How can I view this results in my IDE? (I'm using Aqua data studio)
I need to do that very often, so will be very happy if will find a simple solution
You are using an anonymous block of pl/sql code.
In pl/sql procedures you need to specify a target variable for the result.
So you first need to define a variable to hold the result in the declare section
and then insert the result data into it.
DECLARE
p_asOfDate DATE := '22-Feb-2011';
p_result myTable%ROWTYPE;
BEGIN
select * into p_result from myTable where dateInTable < p_asOfDate;
END
That said you will probaply get more than one row returned, so I would use
a cursor to get the rows separately.
DECLARE
CURSOR c_cursor (asOfDate IN DATE) is
select * from myTable where dateInTable < asOfDate;
p_asOfDate DATE := '22-Feb-2011';
p_result myTable%ROWTYPE;
BEGIN
OPEN c_cursor(p_asOfDate);
loop
FETCH c_cursor into p_result;
exit when c_cursor%NOTFOUND;
/* do something with the result row here */
end loop;
CLOSE c_cursor;
END
To output the results you can use something like this for example:
dbms_output.put_line('some text' || p_result.someColumn);
Alternatively you can execute the query on an sql command-line (like sqlplus)
and get the result as a table immediately.
I hope I understood your question correctly...
update
Here is a different way to inject your test data:
Use your tools sql execution environemnt to submit your sql statement directly without a pl/sql block.
Use a "&" in front of the variable part to trigger a prompt for the variable.
select * from myTable where dateInTable < &p_asOfDate;
The Result should be displayed in a formatted way by your tool this way.
I do not know about Aqua, but some tools have functions to define those parameters outside the sql code.