如何使用游标从多个表中获取信息?
How get information from multiple tables using cursor?
我有一个查询,returns 多个表,类似于:
SELECT TableName, DatabaseName +'.'+ TableName, ColumnName
FROM DBC.Columns
WHERE ColumnName = 'id'
我需要通过查看存储在这些表中的信息来遍历这些表,以便仅获取特定的表。
我尝试了类似下面的代码,使用 'LOOP' 和光标,但它说 Query is invalid
(代码取自 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;
我该如何实际处理这个问题?我还需要使用程序吗?数据库管理系统是 Teradata
如果这是 SQL 服务器,您可以检查以下内容 SQL cursor,我编辑了游标声明和其中的代码
虽然可能和你的要求不一样,但我觉得你可以轻松修改
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;
在SQL服务器上,sp_MsForEachTable可以使用未记录的存储过程来代替像游标这样的循环结构
请检查下面的SQL命令
EXEC sp_MSForEachTable 'IF EXISTS(select * from sys.columns where name = ''Id'' and object_id = object_id(''?''))SELECT ''?'', COUNT(*) FROM ?'
如果您使用 sp_msforeachtable 或 sp_msforeachdb,语法可能会比较困难,但您可以在网上找到示例
您可以创建一个变量来保存行数并将其设置为等于计数:
DECLARE @count INT
SELECT @count = COUNT(*)
FROM prd3_db_tmd.K_PTY_NK01
WHERE id = 0
然后使用 if 语句 select table 如果它有符合您条件的行:
IF @count > 0
BEGIN
SELECT tbName
END
另请注意,如果您的 CASE 语句前面没有 SELECT,则语法无效,如果您不这样做,您可能想尝试在 CASE 前面添加 SELECT不喜欢上面说的方式
您需要使用动态SQL。如果您需要查看 table 上的信息,您可以创建一个同义词。
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;
或者,如果需要,您可以创建一个视图。
您需要一个存储过程,因为这是您可以在 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;
我有一个查询,returns 多个表,类似于:
SELECT TableName, DatabaseName +'.'+ TableName, ColumnName
FROM DBC.Columns
WHERE ColumnName = 'id'
我需要通过查看存储在这些表中的信息来遍历这些表,以便仅获取特定的表。
我尝试了类似下面的代码,使用 'LOOP' 和光标,但它说 Query is invalid
(代码取自 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;
我该如何实际处理这个问题?我还需要使用程序吗?数据库管理系统是 Teradata
如果这是 SQL 服务器,您可以检查以下内容 SQL cursor,我编辑了游标声明和其中的代码 虽然可能和你的要求不一样,但我觉得你可以轻松修改
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;
在SQL服务器上,sp_MsForEachTable可以使用未记录的存储过程来代替像游标这样的循环结构
请检查下面的SQL命令
EXEC sp_MSForEachTable 'IF EXISTS(select * from sys.columns where name = ''Id'' and object_id = object_id(''?''))SELECT ''?'', COUNT(*) FROM ?'
如果您使用 sp_msforeachtable 或 sp_msforeachdb,语法可能会比较困难,但您可以在网上找到示例
您可以创建一个变量来保存行数并将其设置为等于计数:
DECLARE @count INT
SELECT @count = COUNT(*)
FROM prd3_db_tmd.K_PTY_NK01
WHERE id = 0
然后使用 if 语句 select table 如果它有符合您条件的行:
IF @count > 0
BEGIN
SELECT tbName
END
另请注意,如果您的 CASE 语句前面没有 SELECT,则语法无效,如果您不这样做,您可能想尝试在 CASE 前面添加 SELECT不喜欢上面说的方式
您需要使用动态SQL。如果您需要查看 table 上的信息,您可以创建一个同义词。
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;
或者,如果需要,您可以创建一个视图。
您需要一个存储过程,因为这是您可以在 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;