I'm using oracle. My SQL skills are very bad, I want to update information from a query that I have obtained through the use of a cursor, I've read about using the WHERE CURRENT OF statement, but I don't see how that can fit into my current code. Does anyone mind lending a helping hand? I want to allow a calling program to update a row in the cursor (I want to update the race location) returned by the query in my current code. Here's my code so far:
DECLARE
l_race_rec race%rowtype;
CURSOR Query1
IS
SELECT *
FROM RACE
WHERE Race_Time='22-SEP-14 12.00.00.000000000';
BEGIN
OPEN Query1;
LOOP
FETCH query1 INTO l_race_rec;
EXIT WHEN query1%notfound;
dbms_output.put_line( l_race_rec.raceid || ', ' || l_race_rec.race_location || ', ' ||
l_race_rec.race_type || ', ' || l_race_rec.race_time || ', ' || l_race_rec.sex || ', ' ||
l_race_rec.minage || ', ' || l_race_rec.maxage );
END LOOP;
CLOSE Query1;
END;
Here's an example to get you going:
DECLARE
l_race_rec race%rowtype;
CURSOR Query1 IS
SELECT *
FROM RACE
WHERE Race_Time = '22-SEP-14 12.00.00.000000000';
nSome_value NUMBER := 42;
BEGIN
OPEN Query1;
LOOP
FETCH query1 INTO l_race_rec;
EXIT WHEN query1%notfound;
dbms_output.put_line(l_race_rec.raceid || ', ' ||
l_race_rec.race_location || ', ' ||
l_race_rec.race_type || ', ' ||
l_race_rec.race_time || ', ' ||
l_race_rec.sex || ', ' ||
l_race_rec.minage || ', ' ||
l_race_rec.maxage );
UPDATE RACE
SET SOME_FIELD = nSome_value
WHERE CURRENT OF QUERY1;
END LOOP;
CLOSE Query1;
END;
Share and enjoy.
Why don't you use a cursor for loop.
...
for row in query1
loop
dbms_output.put_line(row.raceid || ', ' ||
row.race_location || ', ' ||
row.race_type || ', ' ||
row.race_time || ', ' ||
row.sex || ', ' ||
row.minage || ', ' ||
row.maxage );
UPDATE RACE
SET SOME_FIELD = nSome_value
WHERE CURRENT OF QUERY1;
end loop;
...
In this way there no need to open and to close a cursor.
Keep in mind that a cursor for loop works better for a cursor with more than 1 row as result.
Good luck.
Related
I am using the code below which outputs as intended:
DECLARE
v_ins_param VARCHAR2(10);
CURSOR c_ins_param IS
SELECT status
FROM v$instance;
BEGIN
OPEN c_ins_param;
LOOP
FETCH c_ins_param INTO v_ins_param;
EXIT WHEN c_ins_param%NOTFOUND;
--
--
--
IF v_ins_param = 'OPEN' THEN
DBMS_OUTPUT.PUT_LINE('
' || CHR(35) || '' || CHR(35) ||'' || CHR(35) || '
Great! Your database is up.
' || CHR(35) || '' || CHR(35) ||'' || CHR(35) || ' ');
ELSIF v_ins_param = 'MOUNTED' THEN
DBMS_OUTPUT.PUT_LINE('
' || CHR(35) || '' || CHR(35) ||'' || CHR(35) || '
Database is only mounted.
' || CHR(35) || '' || CHR(35) ||'' || CHR(35) || '
');
ELSE
DBMS_OUTPUT.PUT_LINE('
' || CHR(35) || '' || CHR(35) ||'' || CHR(35) || '
Database is neither mounted or open.
' || CHR(35) || '' || CHR(35) ||'' || CHR(35) || '
');
END IF;
END LOOP;
CLOSE c_ins_param;
END;
/
This is the "kind" of output it'll give you:
###
Great! Your database is up.
###
Ultimately this will be a series of anonymous block "typed" scripts like this one which I want to output to a single file.
I am now trying to get the output to just give the text information only, in a html output. I saw this on another page and adapted it for my code to see how it would / could work:
spool c:mag.html
DECLARE
CURSOR c1 IS
SELECT * FROM dept;
BEGIN
DBMS_OUTPUT.PUT_LINE('< pre >');
DBMS_OUTPUT.PUT_LINE('< h1 >Report on Databases</h1>');
FOR mag IN c1
LOOP
EXIT WHEN c1%notfound;
DBMS_OUTPUT.PUT_LINE('< b >Department Name[/b] =' || mag.dname);
END LOOP;
END;
/
However the way of doing this, using:
mag.dname
is not applicable in my 'non for loop' example.
I feel like there must be a more appropriate way of achieving the output. I have tried:
set markup html on
And it does not just returned impact the output but ALL of the code.
Has anyone tried this before and know perhaps how I might get the html output for the returned data only?
Here's an example - I store the following in a script called (say) scr.sql
set termout off
set feedback off
set serverout on
begin
for i in (
select
case
when status = 'OPEN' then '<p>Database is open</p>'
when status = 'MOUNTED' then '<p>Database is mounted</p>'
else '<p>Database is not happy</p>'
end status_output
from v$instance
)
loop
dbms_output.put_line(i.status_output);
end loop;
end;
.
spool /tmp/status.html
/
spool off
and then run this from SQLPlus as
SQL> #scr.sql
and the only thing my resultant status.html is
<p>Database is open</p>
I had to write this query for an assignement. So we have a database and we are pulling information from it, this is going to work with some back end c# eventually. Is there anything i can do , knowing im going to reuse this, in order to make it better and more adaptable when the day comes when i have to connect it all.
set serveroutput on
DECLARE
LV_DATE HVK_RESERVATION.RESERVATION_START_DATE%TYPE;
LV_SERV VARCHAR(100);
CURSOR LCUR_RES IS
SELECT *
FROM HVK_RESERVATION R
INNER JOIN HVK_PET_RESERVATION PR
ON R.RESERVATION_NUMBER = PR.RES_RESERVATION_NUMBER
INNER JOIN HVK_PET P
ON P.PET_NUMBER = PR.PET_PET_NUMBER
INNER JOIN HVK_OWNER OW
ON OW.OWNER_NUMBER = P.OWN_OWNER_NUMBER
WHERE R.RESERVATION_START_DATE < LV_DATE
AND R.RESERVATION_END_DATE > LV_DATE;
CURSOR LCUR_SERVICE(PET_RES_NUM NUMBER) IS
SELECT *
FROM HVK_SERVICE S
INNER JOIN HVK_PET_RESERVATION_SERVICE PRS
ON PRS.SERV_SERVICE_NUMBER = S.SERVICE_NUMBER
AND PRS.PR_PET_RES_NUMBER = PET_RES_NUM;
BEGIN
LV_DATE := TO_DATE('&logdate', 'yy-mm-dd');
DBMS_OUTPUT.PUT_LINE('Kennel log for ' || '' || LV_DATE);
DBMS_OUTPUT.PUT_LINE('-------------------------------');
FOR I IN LCUR_RES LOOP
DBMS_OUTPUT.PUT_LINE('Run:' || '' || I.RUN_RUN_NUMBER || ' ' ||
'Pet: ' || '' || I.PET_NAME || ' ' ||
I.OWNER_LAST_NAME || ' Pet Reservation: ' || '' ||
I.PET_RES_NUMBER);
DBMS_OUTPUT.PUT_LINE('Reservation start/end ' || ' ' ||
I.RESERVATION_START_DATE || ' ' ||
I.RESERVATION_END_DATE);
DBMS_OUTPUT.PUT('Services : ');
FOR X IN LCUR_SERVICE(I.PET_RES_NUMBER) LOOP
DBMS_OUTPUT.PUT(X.SERVICE_DESCRIPTION || ' ');
END LOOP;
DBMS_OUTPUT.PUT_LINE('');
FOR LREC_LOG IN (SELECT *
FROM HVK_KENNEL_LOG KL
WHERE KL.PR_PET_RES_NUMBER = I.PET_RES_NUMBER
) LOOP
DBMS_OUTPUT.PUT_LINE('Notes: ' || '' ||
LREC_LOG.KENNEL_LOG_SEQUENCE_NUMBER || ' ' ||
'Log Note: ' || '' || LREC_LOG.KENNEL_LOG_NOTES);
END LOOP;
DBMS_OUTPUT.PUT_LINE(' ');
END LOOP;
END;
It it supposed to output the run number , reservation number , pet name , and any relate notes.
you can replace DECLARE with CREATE OR REPLACE PROCEDURE my_proc(in_logdate in date) IS.
in that case my_proc will be the name of your procedure.
you should also use a parameter instead of &logdate
so e.g. parameter name in_logdate of type date
...
LV_DATE := in_logdate;
...
This is how I create my search_term:
IF char_length(search_term) > 0 THEN
order_by := 'ts_rank_cd(textsearchable_index_col, to_tsquery(''' || search_term || ':*''))+GREATEST(0,(-1*EXTRACT(epoch FROM age(last_edited)/86400))+60)/60 DESC';
search_term := 'to_tsquery(''' || search_term || ':*'') ## textsearchable_index_col';
ELSE
search_term := 'true';
END IF;
I am having some trouble with a PLPGSQL function:
RETURN QUERY EXECUTE '
SELECT
*
FROM
articles
WHERE
$1 AND
' || publication_date_query || ' AND
primary_category LIKE ''' || category_filter || ''' AND
' || tags_query || ' AND
' || districts_query || ' AND
' || capability_query || ' AND
' || push_notification_query || ' AND
' || distance_query || ' AND
' || revision_by || ' AND
' || publication_priority_query || ' AND
' || status_query || ' AND
is_template = ' || only_templates || ' AND
status <> ''DELETED''
ORDER BY ' || order_by || ' LIMIT 500'
USING search_term;
END; $$;
returns ERROR:
argument of AND must be type boolean, not type text at character 64
As opposed to:
RETURN QUERY EXECUTE '
SELECT
*
FROM
articles
WHERE
' || search_term || ' AND
' || publication_date_query || ' AND
primary_category LIKE ''' || category_filter || ''' AND
' || tags_query || ' AND
' || districts_query || ' AND
' || capability_query || ' AND
' || push_notification_query || ' AND
' || distance_query || ' AND
' || revision_by || ' AND
' || publication_priority_query || ' AND
' || status_query || ' AND
is_template = ' || only_templates || ' AND
status <> ''DELETED''
ORDER BY ' || order_by || ' LIMIT 500';
END; $$;
... which works. Am I missing something?
My goal is to sanitize my user input.
If some of your input parameters can be NULL or empty and should be ignored in this case, you best build your whole statement dynamically depending on user input - and omit respective WHERE / ORDER BY clauses completely.
The key is to handle NULL and empty string correctly, safely (and elegantly) in the process. For starters, search_term <> '' is a smarter test than char_length(search_term) > 0. See:
Best way to check for "empty or null value"
And you need a firm understanding of PL/pgSQL, or you may be in over your head. Example code for your case:
CREATE OR REPLACE FUNCTION my_func(
_search_term text = NULL -- default value NULL to allow short call
, _publication_date_query date = NULL
-- , more parameters
)
RETURNS SETOF articles AS
$func$
DECLARE
sql text;
sql_order text; -- defaults to NULL
BEGIN
sql := concat_ws(' AND '
,'SELECT * FROM articles WHERE status <> ''DELETED''' -- first WHERE clause is immutable
, CASE WHEN _search_term <> '' THEN '$1 ## textsearchable_index_col' END -- ELSE NULL is implicit
, CASE WHEN _publication_date_query <> '' THEN 'publication_date > $2' END -- or similar ...
-- , more more parameters
);
IF search_term <> '' THEN -- note use of $1!
sql_order := 'ORDER BY ts_rank_cd(textsearchable_index_col, $1) + GREATEST(0,(-1*EXTRACT(epoch FROM age(last_edited)/86400))+60)/60 DESC';
END IF;
RETURN QUERY EXECUTE concat_ws(' ', sql, sql_order, 'LIMIT 500')
USING to_tsquery(_search_term || ':*') -- $1 -- prepare ts_query once here!
, _publication_date_query -- $2 -- order of params must match!
-- , more parameters
;
END
$func$ LANGUAGE plpgsql;
I added default values for function parameters, so you can omit params that don't apply in the call. Like:
SELECT * FROM my_func(_publication_date_query => '2016-01-01');
More:
Functions with variable number of input parameters
The forgotten assignment operator "=" and the commonplace ":="
Note the strategic use of concat_ws(). See:
How to concatenate columns in a Postgres SELECT?
Here is a related answer with lots of explanation:
Test for null in function with varying parameters
Little help needed. i have a dynamic query that outputs 4 column names and two table names into 6 cursor variables. Now i need to use the cursor variables to select the first 4 columns and then from the two table names using the cursor variables since those contain the data think something with a fetch through query using a variable that contains the query but i don’t know how to go about that. here’s what i have now i just need to fetch the cursor variables and runt hem into a query
DECLARE
arow VARCHAR2 (1000);
column1 VARCHAR2 (50);
column2 VARCHAR2 (50);
column3 VARCHAR2 (50);
column4 VARCHAR2 (50);
table1 VARCHAR2 (50);
table2 VARCHAR2 (50);
match VARCHAR2 (50);
match1 VARCHAR2 (50);
sql_statement VARCHAR2 (500);
BEGIN
FOR arow IN (SELECT column_name_old,
column_name_new,
column_name_old_2,
column_name_new_2,
table_name_old,
table_name_new
FROM A550003.META_DATA_TABLE)
LOOP
sql_statement :=
'INSERT'
|| ' '
|| 'INTO'
|| ' '
|| 'a550003.MATCH_TABLE'
|| ' '
|| 'SELECT '
|| arow.column_name_old
|| ', '
|| arow.column_name_new
|| ', '
|| 'DECODE( '
|| arow.column_name_old
|| ', '
|| arow.column_name_new
|| ','
|| '1'
|| ','
|| '0)'
|| 'AS'
|| ' '
|| 'MATCH'
|| ','
|| arow.column_name_old_2
|| ', '
|| arow.column_name_new_2
|| ','
|| 'DECODE( '
|| arow.column_name_old_2
|| ', '
|| arow.column_name_new_2
|| ','
|| '1'
|| ','
|| '0)'
|| 'AS'
|| ' '
|| 'MATCH1'
|| ' FROM '
||' '
|| arow.table_name_old
|| ', '
|| arow.table_name_new
|| ' WHERE '
|| arow.column_name_old
|| '='
|| arow.column_name_new
|| '(+)';
DBMS_OUTPUT.PUT_LINE (sql_statement);
EXECUTE IMMEDIATE sql_statement;
COMMIT;
END LOOP;
END;
First of all you sql_statement is wrong. You should set the value of this variable to sth like this (when you will get all needed names):
sql_statement := 'SELECT '
|| column1
|| ', '
|| column2
|| ', '
|| column3
|| ', '
|| column4
|| ' FROM '
|| table1
|| ', '
|| table2
|| ' WHERE '
|| -- JOIN_CONDITION
And then you can use EXECUTE IMMEDIATE statement:
EXECUTE IMMEDIATE sql_statement
INTO col1_val
,col2_val
,col3_val
,col4_val
;
Of course variables col[1..4]_val have to be declared.
Also watch out for SQL Injection.
It must be this:
sql_statement := 'SELECT '
|| column1 || ', ' || column2 || ', ' || column3 || ', ' || column4
|| ' FROM ' || table1 || ', ' || table2
|| ' WHERE ' || column1 ||'=' ||column2||'(+)';
EXECUTE IMMEDIATE sql_statement INTO col1_val, col2_val, col3_val, col4_val;
or preferably
sql_statement := 'SELECT '
|| column1 || ', ' || column2 || ', ' || column3 || ', ' || column4
||' FROM '||table1||' LEFT OUTER JOIN '||table2||' ON '||column1||'='||column2;
EXECUTE IMMEDIATE sql_statement INTO col1_val, col2_val, col3_val, col4_val;
For debugging DBMS_OUTPUT.PUT_LINE (sql_statement); will be usefull!
Then you don't need a Ref-Cursor, simply do:
BEGIN
For aRow in (SELECT * FROM a550003.meta_data_table) LOOP
sql_statement := 'SELECT '||aRow.column1||','||aRow.column2 ...
END LOOP;
END;
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 9 years ago.
Improve this question
I am unable to find the error with a quoted string not properly ended. I've looked everywhere and my syntax seems to be correct. The issue only came about when I introduced the if statement. Any ideas would be appreciated. Thanks. Let me know if you need more information.
declare
bk_id book.book_code%type;
bk_authorName author.author_first%type;
bk_authorLastName author.author_last%type;
bk_title book.title%type;
bk_pubcode book.publisher_code%type;
bk_category book.type%type;
bk_price book.price%type;
bk_paper book.paperback%type;
TempData := 10;
cursor book_cursor is select author.author_first, author.author_last, book.title, book.type, book.price from book, author, wrote where book.book_code=wrote.book_code and author.author_num=wrote.author_num;
begin
open book_cursor;
dbms_output.put_line('First Name Last Name Title Type Price');
dbms_output.put_line('________________________________________________________________________');
dbms_output.put_line('Date: '||Systimestamp);
loop
fetch book_cursor into bk_authorName, bk_authorLastName, bk_title, bk_category, bk_price;
if(bk_price<TempData) then
dbms_output.put_line(bk_authorName || ' ' || bk_authorLastName || ' ' || bk_title || ' ' || bk_category || ' ' || bk_price || 'Special Deal');
else
dbms_output.put_line(bk_authorName || ' ' || bk_authorLastName || ' ' || bk_title || ' " || bk_category || ' ' || bk_price);
end if;
exit when book_cursor%notfound;
end loop;
close book_cursor;
end;
Actually the problem with this syntax is you used double quotes instead of single quotes.
This is the corrected code. Try this,it should work.
declare
bk_id book.book_code%type;
bk_authorName author.author_first%type;
bk_authorLastName author.author_last%type;
bk_title book.title%type;
bk_pubcode book.publisher_code%type;
bk_category book.type%type;
bk_price book.price%type;
bk_paper book.paperback%type;
TempData := 10;
cursor book_cursor is select author.author_first, author.author_last, book.title, book.type, book.price from book, author, wrote where book.book_code=wrote.book_code and author.author_num=wrote.author_num;
begin
open book_cursor;
dbms_output.put_line('First Name Last Name Title Type Price');
dbms_output.put_line('________________________________________________________________________');
dbms_output.put_line('Date: '||Systimestamp);
loop
fetch book_cursor into bk_authorName, bk_authorLastName, bk_title, bk_category, bk_price;
if(bk_price<TempData) then
dbms_output.put_line(bk_authorName || ' ' || bk_authorLastName || ' ' || bk_title || ' ' || bk_category || ' ' || bk_price || 'Special Deal');
else
dbms_output.put_line(bk_authorName || ' ' || bk_authorLastName || ' ' || bk_title || ' ' || bk_category || ' ' || bk_price);
end if;
exit when book_cursor%notfound;
end loop;
close book_cursor;
end;