Query to find row count of tables based on column name? - sql

I have been trying to find out total count of rows in each tables which are de-activated.
In my DB I have 20 tables with column IsActive.
I have tried below cursor,however it is getting error saying Invalid object name #Namee.
Create table #t
(
NoOfRows bigint,
)
Declare #Namee Varchar(500)
Declare #GetName Cursor
Set #Getname = Cursor for
Select table_name from information_Schema.columns
where column_name='isactive'Open #Getname
Fetch Next From #Getname into #Namee
While ##Fetch_Status=0
Begin
insert into #t Select count(*) from #Namee where isactive=0
Fetch Next From #Getname into #Namee
End
Close #GetName
Deallocate #GetName
select * from #t

Try this:
exec sp_msforeachtable '
if exists(
select * from sys.tables as t
join sys.columns as c on t.object_id = c.object_id
where t.name = ''?'' and c.name = ''IsActive'')
select count(*)
from [?]
where isactive=0'

Based on your example query, this should work. It will also be much faster than using the cursor
select
OBJECT_NAME(c.object_id) as table_name
, p.row_count
from sys.columns c
join sys.dm_db_partition_stats p
on c.object_id = p.object_id
and p.index_id < 2
where c.name = 'IsActive'

While I haven't tested them, I would go with either Mike's or Denis's answer.
However, the problem here is the line:
insert into #t Select count(*) from #Namee where isactive=0
you are using #Namee like it is a table, but it is really a string with a table name. You would have to build the SQL dynamically and then exec it:
exec 'insert into #t select count(*) from ' + #Namee + ' where isactive=0'

Replace
insert into #t Select count(*) from #Namee where isactive=0
with
exec ('insert into #t Select count(*) from ' + #Namee + ' where isactive=0')

Related

How to use loop for like or ilike function?

I am currently asked to validate the result of a global search which to find all records containing some keywords cross whole database. To do so, I need to check all the rows in each table that have keywords. The result for this global search is ready and partially of the result looks like the one below:
table_name
column_name
keyword
cnt
Wf_Process
Name_EN
FEC
11
Wf_Process
FTABLENAME
GB
14
ICCClass
Name_EN
GB
4
What I am trying to do is using the 'like' operator to extract all the data in each table where columns containing keywords. That is, I will use query such as:
select distinct Name_EN, FTABLENAME from Wf_Process where Name_EN like '%FEC%' or FTABLENAME like '%GB%'
and
select distinct Name_EN from ICCClass where Name_EN like '%GB%'
to pull out all data I need in whole database. If I only have three records, then it is not a problem. However my result returned over thousands tables have more than 10K rows containing keywords in total. Therefore, I was trying to use a loop to do this mission but I failed.
My question therefore is, does anyone have any idea to write a loop to do the 'like' search for all the tables in one time? Or is there another way rather than loop can do this in SQL Server?
Thank you very much!
You need dynamic SQL for this. You can generate a big UNION ALL query of all the tables together.
DECLARE #sql nvarchar(max) = (
SELECT STRING_AGG(CAST('
SELECT
' + QUOTENAME(con.table_name, '''') + ' table_name,
' + QUOTENAME(con.column_name, '''') + ' column_name,
' + QUOTENAME(con.keyword, '''') + ' keyword,
COUNT(*) cnt
FROM ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) + ' t
WHERE t.' + QUOTENAME(c.name) + ' LIKE ' + QUOTENAME('%' + con.keyword + '%', '''')
AS nvarchar(max)), '
UNION ALL')
FROM YourConditions con
JOIN sys.tables t ON t.table_name
JOIN sys.schemas s ON s.schema_id = t.schema_id
JOIN sys.columns c ON c.object_id = t.object_id
WHERE t.name = con.table_name
AND c.name = con.column_name
);
PRINT #sql; -- your friend
EXEC sp_executesql #sql;
There are more efficient ways to do this if there are many columns or keywords per table, but this should get you started.
The question looks odd, thou can be done via dynamic sql, but not as a regular solution more like a one off or POC/test.
use tempdb
GO
drop table if exists search_result
go
create table search_result (
table_name sysname
,column_name sysname
,keyword varchar(100))
go
insert into search_result values
('Wf_Process', 'Name_EN', 'FEC')
,('Wf_Process' , 'FTABLENAME', 'GB')
,('ICCClass', 'Name_EN', 'GB')
GO
drop table if exists result
create table result (val varchar(500))
go
declare #col sysname
declare #tab sysname
declare #kw varchar(100)
declare #sql varchar(1000)
while exists (select * from search_result)
begin
select top 1
#tab = table_name
, #col = column_name
, #kw = keyword
from search_result
set #sql = concat('insert into result select ', #col, ' from ', #tab, ' where ', #col, ' like ''%', #kw, '%''' )
print(#sql)
exec (#sql)
delete from search_result
where table_name = #tab and column_name = #col and keyword = #kw
end
GO
select * from result
--initially trying to get all the column name with its respective table name, finding out if there is that particular keyword in all table,
--if yes, insert into temp table, if there aint keyword, it will insert the record too but the count of record will be zero.
--trying to make it dynamic and running it inside the loop by assigning row number to each table with different column.
IF OBJECT_ID('tempdb..#TEMP') IS NOT NULL
DROP TABLE #TEMP
CREATE TABLE #TEMP (TABLE_NAME NVARCHAR(200), COLUMN_NAME NVARCHAR(200), KEYWORD NVARCHAR(200), CNT INT)
DECLARE #TABLE NVARCHAR(200)
DECLARE #TABLE_ID INT
SET #TABLE_ID = 1
DECLARE #TABLE_NAME NVARCHAR (200)
DECLARE #FOR_LOOP INT
DECLARE #COLUMN NVARCHAR(200)
DECLARE #COLUMN_NAME NVARCHAR(200)
--TOTAL NO OF RECORDS FOR LOOP
SET #FOR_LOOP = (SELECT COUNT(*)
FROM SYS.tables T
JOIN SYS.all_columns C ON T.object_id = C.object_id
JOIN INFORMATION_SCHEMA.TABLES S ON S.TABLE_NAME = T.name)
DECLARE #STRINGS NVARCHAR(200)
SET #STRINGS = '%FEC%' --------->ENTER YOUR KEYWORD HERE, TRY ONE AT A TIME
DECLARE #COUNT INT
WHILE #TABLE_ID <= #FOR_LOOP
BEGIN
SET #TABLE = (SELECT CAST(TABLE_NAME AS NVARCHAR(200))
FROM
(SELECT ROW_NUMBER()OVER(ORDER BY T.NAME) TABLE_ID
,S.TABLE_SCHEMA SCHEMA_NAME ,T.NAME TABLE_NAME, C.name COLUMN_NAME
FROM SYS.tables T
JOIN SYS.all_columns C ON T.object_id = C.object_id
JOIN INFORMATION_SCHEMA.TABLES S ON S.TABLE_NAME = T.name)A
WHERE TABLE_ID = #TABLE_ID)
SET #TABLE_NAME = '['+#TABLE+']'
SET #COLUMN = (SELECT CAST(COLUMN_NAME AS NVARCHAR(200))
FROM
(SELECT ROW_NUMBER()OVER(ORDER BY T.NAME) TABLE_ID
,S.TABLE_SCHEMA SCHEMA_NAME ,T.NAME TABLE_NAME, C.name COLUMN_NAME
FROM SYS.tables T
JOIN SYS.all_columns C ON T.object_id = C.object_id
JOIN INFORMATION_SCHEMA.TABLES S ON S.TABLE_NAME = T.name)A
WHERE TABLE_ID = #TABLE_ID)
SET #COLUMN_NAME = '['+#COLUMN+']'
DECLARE #EXEC NVARCHAR(200) = 'SELECT ' + #COLUMN_NAME +' FROM ' + #TABLE_NAME + ' WHERE ' + #COLUMN_NAME + ' LIKE ' + ''''+#STRINGS+''''
--THERE MUST BE ANOTHER WAY TO REPLACE SP_EXECUTESQL FOR BETTER PERFORMANCE, AS IT WILL BE EXECUTED AS MANY TIMES AS THERE ARE RECORDS IN #FOR_LOOP
EXEC SP_EXECUTESQL #EXEC
SET #COUNT = (SELECT ##ROWCOUNT)
IF (SELECT ##ROWCOUNT) >=1
BEGIN
INSERT INTO #TEMP VALUES
(#TABLE_NAME, #COLUMN_NAME, #STRINGS, #COUNT)
SET #TABLE_ID = #TABLE_ID + 1
END
ELSE
--DONT KNOW WHY THIS ELSE PART IS NOT TOUCHED, WHEREAS I THINK IT SHOULD HAVE
BEGIN
PRINT 'RECORD NOT FOUND'
END
END
GO
--AFTER THE ABOVE BLOCK IS EXECUTED THEN TRY RUNNING BELOW ONE
SELECT *FROM #TEMP WHERE CNT>0
--THERE MAY BE MULTIPLE ERROS, MUST BE EDITED AND CAN MAKE IT AS A PROCEDURE TOO.

SQL Server SELECT where any column contains 'x'

Using SQL Server 2008, say I have a table called testing with 80 columns and I want to find a value called foo.
I can do:
SELECT *
FROM testing
WHERE COLNAME = 'foo'
Is it possible I can query all 80 columns and return all the results where foo is contained in any of the 80 columns?
You can use in:
SELECT *
FROM testing
WHERE 'foo' in (col1, col2, col3, . . . );
First Method(Tested)
First get list of columns in string variable separated by commas and then you can search 'foo' using that variable by use of IN
Check stored procedure below which first gets columns and then searches for string:
DECLARE #TABLE_NAME VARCHAR(128)
DECLARE #SCHEMA_NAME VARCHAR(128)
-----------------------------------------------------------------------
-- Set up the name of the table here :
SET #TABLE_NAME = 'testing'
-- Set up the name of the schema here, or just leave set to 'dbo' :
SET #SCHEMA_NAME = 'dbo'
-----------------------------------------------------------------------
DECLARE #vvc_ColumnName VARCHAR(128)
DECLARE #vvc_ColumnList VARCHAR(MAX)
IF #SCHEMA_NAME =''
BEGIN
PRINT 'Error : No schema defined!'
RETURN
END
IF NOT EXISTS (SELECT * FROM sys.tables T JOIN sys.schemas S
ON T.schema_id=S.schema_id
WHERE T.Name=#TABLE_NAME AND S.name=#SCHEMA_NAME)
BEGIN
PRINT 'Error : The table '''+#TABLE_NAME+''' in schema '''+
#SCHEMA_NAME+''' does not exist in this database!'
RETURN
END
DECLARE TableCursor CURSOR FAST_FORWARD FOR
SELECT CASE WHEN PATINDEX('% %',C.name) > 0
THEN '['+ C.name +']'
ELSE C.name
END
FROM sys.columns C
JOIN sys.tables T
ON C.object_id = T.object_id
JOIN sys.schemas S
ON S.schema_id = T.schema_id
WHERE T.name = #TABLE_NAME
AND S.name = #SCHEMA_NAME
ORDER BY column_id
SET #vvc_ColumnList=''
OPEN TableCursor
FETCH NEXT FROM TableCursor INTO #vvc_ColumnName
WHILE ##FETCH_STATUS=0
BEGIN
SET #vvc_ColumnList = #vvc_ColumnList + #vvc_ColumnName
-- get the details of the next column
FETCH NEXT FROM TableCursor INTO #vvc_ColumnName
-- add a comma if we are not at the end of the row
IF ##FETCH_STATUS=0
SET #vvc_ColumnList = #vvc_ColumnList + ','
END
CLOSE TableCursor
DEALLOCATE TableCursor
-- Now search for `foo`
SELECT *
FROM testing
WHERE 'foo' in (#vvc_ColumnList );
2nd Method
In sql server you can get object id of table then using that object id you can fetch columns. In that case it will be as below:
Step 1: First get Object Id of table
select * from sys.tables order by name
Step 2: Now get columns of your table and search in it:
select * from testing where 'foo' in (select name from sys.columns where object_id =1977058079)
Note: object_id is what you get fetch in first step for you relevant table
You can use in and you can get the column names dynamically and pass them to IN clause by making sql string and executing it using execute sp_executesql.
declare #sql nvarchar(2100)
declare #cols nvarchar(2000)
declare #toSearch nvarchar(200)
declare #tableName nvarchar(200)
set #tableName = 'tbltemp'
set #toSearch = '5'
set #cols =(
SELECT LEFT(column_name, LEN(column_name) - 1)
FROM (
SELECT column_name + ', '
FROM INFORMATION_SCHEMA.COLUMNS where table_name = #tableName
FOR XML PATH ('')
) c (column_name )
)
set #sql = 'select * from tbltemp where '''+ #toSearch + ''' in (' + #cols + ')';
execute sp_executesql #sql
I think this is one of the best ways of doing it
SELECT * FROM sys.columns a
inner join
(
SELECT object_id
FROM sys.tables
where
type='U'--user table
and name like 'testing'
) b on a.object_id=b.object_id
WHERE a.name like '%foo%'
I took the idea from ubaid ashraf's answer, but made it actually work. Just change MyTableName here:
SELECT STUFF((
SELECT ', ' + c.name
FROM sys.columns c
JOIN sys.types AS t ON c.user_type_id=t.user_type_id
WHERE t.name != 'int' AND t.name != 'bit' AND t.name !='date' AND t.name !='datetime'
AND object_id =(SELECT object_id FROM sys.tables WHERE name='MyTableName')
FOR XML PATH('')),1,2,'')
You could tweak it to your needs and add or remove conditions from the where column (the 't.name != 'int' AND t.name != 'bit' etc. part), e.g. add 't.name != 'uniqueidentifier'' to avoid getting Conversion failed when converting the varchar value 'myvalue' to data type int type of errors..
Then copy paste the result into this query (otherwise it didn't work):
SELECT * from MyTableName where 'foo' in (COPY PASTE PREVIOUS QUERY RESULT INTO HERE)
--Obtain object_id
SELECT object_id FROM sys.tables WHERE name = <your_table>
--look for desired value in specified columns using below syntax
SELECT * FROM <your_table> WHERE <VALUE_YOU_SEARCH_FOR> in
(SELECT name FROM sys.tables WHERE object_id = <your_table_object_id>
and name like '<if_you_have_multiple_columns_with_same_name_pattern>')
I've worked with BornToCode's answer and this script generates the queries to find a value in all columns of type varchar for any view (can be table) of the database:
DECLARE #id INT
declare #name nvarchar(30)
DECLARE #getid CURSOR
declare #value nvarchar(30)
set #value = 'x'
SET #getid = CURSOR FOR
SELECT object_id,name
FROM sys.views
OPEN #getid
FETCH NEXT
FROM #getid INTO #id, #name
WHILE ##FETCH_STATUS = 0
BEGIN
---------
SELECT 'SELECT * from ' + #name + ' where ''' + #value + ''' in (' +
STUFF((
SELECT ', ' + c.name
FROM sys.columns c
JOIN sys.types AS t ON c.user_type_id=t.user_type_id
WHERE t.name = 'varchar'-- AND t.name != 'bit' AND t.name !='date' AND t.name !='datetime'
AND object_id =(SELECT object_id FROM sys.views WHERE name=#name)
FOR XML PATH('')),1,2,'')
+ ')' as 'query'
------
FETCH NEXT
FROM #getid INTO #id, #name
END
CLOSE #getid
DEALLOCATE #getid

SQL Query to get table name and number of rows based on column name"

I have declared a Cursor to get table names and no of columns in that tables based on column names.Please find the below query table name is not get inserted.Please suggest.
Create table #t
(
tabname varchar(500),
NoOfRows bigint,
)
Declare #Namee Varchar(500)
Declare #GetName Cursor
Set #Getname = Cursor for
Select table_name from information_Schema.columns
where column_name='isactive'Open #Getname
Fetch Next From #Getname into #Namee
While ##Fetch_Status=0
Begin
--Print #Namee
insert into #t(tabname) SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME =' + #Namee + '
exec ('insert into #t(NoOfRows) Select count(*) from ' + #Namee + ' where isactive=0')
Fetch Next From #Getname into #Namee
End
Close #GetName
Deallocate #GetName
select * from #t
You can insert the table name and number of rows in a single INSERT:
EXEC('INSERT INTO #t
(tabname, NoOfRows)
SELECT '''+ #Namee +''', COUNT(*)
FROM ' + #Namee + '
WHERE isactive = 0')
What you have makes no link between the table name and the count, so it's unlikely you're missing a table but it is doubtful that the NoOfRows was actually associated with the table name in the record.
Here is a better way to get the tables you want (won't have some issues with catalog and schema overlap)
declare #colname varchar(max)
set #colname = 'isactive'
SELECT table_name from information_schema.tables t
join information_schema.columns c on t.table_catalog = c.table_catalog and
t.table_schema = c.table_schema and
t.table_name = c.table_name and
column_name = #colname
You are doing two inserts into your temporary table, one for the table name (With no count) and one for the count with no table name.
See OMG Ponies for the SQL to replace yours with and remove the insert with just a table name

How to fetch the row count for all tables in a SQL SERVER database [duplicate]

This question already has answers here:
Query to list number of records in each table in a database
(23 answers)
Closed 8 years ago.
I am searching for a SQL Script that can be used to determine if there is any data (i.e. row count) in any of the tables of a given database.
The idea is to re-incarnate the database in case there are any rows existing (in any of the database).
The database being spoken of is Microsoft SQL SERVER.
Could someone suggest a sample script?
The following SQL will get you the row count of all tables in a database:
CREATE TABLE #counts
(
table_name varchar(255),
row_count int
)
EXEC sp_MSForEachTable #command1='INSERT #counts (table_name, row_count) SELECT ''?'', COUNT(*) FROM ?'
SELECT table_name, row_count FROM #counts ORDER BY table_name, row_count DESC
DROP TABLE #counts
The output will be a list of tables and their row counts.
If you just want the total row count across the whole database, appending:
SELECT SUM(row_count) AS total_row_count FROM #counts
will get you a single value for the total number of rows in the whole database.
If you want to by pass the time and resources it takes to count(*) your 3million row tables. Try this per SQL SERVER Central by Kendal Van Dyke.
Row Counts Using sysindexes
If you're using SQL 2000 you'll need to use sysindexes like so:
-- Shows all user tables and row counts for the current database
-- Remove OBJECTPROPERTY function call to include system objects
SELECT o.NAME,
i.rowcnt
FROM sysindexes AS i
INNER JOIN sysobjects AS o ON i.id = o.id
WHERE i.indid < 2 AND OBJECTPROPERTY(o.id, 'IsMSShipped') = 0
ORDER BY o.NAME
If you're using SQL 2005 or 2008 querying sysindexes will still work but Microsoft advises that sysindexes may be removed in a future version of SQL Server so as a good practice you should use the DMVs instead, like so:
-- Shows all user tables and row counts for the current database
-- Remove is_ms_shipped = 0 check to include system objects
-- i.index_id < 2 indicates clustered index (1) or hash table (0)
SELECT o.name,
ddps.row_count
FROM sys.indexes AS i
INNER JOIN sys.objects AS o ON i.OBJECT_ID = o.OBJECT_ID
INNER JOIN sys.dm_db_partition_stats AS ddps ON i.OBJECT_ID = ddps.OBJECT_ID
AND i.index_id = ddps.index_id
WHERE i.index_id < 2 AND o.is_ms_shipped = 0 ORDER BY o.NAME
Works on Azure, doesn't require stored procs.
SELECT t.name AS table_name
,s.row_count AS row_count
FROM sys.tables t
JOIN sys.dm_db_partition_stats s
ON t.OBJECT_ID = s.OBJECT_ID
AND t.type_desc = 'USER_TABLE'
AND t.name NOT LIKE '%dss%' --Exclude tables created by SQL Data Sync for Azure.
AND s.index_id IN (0, 1)
ORDER BY table_name;
Credit.
This one looks better than the others I think.
USE [enter your db name here]
GO
SELECT SCHEMA_NAME(A.schema_id) + '.' +
--A.Name, SUM(B.rows) AS 'RowCount' Use AVG instead of SUM
A.Name, AVG(B.rows) AS 'RowCount'
FROM sys.objects A
INNER JOIN sys.partitions B ON A.object_id = B.object_id
WHERE A.type = 'U'
GROUP BY A.schema_id, A.Name
GO
Short and sweet
sp_MSForEachTable 'DECLARE #t AS VARCHAR(MAX);
SELECT #t = CAST(COUNT(1) as VARCHAR(MAX))
+ CHAR(9) + CHAR(9) + ''?'' FROM ? ; PRINT #t'
Output:
SELECT
sc.name +'.'+ ta.name TableName, SUM(pa.rows) RowCnt
FROM
sys.tables ta
INNER JOIN sys.partitions pa
ON pa.OBJECT_ID = ta.OBJECT_ID
INNER JOIN sys.schemas sc
ON ta.schema_id = sc.schema_id
WHERE ta.is_ms_shipped = 0 AND pa.index_id IN (1,0)
GROUP BY sc.name,ta.name
ORDER BY SUM(pa.rows) DESC
SQL Server 2005 or later gives quite a nice report showing table sizes - including row counts etc. It's in Standard Reports - and it is Disc Usage by Table.
Programmatically, there's a nice solution at:
http://www.sqlservercentral.com/articles/T-SQL/67624/
Don't use SELECT COUNT(*) FROM TABLENAME, since that is a resource intensive operation. One should use SQL Server Dynamic Management Views or System Catalogs to get the row count information for all tables in a database.
I would make a minor change to Frederik's solution. I would use the sp_spaceused system stored procedure which will also include data and index sizes.
declare c_tables cursor fast_forward for
select table_name from information_schema.tables
open c_tables
declare #tablename varchar(255)
declare #stmt nvarchar(2000)
declare #rowcount int
fetch next from c_tables into #tablename
while ##fetch_status = 0
begin
select #stmt = 'sp_spaceused ' + #tablename
exec sp_executesql #stmt
fetch next from c_tables into #tablename
end
close c_tables
deallocate c_tables
Here's a dynamic SQL approach that also gives you the schema as well:
DECLARE #sql nvarchar(MAX)
SELECT
#sql = COALESCE(#sql + ' UNION ALL ', '') +
'SELECT
''' + s.name + ''' AS ''Schema'',
''' + t.name + ''' AS ''Table'',
COUNT(*) AS Count
FROM ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name)
FROM sys.schemas s
INNER JOIN sys.tables t ON t.schema_id = s.schema_id
ORDER BY
s.name,
t.name
EXEC(#sql)
If needed, it would be trivial to extend this to run over all databases in the instance (join to sys.databases).
select all rows from the information_schema.tables view, and issue a count(*) statement for each entry that has been returned from that view.
declare c_tables cursor fast_forward for
select table_name from information_schema.tables
open c_tables
declare #tablename varchar(255)
declare #stmt nvarchar(2000)
declare #rowcount int
fetch next from c_tables into #tablename
while ##fetch_status = 0
begin
select #stmt = 'select #rowcount = count(*) from ' + #tablename
exec sp_executesql #stmt, N'#rowcount int output', #rowcount=#rowcount OUTPUT
print N'table: ' + #tablename + ' has ' + convert(nvarchar(1000),#rowcount) + ' rows'
fetch next from c_tables into #tablename
end
close c_tables
deallocate c_tables
This is my favorite solution for SQL 2008 , which puts the results into a "TEST" temp table that I can use to sort and get the results that I need :
SET NOCOUNT ON
DBCC UPDATEUSAGE(0)
DROP TABLE #t;
CREATE TABLE #t
(
[name] NVARCHAR(128),
[rows] CHAR(11),
reserved VARCHAR(18),
data VARCHAR(18),
index_size VARCHAR(18),
unused VARCHAR(18)
) ;
INSERT #t EXEC sp_msForEachTable 'EXEC sp_spaceused ''?'''
SELECT * INTO TEST FROM #t;
DROP TABLE #t;
SELECT name, [rows], reserved, data, index_size, unused FROM TEST \
WHERE ([rows] > 0) AND (name LIKE 'XXX%')
SELECT
SUM(sdmvPTNS.row_count) AS [DBRows]
FROM
sys.objects AS sOBJ
INNER JOIN sys.dm_db_partition_stats AS sdmvPTNS
ON sOBJ.object_id = sdmvPTNS.object_id
WHERE
sOBJ.type = 'U'
AND sOBJ.is_ms_shipped = 0
AND sdmvPTNS.index_id < 2
GO

Constructing the FROM in SQL

I'm looking to pull a specific line from a number of table that have a field name criteria1. The problem I'm having is that when I combine the Owner and Table Name and try to call "select criteria1 from #t where linenum = 1" SQL is expecting #t to be a table. I need to know how to construct the full table name and then pass it to this query. I know I can us a programming language to access the DB but i need this to be in SQL. If someone knows of a better way of doing this that would be great too.
declare #next as varchar
declare #owner varchar
while 1=1
begin
set #next = (select top 1 o.name FROM syscolumns c inner join sysobjects o on c.id = o.id
where c.name = 'criteria1' and o.id > #next order by o.id)
if #next is null
break
else
begin
set #owner = (select top 1 u.name
FROM syscolumns c inner join
sysobjects o on c.id = o.id left join
sysusers u on o.uid=u.uid
where c.name = 'criteria1' and o.id = #next order by o.id)
declare #t as varchar
set #t = #owner+'.'+#next
select criteria1 from #t where linenum = 1
end
continue
end
You can build the entire query you want as a varchar() and then execute it with the sp_executesql stored procedure.
http://msdn.microsoft.com/en-us/library/ms188001.aspx
In your case, that bit at the end becomes
declare #sql varchar(512);
set #sql = 'select criteria1 from ' + #t + ' where linenum = 1'
sp_executesql #sql
Have you considered the following construct in a stored procedure?
CASE #tablename
WHEN 'table1' THEN SELECT * FROM table1
WHEN 'table2' THEN SELECT * FROM table2
WHEN 'table3' THEN SELECT * FROM table3
WHEN 'table4' THEN SELECT * FROM table4
END
In case you're married to dynamic SQL (considered to be a bad choice for this problem space), this guide to dynamic SQL should help a lot. It helped me and I've used dynamic SQL extensively.
Thanks for all the help. This is what I ended up with.
declare cur cursor for
select u.name + '.' + o.name tname
FROM sysobject o left join
syscolumns c on c.id = o.id left join
sysusers u on o.uid=u.uid
where c.name = 'criteria1'
declare #tn as varchar(512)
open cur
fetch next from cur into #tn
create table holding_table ( val varchar(512), table_name varchar(512))
declare #sql nvarchar(1000)
while ##FETCH_STATUS = 0
begin
set #sql = 'insert into holding_table select criteria1, ''' + #tn + ''' from ' + #tn + ' where linenum = 1'
execute sp_executesql #sql
fetch next from cur into #tn
end
close cur
deallocate cur
Maybe a view can be used here?
CREATE VIEW vCriterias
AS
SELECT 'Table1' AS TableName,
linenum,
criteria1
FROM Table1
UNION ALL
SELECT 'Table2' AS TableName,
linenum,
criteria1
FROM Table2
UNION ALL
SELECT 'Table3' AS TableName,
linenum,
criteria1
FROM Table3
go
Then selection is like:
SELECT criteria1
FROM vCriterias
WHERE linenum = 3
AND TableName IN ('Table1','Table3')