Can we declare and open a cursor for UPDATE query also or is it only for SELECT queries?
EXEC SQL PREPARE S FROM :query;
EXEC SQL DECLARE C CURSOR FOR S;
DbUtilT::set_bind_variables(bind_dp,¶mList);
EXEC SQL OPEN C USING DESCRIPTOR bind_dp;
EXEC SQL WHENEVER NOT FOUND GOTO end_update_loop;
EXEC SQL FETCH C USING DESCRIPTOR bind_dp;
EXEC SQL COMMIT WORK;
Is this fine? Or should we use cursor only for SELECT statments then how do we execute UPDATE queries?
If query is something like:
SELECT id FROM mytable WHERE ... FOR UPDATE OF id
then you can do:
...
EXEC SQL FETCH C USING DESCRIPTOR bind_dp;
EXEC SQL UPDATE mytable SET id = <something> WHERE CURRENT OF C;
I'm not quite sure what you mean though; you don't have to use a cursor to do an update, you can do:
EXEC SQL UPDATE mytable SET id = <something> WHERE ...;
... or the equivalent prepared statement.
Have I completely misunderstood the question?
Related
I want to remove the value for a specific column in multiple SQL Server tables using an UPDATE statement.
Using T-SQL, is it possible to store the tables in a list, then use a for each loop to execute the same SQL update statement to every single table in the list?
This is easy to do in a programming language like Python where you just specify
for table in tables:
Update statement
Yes, you could use dynamic SQL to build and execute a single SQL statement, no looping required, you could build on something like:
declare #sql nvarchar(max);
with t as (
select n from(values('Table1'),('Table2'),('Table3'))t(n) /* My list of tables*/
)
select #sql = String_Agg(Concat('Update ', QuoteName(n), ' set col = 5 where col = 4; '),'')
from t;
exec(#sql);
See Demo Fiddle
You have bunch of options to make it really dynamic and flexible i created a potential solution that might meet your needs, the approach consist in Sql Cursors , temp tables and dynamic execution:
Fiddle
declare #updateStatement nvarchar(150)
declare #myList table (updateStatement nvarchar(150))
insert into #myList values
('update TableA set valA=''AUpdated'' where valA=''ANotUpdated'''),
('update TableB set valB=''BUpdated'''),
('update TableC set valC=''CUpdated''')
declare C cursor local fast_forward for
SELECT updateStatement
FROM #myList
OPEN C
FETCH NEXT FROM C
INTO #updateStatement
WHILE ##FETCH_STATUS = 0
BEGIN
exec (#updateStatement)
FETCH NEXT FROM C
INTO #updateStatement
END
CLOSE C
DEALLOCATE C
The following DECLARE fails:
PREPARE stmt(bigint) AS SELECT ...;
DECLARE crs CURSOR FOR stmt;
According to https://www.postgresql.org/docs/9.6/static/sql-declare.html,
stmt has to be either SELECT or VALUES command.
I use PREPARE statement in a latency-critical section of the code in which thousands of quick queries are emitted. Parsing and generating a query plan each time would be performance killer. However, in some rare cases the query can return millions of records and the result doesn't fit into memory.
Is there a way to declare a cursor for prepared statement in PostgreSQL? If not, are there any workarounds?
https://www.postgresql.org/docs/9.1/static/ecpg-commands.html#ECPG-EXECUTING
This can be done through ECPG C library in c code.
One can create prepared statement in C code as:
EXEC SQL PREPARE stmt1 FROM "SELECT oid,datname FROM pg_database WHERE oid > ?";
and then create cursor for that statement as:
EXEC SQL DECLARE foo_bar CURSOR FOR stmt1;
fetch result form cursor within infinite loop.
EXEC SQL OPEN foo_bar USING 100;
while(1){
EXEC SQL FETCH NEXT FROM foo_bar INTO :dboid, :dbname;
}
This is available with 9.1 version of postgresql.
I have been trying to prepare a Fetch statement in db2 as below
Stmt = %trim('FETCH EXSQCRS INTO ?');
EXEC SQL PREPARE SQLSTMT2 FROM :STMT ;
EXSQCRS is a cursor.
But this is failing with -104 error. Any clue on how to write this?
FETCH isn't a statement that can be prepared. It's simply an executable statement. See Actions allowed on SQL statements
You need to read up on Embedded SQL programming
Simple example with dynamic SQL
D EMPNUM S 6A
D NAME S 15A
D STMT S 500A INZ('SELECT LASTNAME -
D FROM CORPDATA.EMPLOYEE WHERE -
D EMPNO = ?')
//************************************************************
// Prepare STMT as initialized in declare section *
//************************************************************
/FREE
EXEC SQL
PREPARE S1 FROM :STMT;
//
//************************************
// Declare Cursor for STMT *
//************************************
EXEC SQL
DECLARE C1 CURSOR FOR S1;
//
//****************************************************
// Assign employee number to use in select statement *
//****************************************************
EMPNUM = '000110';
//*********************
// Open Cursor *
//*********************
EXEC SQL
OPEN C1 USING :EMPNUM;
//
//**********************************************
// Fetch record and put value of *
// LASTNAME into NAME *
//**********************************************
EXEC SQL
FETCH C1 INTO :NAME;
You can't prepare the fetch. You can prepare the SQL statement that is used to define the cursor though. So it would look like this:
dcl-s stmt Varchar(256) Inz('');
exec sql declare S1 statement;
exec sql declare C1 cursor for S1;
stmt = 'select * from customer where cusno = ?';
exec sql prepare S1 from :stmt;
exec sql open C1 using :customerNumber;
exec sql fetch C1 into :customerDS;
dow %subst(sqlstate:1:2) = '00'
or %subst(sqlstate:1:2) = '01';
... process it here ...
exec sql fetch C1 into :customerDS;
enddo;
exec sql close C1;
Note there is no error checking here. You really want to do that on all executable sql statements. Note also that the exec sql declare ... statements are not executable. Not even the declare C1 cursor. I will usually put my sql in their own procedures. The prepare and open will go in one procedure, the fetch in another, and the close in another.
Some notes about using procedures and local variables with embedded sql. When using static cursors, you need to put the declare in the same procedure as the open because the host variables are in the declare statement, and they need to be the same variables in scope when you do the open. That is because the declare is totally commented out, and generates no code. It is not executable. The host variables appear in the code generated for the open in this case.
With prepared cursors, you do not need to put the declare in the same procedure as the open like you do with static cursors. That is because the host variables that are bound to parameter markers in the prepared statement appear in the open statement. The declare can be up at the head of the program with the global declarations. It is a global declaration after all regardless of where the declare is physically located. I like to explicitly declare my prepared statements even though you don't have to. I put them up with the cursor declarations.
I generally will have the fetch procedure return a boolean (indicator), or a record count so that I don't have to repeat the call in the code. The fetch is indeed repeated here just because I did not use procedures.
And finally, the one exception I have with testing errors is that I do not test for an error after the close because the only error that will throw is that the cursor isn't open which is not an error in my mind, it is what I want the state of the cursor to be when I am finished with it.
There's one stored procedure which executes a dynamic queries which will be from parameter. The dynamic queries mostly contains just SELECT statement but may contain delete/update some time.
I want to raise errors when this procedure tries to run the dynamic query which has DELETE or UPDATE commands.
Eg..
create procedure spa_test
#sql varchar(2000)
AS
EXEC(#sql)
go
----------------------
SET #sql1 = ' DELETE FROM data_table where .... ;
.........
SELECT * FROM some_table .. '
SET #sql2 = '....
.........
SELECT * FROM some_table '
EXEC spa_test #sql1 -- should result in error
EXEC spa_test #sql2 -- no error and procedure runs successfully
Can I accomplish this by using SQL Server Policy management ?
I can not alter this procedure spa_test and can not change the privilege of user running it.
Is there any other way I can accomplish this need ?
You can use CHARINDEX() to search for DELETE , UPDATE expression in your #sql query.
CHARINDEX ( expressionToFind ,expressionToSearch)
-
IF (CHARINDEX(#sql1 , 'DELETE FROM') <> 0 or CHARINDEX(#sql1 , 'UPDATE') <> 0 )
RAISERROR(...)
ELSE
EXEC(#sql1)
I am working with sql server 2008
I have a database table that has a column containing a stored procedure name.
I want to query the database table which returns a list of the stored procedure names, and execute them.
The stored procedures are similar all having a select statment. The data returned in this select statement I want to insert in to a data base table.
Pseudo code looks like this:
INSERT INTO MyTable
EXECUTE sp_executesql SELECT StoredProcedureName FROM Table
Anyone able to assist me with correct sql for achieveing the above?
sp_executesql accepts a unicode string not a tsql statement. So you would need to execute your procedure(s) like this:
execute sp_executesql 'execute ' + #storedprocedurename
which will execute a single procedure.
You will need to write some iterative process to populate the #storedprocedurename variable from your source table.
This is pretty much same as #Coltech answer just with cursor.
DECLARE #spname VARCHAR(200)
DECLARE #sql VARCHAR(1000)
DECLARE your_cursor CURSOR FOR
SELECT spname
FROM yourTable;
OPEN your_cursor;
FETCH NEXT FROM your_cursor
INTO #spname;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = 'EXEC ' + #spname
execute sp_executesql #sql
FETCH NEXT FROM your_cursor
INTO #spname;
END
CLOSE your_cursor;