How get information from multiple tables using cursor? - sql

I have a query, that returns multiple tables, something like that:
SELECT TableName, DatabaseName +'.'+ TableName, ColumnName
FROM DBC.Columns
WHERE ColumnName = 'id'
And I need to loop through these tables by looking to the information stored in these tables, in order to get only specific tables.
I tried something like code below, using 'LOOP' and cursor, but it says that Query is invalid (code have been taken from here):
DECLARE cursor_Tables CURSOR FOR
SELECT DatabaseName || '.' || TableName
FROM DBC.Columns
WHERE ColumnName ='id';
OPEN cursor_Tables;
label1:
LOOP
FETCH cursor_Tables into tbName;
IF (SQLSTATE ='02000') THEN
LEAVE label1;
END IF;
CASE WHEN (
SELECT COUNT(*)
FROM prd3_db_tmd.K_PTY_NK01
WHERE id = 0 ) > 0
THEN tbName
END
END LOOP label1;
CLOSE cursor_Tables;
END;
How can I actually deal with this problem? Do I need to use procedure in addition? DBMS is Teradata

You need a Stored Procedure because this is the only place where you can use a cursor in Teradata.
REPLACE PROCEDURE testproc()
DYNAMIC RESULT SETS 1
BEGIN
DECLARE tbName VARCHAR(257);
DECLARE SqlStr VARCHAR(500);
-- temporary table to store the result set
CREATE VOLATILE TABLE _vt_(tbName VARCHAR(257)) ON COMMIT PRESERVE ROWS;
-- your existing query to return the table name
-- Better use ColumnsV instead of Columns
FOR cursor_Tables AS
SELECT DatabaseName || '.' || TABLENAME AS tbName
FROM DBC.ColumnsV
WHERE ColumnName ='id'
DO -- prepare the dynamic SQL ...
SET SqlStr =
'insert into _vt_
select ''' || cursor_tables.tbName || '''
from ' || cursor_tables.tbName || '
where id = 0
having count(*) > 0;
';
-- ... and run it
EXECUTE IMMEDIATE SqlStr;
END FOR;
BEGIN -- return the result set
DECLARE resultset CURSOR WITH RETURN ONLY FOR S1;
SET SqlStr = 'SELECT * FROM _vt_;';
PREPARE S1 FROM SqlStr;
OPEN resultset;
END;
DROP TABLE vt;
END;

If this is SQL Server you can check following SQL cursor, I edited the cursor declaration and the code within
Although they may differ from your requirement, I think you can modify easily
declare #sql nvarchar(max)
declare #tablename nvarchar(100)
DECLARE cursor_Tables CURSOR FOR
SELECT s.name + '.' + o.name
--s.name [schema], o.name [table]
FROM sys.Columns c
inner join sys.objects o on c.object_id = o.object_id
inner join sys.schemas s on s.schema_id = o.schema_id
WHERE c.Name ='id' and o.type = 'U'
/*
SELECT TableName, DatabaseName +'.'+ TableName, ColumnName
FROM DBC.Columns
WHERE ColumnName = 'id'
*/
OPEN cursor_Tables;
FETCH NEXT FROM cursor_Tables INTO #tablename
WHILE ##FETCH_STATUS = 0
BEGIN
-- print #tablename
set #sql = 'select case when count(*) > 0 then ''' + #tablename + ''' else '''' end from ' + #tablename
exec sp_executesql #sql
FETCH NEXT FROM cursor_Tables INTO #tablename
END
CLOSE cursor_Tables;
DEALLOCATE cursor_Tables;

On SQL Server, sp_MsForEachTable undocumented stored procedure can be used instead of a loop structure like a cursor
Please check the below SQL command
EXEC sp_MSForEachTable 'IF EXISTS(select * from sys.columns where name = ''Id'' and object_id = object_id(''?''))SELECT ''?'', COUNT(*) FROM ?'
The syntax may be difficult if you are using the sp_msforeachtable or sp_msforeachdb, but you can find samples on the web

You could create a variable to hold the number of rows and set it equal to the count:
DECLARE #count INT
SELECT #count = COUNT(*)
FROM prd3_db_tmd.K_PTY_NK01
WHERE id = 0
Then use an if statement to select the table if it has rows that meet your criteria:
IF #count > 0
BEGIN
SELECT tbName
END
Also as a side note without having SELECT in front of your CASE statement the syntax is invalid, you may want to try it with just adding SELECT in front of CASE if you don't like the way mentioned above

You need to use dynamic SQL. If you need to see the info on the table, you can create a synonym.
CURSOR cursor_Tables is
SELECT DatabaseName || '.' || TableName AS tbName
FROM DBC.Columns
WHERE ColumnName ='id';
begin
FOR R IN cursor_Tables
LOOP
execute immediate 'CREATE OR REPLACE SYNONYM your_synonym FOR '|| R.tbName ;
select *
from your_synonym;
END LOOP;
END;
Or if you want you can create a view.

Related

Moving a number of tables from one database to another using a linkedserver

Moving one table at the time is no problem, I have the query for that, but I have a larger number of tables that I will need to extract several times, so I would like a script that did it for me.
Basically it's this code I need in sql but don't know how to write it. Executed from the DB they should end up in.
for #TableName in ('TABLE1','TABLE2','TABLE3')
SELECT *
INTO SCHEMA.#TableName
FROM
OPENQUERY (LINKEDSERVER,'SELECT * FROM #TableName')
End
You could use a cursor fom a list of your tables and loop through that. Then to add in more tables, you just add them to list_of_tables:
declare #tablename nvarchar(128);
declare #sqlquery nvarchar(max);
declare d cursor for
select tablename from (
select 'Table1' as tablename
union
select 'Table2' as tablename
union
select 'Table3' as tablename ) as list_of_tables;
open d;
fetch next from d into #tablename;
while ##fetch_status = 0
begin
set #sqlquery = 'SELECT * INTO SCHEMA.' + QUOTENAME(#TableName) + '
FROM
OPENQUERY (LINKEDSERVER,''SELECT * FROM ' + QUOTENAME(#TableName)+ ''');'
exec (#sqlquery);
fetch next from d into #tablename;
end;
close d;
deallocate d;
You can generate script from sys.objects
Such as:
SELECT
'SELECT *
INTO Schema.' + SO.name + '
FROM
OPENQUERY(LINKEDSERVER, ''SELECT * FROM ' + SO.name + ''')
'
FROM
OPENQUERY(LINKEDSERVER
, 'SELECT * FROM sys.objects WHERE type = ''U''') SO

SQL: Looping through a column, stored the value as a variable, run SQL, then move on to the next line?

I'm currently shifting roles at my job and trying to teach myself some SQL Skills.
Scenario: I'm in charge of 1 database - 10 tables with 10 Primary Keys. Every month, our code team publishes updates to the tables. I am suppose to drop the tables and generate scripts to create the updated tables.
Rather than just drop the old tables and stored procedures, I want to rename my current tables to preserve the structure/data for whatever reason.
In my database, I have an additional table called "TableUpdateList" with 1 column "TableName" and 10 rows - each row containing the name of the updated column (Row 1 = TableName1, Row 2 = TableName2, Row 3 = TableName3)
I would like to be able to "loop" through the TableUpdateList Table and insert each value into a set of SQL statements.
For Example, here are the SQL statements I want to run:
--drop the previous backup table
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_NAME = '*TableName1*'+'_Old') DROP TABLE TableName1_Old
-- rename the current tables to _old
EXEC sp_rename *TableName1*, TableName1_Old;
I'm trying to find a way to scroll through the column of my TableUpdateList and run the above two statements filling in where I've italicized with whatever value is present in that row.
Just taking a wild stab because I think in order to get an answer here, you have to try something so here is my pseudo-code:
Declare #TableNames as List
For i in #TableNames
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_NAME = '*i*'+'_Old') DROP TABLE TableName1_Old
-- rename the current tables to _old
EXEC sp_rename *i*, TableName1_Old;
Oi, thanks in advance for any help or a point in the right direction to where I could do some further reading about the above online.
You can use sp_executesql with CURSORS for such type of work. Here is what i think you need:
Test objects:
CREATE TABLE TableName1 ( ID INT )
GO
CREATE TABLE TableName2 ( ID INT )
GO
CREATE TABLE TableNames ( Name NVARCHAR(MAX) )
GO
INSERT INTO TableNames
VALUES ( 'TableName1' ),
( 'TableName2' )
Script itself:
DECLARE #name NVARCHAR(MAX) ,
#dropStatement NVARCHAR(MAX),
#renameStatement NVARCHAR(MAX)
DECLARE cur CURSOR FAST_FORWARD READ_ONLY
FOR
SELECT Name
FROM dbo.TableNames
OPEN cur
FETCH NEXT FROM cur INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
IF EXISTS ( SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #name + '_Old' )
BEGIN
SET #dropStatement = 'DROP TABLE ' + #name + '_Old'
EXEC sp_executesql #dropStatement
END
SET #renameStatement = 'sp_rename ' + #name + ', ' + #name + '_Old';
EXEC sp_executesql #renameStatement
FETCH NEXT FROM cur INTO #name
END
CLOSE cur
DEALLOCATE cur
After this you should add TableName1 and TableName2 again.
Cursors must be avoided as long as possible.
--Preparing script which would check if the old tables exists. If it does,
--it drops the old table
--e.g. first the value 'Table1' is found in TableUpdateList table.
--Then, Table1_Old is deleted and Table1 is renamed to Table1_Old
SELECT 'DROP TABLE ' + b.name + '_Old; EXEC sp_rename ''' + b.name+ ''', ''' + b.name+ '_Old;''' AS [Action]
INTO #Action
FROM INFORMATION_SCHEMA.TABLES A JOIN TableUpdateList B ON A.TABLE_NAME = b.NAME + '_Old'
DECLARE #sql VARCHAR(8000)
SELECT #sql = COALESCE(#sql + ' ', '') + [Action]
FROM #Action
select #sql
--EXEC (#sql)
First verify the value of variable #sql. Then, uncomment the last line to execute the code.
SQL fiddle

Use a variable for table name [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
how do find the number of rows in a table when the table name is in a variable?
I need to find tables in a SQL Server database (2000) that contain one value for a column.
I can use the following query to output a list of possible candidate tables containing my_column:
SELECT DISTINCT TABLE_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME = 'my_column'
What I would like to get at, is the following pseudo query with result:
select '$TABLE_NAME', count(*) from $TABLE_NAME where my_column = '12345'
table01 1
table02 5
table03 0
table04 3
Or more generally formulated: Is it possible to make the FROM-clause variable?
Only way it's possible is by using dynamic SQL:
declare #stmt nvarchar(max), #value nvarchar(max)
select #stmt = isnull(#stmt + ' union all ', '') + '
select ''' + TABLE_NAME + ''', count(*) from ' + TABLE_NAME + ' where my_column = #value'
from INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME = 'my_column'
select #value = '12345'
exec sp_executesql
#stmt = #stmt,
#params = N'#value nvarchar(max)',
#value = #value
update:
For SQL 2000 you can use nvarchar(4000) If you have really big number of tables, you can use temporary table + cursor:
create table #Temp_Results (table_name nvarchar(128), cnt int)
declare #stmt nvarchar(4000), #value nvarchar(128)
declare t_cursor cursor local fast_forward for
select
'select ''' + TABLE_NAME + ''', count(*) from ' + TABLE_NAME + ' where id = #value'
from INFORMATION_SCHEMA.COLUMNS
where COLUMN_NAME = 'name'
select #value = 1
open t_cursor
fetch t_cursor into #stmt
while ##fetch_status = 0
begin
insert into #Temp_Results
exec sp_executesql
#stmt = #stmt,
#params = N'#value nvarchar(128)',
#value = #value
fetch t_cursor into #stmt
end
close t_cursor
deallocate t_cursor
select * from #Temp_Results
You can use the sp_MSforeachtable undocumented stored procedure to make the FROM clause variable.Here is an article that shows how to use it: sp_msForEachTable examples
If I understand the question, you want a list of tables containing a given column name and a record count from each table, yes? If so
select o.name as "Table Name", i.rowcnt as "Rows"
from sysobjects o
inner join sysindexes i on o.id = i.id
where i.indid in (0,1)
and o.id in
(select distinct id from syscolumns where name = 'My_Column')
order by o.name
Requires that you have ability to query system tables.

Select from table, name is stored in the field

How can I join some data from some table whose name is a field of the dataset?
Like this:
SELECT *
FROM dataset
INNER JOIN dataset.table_name
ON dataset.param_id = (dataset.table_name).id_(dataset.table_name)
You will have to construct the select statement as a string using T-SQL. Then, use the execute command to run it. For example:
DECLARE #sql VARCHAR(MAX);
DECLARE #table_name VARCHAR(100);
SET #table_name = (SELECT TOP 1 table_name FROM dataset) ' TODO set criteria correctly here
SELECT #sql = 'SELECT * FROM dataset INNER JOIN ' & #table_name & ' ON dataset.param_id = ' & #table_name & '.id_' & #table_name & ';'
EXEC (#sql)
Update
This is the syntax for Oracle (quoted from Andrewst's answer here):
DECLARE
TYPE rc_type REF CURSOR;
rc rc_type;
table_rec table%ROWTYPE;
BEGIN
OPEN rc FOR 'select * from table';
LOOP
FETCH rc INTO table_rec;
EXIT WHEN rc%NOTFOUND;
-- Process this row, e.g.
DBMS_OUTPUT.PUT_LINE( 'Name: '||table_rec.name );
END LOOP;
END;
http://www.dbforums.com/oracle/718534-ms-sql-exec-equivalent.html

Drop group of stored procedures by name

I have group of stored procedures with names like 'somename_%'. Are there any way to delete that SP with one query, forexample
DROP PROCEDURE where name like
'somename_%'
.
This works for MSSQL 2005 +
DECLARE #DropScript varchar(max)
set #DropScript = ''
SELECT #DropScript = #DropScript + 'DROP PROCEDURE [' + schema_name(schema_id)+ '].' + '[' + name + ']
' FROM sys.procedures
where name like 'somename_%'
exec (#DropScript)
You can generate the DDL by querying the data dictionary. For example, in Oracle:
SELECT 'DROP PROCEDURE "'||owner||'"."'||object_name||'";'
FROM all_procedures
WHERE procedure_name IS NULL
AND lower(object_name) LIKE 'somename_%';
The way I always tend to do these kind of things is just extract the list procedures from the system tables using my critierion and then create the command list - either direct in sql e.g. SELECT 'DROP PROCEDURE ' + procName FROM system_procedures_table WHERE procName like... or in Excel.
In MS_Sql-Server you cn create a Statement with all the relevant Procedures to drop through (ab)using the "FOR XML PATH ('')" clause...
BEGIN TRANSACTION;
GO
CREATE PROC Test_1 AS
BEGIN;
PRINT '1'
END;
GO
CREATE PROC Test_2 AS
BEGIN;
PRINT '2'
END;
GO
SELECT * FROM sys.objects WHERE name LIKE 'Test%' AND TYPE = 'P';
DECLARE #Stmt NVARCHAR(MAX);
SET #Stmt = ( SELECT 'DROP PROC ' + STUFF (x.Stmt, 1, 2, SPACE(0))
FROM (SELECT ', ' + SCHEMA_NAME(Obj.Schema_ID) + CHAR(46) + Obj.Name
FROM sys.objects AS Obj
WHERE Obj.name LIKE 'Test%'
AND obj.TYPE = 'P'
FOR XML PATH ('')
) AS X (Stmt)
);
SELECT #Stmt;
EXEC sp_ExecuteSQL #Stmt;
SELECT * FROM sys.objects WHERE name LIKE 'Test%' AND TYPE = 'P';
ROLLBACK;
Check this TSQL script that automatically drops a list of stored procedures.