Select in a cursor in DB2 - database

I have to fetch all columns names for all tables in a specific schema.
I did it without any problem in PL/SQL for an oracle Database but in DB2 I can't seem to make it work.
Here is my code :
BEGIN
declare cur1 cursor for
select TABNAME
from syscat.tables
where tabschema = 'SchemaX';
open cur1;
fetch cur1 into i;
while SQLCODE <> 100
do
select * from SYSCAT.COLUMNS where tabname = i;
end while;
close cur1;
END
it doesn't seems to like my select in the while loop.
Anybody have done this before?
Thank you!

First you need to create one proc and then call it to get the result set.
Without creating procedure if you run it it will run but will give 0 zero results.
CREATE OR REPLACE PROCEDURE MY_PROC_FOR_TESTING
DYNAMIC RESULT SETS 1
BEGIN
FOR I AS C1 cursor WITH HOLD for select TABNAME from syscat.tables where tabschema = 'SchemaX'
DO
BEGIN
DECLARE C_DISBURS_RPT CURSOR WITH RETURN TO CLIENT FOR
select * FROM SYSCAT.COLUMNS where tabname =I.TABNAME;
OPEN C_DISBURS_RPT;
END;
END FOR;
END!
CALL MY_PROC_FOR_TESTING!
Note: End of the statement should be mentioned at the statement termination box if it is IBM client.

Related

Why is this very simple cursor breaking SQL Server Management Studio?

I have created an item on the Degree table and I want to duplicate that record for 19 other Colleges. I have a really simple cursor, but every time I run it it totally crashes SQL Server Management Studio. Is there a way to rewrite this query (or another query entirely which performs the same INSERT INTO) so that it does not crash (and actually executes)?
DECLARE #Colleges VARCHAR(200)
DECLARE DUPLICATE_DEGREE CURSOR FOR
SELECT CollegeID FROM Colleges WHERE CollegeName <> 'Main Office'
OPEN DUPLICATE_DEGREE
FETCH NEXT FROM DUPLICATE_DEGREE INTO #Colleges
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO Degree
(
DegreeName
, CollegeID
)
SELECT
DegreeName
, #Colleges
FROM Degrees
WHERE DegreeID = 123
END
CLOSE DUPLICATE_DEGREE
DEALLOCATE DUPLICATE_DEGREE
Your script is getting stuck in an infinite loop because you're never advancing the cursor and therefore the value of ##FETCH_STATUS never changes resulting in you adding the same record for the same college ad nauseum. Add FETCH NEXT FROM DUPLICATE_DEGREE INTO #Colleges after the INSERT.
Jake - you don't need a cursor, try this:
DECLARE #DegreeName varchar (256)
SET #DegreeName = SELECT DISTINCT DegreeName from Degrees WHERE DegreeID = 123
INSERT INTO Degree (DegreeName, CollegeID)
SELECT #DegreeName, CollegeID
FROM Colleges WHERE CollegeName <> 'Main Office'

How to create a SQL function which splits comma separated value?

I want to create a function in SQL Server which takes a comma separated string a parameter, splits it and returns one value at a time. The basic idea here is to call that function from a query. Something like this.
CREATE FUNCTION SPLIT_VALUE(#IN_CSV)
RETURN VARCHAR AS
-- LOGIC TO RETURN A SINGLE VALUE FROM CSV
END
I want to call this function from a stored procedure.
CREATE PROCEDURE DEMO_PROC #IN_CSV VARCHAR(5000), #OUT VARCHAR(5000) OUTPUT AS
BEGIN
SELECT #OUT= CONCAT(A.VALUE1,B.VALUE2) FROM TABLE1 A INNER JOIN TABLE2 B ON A.ID=B.ID WHERE A.ID
IN(--CALL THE FUNCTION AND GET ONE VALUE);
END;
I have to create a loop or cursor to point to a particular value every time. Is this practically possible to? If yes then how can I do that?
Like I mention, you'll have to use a CURSOR to do this, however, the fact you want to do it this way infers a (large) design flaw:
DECLARE #value varchar(8000)
DECLARE Delimited_Values CURSOR FAST_FORWARD
FOR
SELECT [value]
FROM STRING_SPLIT('a,b,c,d,e',',')
OPEN Delimited_Values;
FETCH NEXT FROM Delimited_Values
INTO #value;
WHILE ##FETCH_STATUS = 0 BEGIN
SELECT #value; --Do your stuff here
FETCH NEXT FROM Delimited_Values
INTO #value;
END;
CLOSE Delimited_Values;
DEALLOCATE Delimited_Values;

SQL Server a trigger to work on multiple rows updated

I have a problem with trigger which I use for procedure implementation. I use inserted table to collect all rows which user updated and procure procedure. But procedure repeat for ech row separately. How to handle this?
my trigger:
ALTER TRIGGER [dbo].[FormUpdate]
ON [dbo].[FORM]
For UPDATE
AS
BEGIN
SET NOCOUNT ON;
select * into #inserted from (
SELECT i.* from FORM gw
inner join inserted i on gw.FORMID = i.FORMID) t
WHERE t.PREPARING <> 0
IF (SELECT COUNT(*) FROM #inserted) > 0
BEGIN
UPDATE GW
SET PREPARING = 0
FROM FORM GW
INNER JOIN #inserted on GW.FORMID = #inserted.FORMID
EXEC dbo.PREPARING_OF_THE_FORM
END
END
I may be way off but i think i am pretty close.
As it looks right now the Form table is updated and then the stored procedure runs. I am guessing the stored procedure runs some work on the form table. If you want to run it on every row it looks like (i hate to say it) you need a CURSOR.
You will need to create a cursor from your first select something like
select * into #inserted from (
SELECT i.* from FORM gw
inner join inserted i on gw.FORMID = i.FORMID) t
WHERE t.PREPARING <> 0
DECLARE CURSOR inserted_Cursor
FOR
SELECT *
FROM #inserted
OPEN inserted_cursor
FETCH NEXT FROM inserted_cursor
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE GW
SET PREPARING = 0
FROM FORM GW
INNER JOIN #inserted on GW.FORMID = #inserted.FORMID
EXEC dbo.PREPARING_OF_THE_FORM
FETCH NEXT FROM inserted_cursor
END
CLOSE inserted_cursor
DEALLOCATE inserted_Cursor
I haven't had a chance to test this so it may take some fiddling to get it to run. I am not sure what the stored procedure is doing but you will need to make sure it can handle one record at a time. It may be best to not use the stored procedure and just write out the code to ensure it can handle the one row at a time.
Also keep in mind there are better ways to do this but with your specific application and without knowing the architecture this is what i think the best solution for you.

classic asp TSQL no rowset returned

I have some TSQL used in classic asp like this:
Declare #tbl TABLE(some columns)
Declare #somevarables
Declare myCur CURSOR
For
Select something From my_table
Open myCur
Fetch Next From myCur Inti somevarables
While (##Fetch_Status<>-1)
Begin
some processimg
......
Insert Into #tbl(...)
Values(...)
Fetch Next From myCur Inti somevarables
End
Deallocate myCur
Select * From #tbl
The scripts worked well in SQL Query Analyzer. However, when I run it in an ASP page, there's no rowset returned, nor error message.
Who can tell me why?
Thanks!
The problem is that you're inserting multiple times and each time your rows affected count will generate a closed recordset.
Simple fix is to make sure in your T-SQL you first SET NOCOUNT ON;, this will stop the row counts and the only recordset returned will be your end SELECT.

How do I catch a specific exception type from within a stored procedure?

I am writing a stored procedure which iterates over all of the databases on the server and populates a table variable with an aggregate of the data from some of the different databases. Some databases I'm not interested in as they are irrelevant. The problem is when my CURSOR iterates through those databases I don't care about, a SELECT statement is issued on a table that doesn't exist. How can I ignore the Invalid object name exception and continue with my processing?
Edit:
Here is how I was attempting to skip over databases that were irrelevant:
DECLARE db_cursor CURSOR FOR
SELECT name
FROM MASTER.dbo.sysdatabases
WHERE name NOT IN ('master','model','msdb','tempdb')
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #currentDatabaseName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = 'SELECT COUNT(Name) FROM ' + #currentDatabaseName + '.sys.Tables WHERE Name = ''SomeTableICareAbout'''
INSERT INTO #tableSearchResult
EXEC sp_executesql #sql
SET #tableCount = (SELECT COUNT(*) FROM #tableSearchResult WHERE TableCount = 1)
--If the table I care about was found, then do the good stuff
IF #tableCount > 0
...
The problem with this approach is if the executing user (in my case a service account) does not have access to SELECT on the table, then I never know about that error. If the user doesn't have SELECT access, I want that exception to be raised. But, even if the user doesn't have SELECT access, it can SELECT on the sys.Tables view.
You can't catch error 208 directly because it's a name resolution error that is raised at compilation time and before the code is actually executed. The behaviour is documented: see the section called "Errors Unaffected by a TRY…CATCH Construct" for an explanation, and the answers to this question have some interesting comments.
In addition to the 'solution' in the documentation, you can use dynamic SQL; the error will be caught in this example:
begin try
exec('select * from dbo.ThisTableDoesNotExist');
end try
begin catch
select error_number();
end catch;
If you're looping through all databases, there's a good chance you're using dynamic SQL somewhere anyway, so this might suit your case better.
You can catch the error if you are doing it inside a stored procedure (Example documented Here: http://msdn.microsoft.com/en-us/library/ms175976.aspx
Also you can change your dynamic sql to do something like this
SET #sql = '
If Exists(Select Name From ' + #currentDatabaseName + '.sys.Tables
WHERE Name = ''SomeTableICareAbout'')' --+
--Add Whatever the Good Stuff is
EXEC sp_executesql #sql
But checking if the table exists first, instead of doing the select count(1) from the table, will prevent that error from being raised.

Resources