Using a variable string in a select * from statement - sql

Is something like this possible?:
DECLARE #test nvarchar(30) = 'Appt'
SELECT * FROM #test.dbo.tablename with (NOLOCK)
or possibly
DECLARE #test nvarchar(30) = 'Appt'
SELECT * FROM #test + '.dbo.tablename' with (NOLOCK)
No, right?
I'm not looking to put the whole string into a variable and then use "EXEC." I have long scripts that I want to just try to replace that with when it occurs.
Thank you.

This requires Dynamic SQL. Basically you create a string that builds the SQL statement dynamically based on your query. That string is then executed with an EXEC Statement. A basic example is like this:
DECLARE #test nvarchar(30) = 'Appt'
DECLARE #sql as varchar(max)
SET #SQL = 'SELECT * FROM' + #test + '.dbo.tablename' + 'with (NOLOCK)'
EXEC #SQL
Assuming your tablename was Appt.dbo.tablename
I think you meant:
SET #SQL = 'SELECT * FROM' + 'dbo.' + #test + ' with (NOLOCK)'

Nice explanation logixologist.
Because Tom wants to run it for multiple select statements, i was thinking he could store all the table names in a column and use a cursor to fetch the table values. Considering you would create a table first such as:
CREATE TABLE tableName ( name varchar(20));
then run the following code once you inserted the right values in the table above.
Declare #table VARCHAR(255)
DECLARE #sql as varchar(max)
SET #SQL = 'SELECT * FROM' + 'dbo.' + #table + ' with (NOLOCK)'
DECLARE table_cursor CURSOR FOR
select distinct([name]) FROM DBname.dbo.tableName
Where [name] is not null
OPEN table_cursor
FETCH Next from table_cursor
INTO #table
WHILE ##FETCH_STATUS =0
BEGIN
EXEC #SQL
FETCH NEXT FROM table_cursor
INTO #table
END
CLOSE table_cursor
DEALLOCATE table_cursor
The cursor would return the table name for the select statement. I think you could use the same logic for insert statements.

Related

Fetch data without using union all every month

Select * from [dbo].[TRNS0119]
union all
Select * from [dbo].[TRNS0219]
union all
Select * from [dbo].[TRNS0319]
union all
Select * from [dbo].[TRNS0419]
In my attendance SQL Server database, every month a new table gets created with in/out records. I have to use union all to fetch data from all 12 month's data. I want to my query to fetch data automatically when new table gets created with a particular name. I am not SA user so can not make any changes / triggers / procedures.
So far I am doing this for every month but I want to know how I can resolve this without any intervention every month
for this solution, you must have same fields in your dynamic tables.
Tablename can be anything in your database, this will works for all tablenames.
Try this if you get your results.
declare #table table([Name] varchar(200))
declare #query VARCHAR(max)
declare #strQuery varchar(max) = '';
set #query='SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES';
insert into #table exec (#query)
--select * from #table (You will get all your table names)
declare #tablename varchar(100)
declare #i int=0
DECLARE curFetchData CURSOR FOR SELECT [Name] from #table
OPEN curFetchData
FETCH NEXT FROM curFetchData INTO #tablename
WHILE ##Fetch_status = 0
BEGIN
IF(#i>0)
set #strQuery = #strQuery + (' UNION ALL ')
set #strQuery = #strQuery + (' SELECT * from '+#tablename+' ')
set #i=#i+1;
FETCH NEXT FROM curFetchData INTO #tablename
END
CLOSE curFetchData
DEALLOCATE curFetchData
PRINT (#strQuery)
EXEC (#strQuery)
Try this query. Please ensure the input parameter.
DECLARE #inputYear INT,#tablename VARCHAR(20)=''
SET #inputYear =2019---- year(getdate())
DECLARE #v nvarchar(30)='TRNS%'+right(convert(varchar(4),#inputyear),2)
DECLARE #query nvarchar(max)=''
SELECT #query=#query+' UNION ALL SELECT * FROM ' + NAME from sys.tables where name like #v
SELECT #query= STUFF(#query,1,10,'')
EXECUTE sp_executesql #query

Looping through a column in SQL table that contains names of other tables

I have fairly new to using SQL, currently I have a table that has a column that contains the names of all the tables I want to use for one query, so what I want to do is to loop through that column and go to every single one of these tables and then search one of their columns for a value (there could be multiple values), so whenever a table contains the value, I will list the name of the table. Could someone give me a hint of how this is done? Is cursor needed for this?
I don't have enough reputation to comment but is the table with the column that contain the table names all in one column, meaning that all the table names are comma separated or marked with some sort of separator? This would cause the query to be a little more complicated as you would have to take care of that before you start looping through your table.
However, this would require a cursor, as well as some dynamic sql.
I will give a basic example of how you can go about this.
declare #value varchar(50)
declare #tableName varchar(50)
declare #sqlstring nvarchar(100)
set #value = 'whateveryouwant'
declare #getTableName = cursor for
select tableName from TablewithTableNames
OPEN #getTableName
fetch NEXT
from #getTableName into #tableName
while ##FETCH_STATUS = 0
BEGIN
set #sqlstring = 'Select Count(*) from ' + #tableName + 'where ColumnNameYouwant = ' + #value
exec #sqlstring
If ##ROWcount > 0
insert into #temptable values (#tableName)
fetch next
from #getTableName into #tableName
END
select * from #temptable
drop table #temptable
close #getTableName
deallocate #getTableName
I'm currently not able to test this out as for time constraint reasons, but this is how I would go about doing this.
You could try something like this:
--Generate dynamic SQL
DECLARE #TablesToSearch TABLE (
TableName VARCHAR(50));
INSERT INTO #TablesToSearch VALUES ('invoiceTbl');
DECLARE #SQL TABLE (
RowNum INT,
SQLText VARCHAR(500));
INSERT INTO
#SQL
SELECT
ROW_NUMBER() OVER (ORDER BY ts.TableName) AS RowNum,
'SELECT * FROM ' + ts.TableName + ' WHERE ' + c.name + ' = 1;'
FROM
#TablesToSearch ts
INNER JOIN sys.tables t ON t.name = ts.TableName
INNER JOIN sys.columns c ON c.object_id = t.object_id;
--Now run the queries
DECLARE #Count INT;
SELECT #Count = COUNT(*) FROM #SQL;
WHILE #Count > 0
BEGIN
DECLARE #RowNum INT;
DECLARE #SQLText VARCHAR(500);
SELECT TOP 1 #RowNum = RowNum, #SQLText = SQLText FROM #SQL;
EXEC (#SQLText);
DELETE FROM #SQL WHERE RowNum = #RowNum;
SELECT #Count = COUNT(*) FROM #SQL;
END;
You would need to change the "1" I am using as an example to the value you are looking for and probably add a CONVERT/ CAST to make sure the column is the right data type?
You actually said that you wanted the name of the table, so you would need to change the SQL to:
'SELECT ''' + ts.TableName + ''' FROM ' + ts.TableName + ' WHERE ' + c.name + ' = 1;'
Another thought, it would probably be best to insert the results from this into a temporary table so you can dump out the results in one go at the end?

Stored procedure to find number of rows in a table

In a stored procedure I pass a table name as the input variable.
I want to return the number of rows of this table with that stored procedure.
I tried something like this but it did not work:
declare #maxRowCount bigint
exec('set '+ #maxRowCount + ' =(select COUNT(1) from ' + #tableName + ')')
This is SQL Server 2008.
You can try this
CREATE PROCEDURE dbo.sp_selectcount
#tablename NVARCHAR(200)
AS
DECLARE #cmd NVARCHAR (255)
SET #cmd = 'SELECT count(*) from ' + #tablename
EXEC sp_executesql #cmd
The following example should give you something to work with.
-- fully qualify your table name (this is probably an input value in your sproc?)
-- please note that I use system view master.sys.tables as an example table here
DECLARE #tablename NVARCHAR(MAX) = N'[master].[sys].[tables]';
-- build the sql statement that you will execute
DECLARE #sql NVARCHAR(MAX) = N'SELECT COUNT(*) FROM ' + #tablename;
-- create a variable to hold the number of rows later on
DECLARE #nrofrows BIGINT;
-- create a temp table to store the result of executing the sql statement
CREATE TABLE #temp (NrOfRows BIGINT);
-- insert the result of the execution of the sql statement into the temp table
INSERT INTO #temp
EXECUTE(#sql);
-- extract the number of rows from the temp table
SET #nrofrows = (SELECT NrOfRows FROM #temp);
-- check the result so you can test!
PRINT #nrofrows;
If you want good background information on dynamic SQL, check out Erland Sommarskogs article The Curse and Blessings of Dynamic SQL.
You should remove the quotes around #maxRowCount.
Try this:
declare #maxRowCount bigint
exec('set #maxRowCount =(select COUNT(*) from ' + #tableName + ')')
OR
exec('SELECT #maxRowCount = COUNT(*) from ' + #tableName)
Analysis:
With the query you tried, it will execute:
set blablabla = (select count(1) from MyTable)
By removing the quotes:
set #maxRowCount = (select count(*) from MyTable)
You can try this instead.
declare #maxRowCount bigint(5)
exec('SELECT COUNT(*) INTO #maxRowCount FROM ' + #tableName)

Error "Declare Scalar" when Dynamic Exec Update inside two Cursor loops

Basically I'm looking to loop through a temp table which lists certain table names which need updated, I take each table name use it to populate another temporary table of all the ID's which are to be updated..
I can select the data in each table needing updated using this structure, but cannot seem to get the inner cursor to run as it isn't picking up the temp table..
Any help would be greatly appreciated as this has been doing my nut in for the past few hours..
Cheers,
DECLARE #table INT
DECLARE #prefix nvarchar(3)
DECLARE #TableName nvarchar(50)
DECLARE #TableIdName nvarchar(50)
DECLARE #getTable CURSOR
SET #getTable = CURSOR FOR
SELECT DISTINCT(id)
FROM #t
OPEN #getTable
FETCH NEXT
FROM #getTable INTO #table
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #TableName = name FROM #t WHERE id = #table
SET #TableIdName = #TableName + 'Id'
SELECT #prefix = prefix FROM #t WHERE name = #TableName
--PRINT #table
PRINT #TableName
--PRINT #TableIdName
--PRINT #prefix
DECLARE #temptable table(rid int, rTableName nvarchar(50), rprefix nvarchar(3), rpk nvarchar(50))
EXEC ('INSERT INTO ' + #temptable + ' SELECT ' + #TableIdName + ', ' + #TableName + ', ' + #prefix + #TableIdName + ' FROM ' + #TableName)
DECLARE #rTableName nvarchar(50)
DECLARE #rpk nvarchar(50)
DECLARE #rprefix nvarchar(3)
DECLARE #row INT
DECLARE #getRow CURSOR
SET #getRow = CURSOR FOR
SELECT DISTINCT(rid)
FROM #temptable
OPEN #getRow
FETCH NEXT
FROM #getRow INTO #row
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #row
SELECT #rTableName = rTableName FROM #temptable WHERE rid = #row
SELECT #rpk = rpk FROM #temptable WHERE rid = #row
SELECT #rprefix = rprefix FROM #temptable WHERE rid = #row
EXEC ('UPDATE ' + #rTableName + ' SET CoiRef = ' + #rprefix + '_' + #row + ' WHERE ' + #rpk + ' = ' + #row)
FETCH NEXT
FROM #getRow INTO #row
END
CLOSE #getRow
DEALLOCATE #getRow
FETCH NEXT
FROM #getTable INTO #table
END
CLOSE #getTable
DEALLOCATE #getTable
I have also tried another solution using sp_executesql but get similar errors there, this was using the below code instead on the first EXEC..
DECLARE #sqlCommand nvarchar(500)
SET #sqlCommand = 'INSERT INTO #temptable SELECT TableIdName, TableName, prefix, TableIdName FROM' + #TableName
EXECUTE sp_executesql #sqlCommand, N'#temptable nvarchar(50) output', #temptable OUTPUT
Again, Any help would be greatly appreciated..
Thanks..
Gerry
I think the error is coming from the fact that you're trying to use a table variable inside of dynamic sql. This is not something that is supported because the table variable is out of scope for the dynamic sql. You should make your #temptable into a temporary table using the create table command.
In the unsolicited advice category, I'd suggest attempting to recreate this without using cursors if at all possible, as cursors go against the concept of set based processing which is the foundation of sql server.

Why isn't the table being created from within the stored procedure?

I am creating stored procedure in which I need to build a temporary table dynamically. I tried the following code but its not creating table. When I execute the generated Query in Query window it works fine there.
--declare query variable
DECLARE #Query nvarchar(MAX)
SET #Query = 'CREATE TABLE #final (DATE int,'
--DECLARE #COLUMNNAME VARIABLE
DECLARE #ColName nvarchar(10)
OPEN #taCur
FETCH NEXT FROM #taCur INTO #ColName
WHILE (##FETCH_STATUS = 0)
BEGIN
SET #Query = #Query + 'T_' + #ColName +' int,'
FETCH NEXT FROM #taCur INTO #ColName
END
SET #Query = #Query + 'TOTAL int,CUMM_TOTAL int)'
print #Query
EXEC sp_executesql #Query
--SET #Query = 'INSERT INTO #final (DATE) VALUES (1)'
SET #Query = 'SELECT * FROM #final'
print #Query
EXEC(#Query)
Final generated create table Query is as follow
CREATE TABLE #final (DATE int,T_211E int,T_211G int,T_211H int,T_211J int,T_211L int,T_221F int,TOTAL int,CUMM_TOTAL int)
Object #final used in CREATE and SELECT statements is not in the same scope.
Here is one way to structure the query.
Try to terminate SQL statements with semicolon. Even though it is not mandatory, it will help you differentiate the statements for readability. Note that I have included semicolon at the end of CREATE, INSERT and SELECT statements.
You can notice that CREATE, INSERT and SELECT are executed in the same transaction. Thereby, you don't lose the scope of the temporary table.
Script:
CREATE TABLE dbo.ColumnSchema
(
ColName NVARCHAR(10)
);
INSERT INTO dbo.ColumnSchema (ColName) VALUES
('211E'),
('211G'),
('211H'),
('211J'),
('211L'),
('211F');
DECLARE #Query NVARCHAR(MAX);
DECLARE #ColName NVARCHAR(10);
SET #Query = 'CREATE TABLE #final (DATE int,';
DECLARE taCursor CURSOR FOR
SELECT ColName
FROM dbo.ColumnSchema;
OPEN taCursor
FETCH NEXT FROM taCursor
INTO #ColName
WHILE (##FETCH_STATUS = 0)
BEGIN
SET #Query = #Query + 'T_' + #ColName + ' int, '
FETCH NEXT FROM taCursor
INTO #ColName
END
CLOSE taCursor;
DEALLOCATE taCursor;
SET #Query = #Query + 'TOTAL int,CUMM_TOTAL int); '
SET #Query = #Query + 'INSERT INTO #final (DATE) VALUES (1); '
SET #Query = #Query + 'SELECT * FROM #final; '
EXEC (#Query);
Output:
DATE T_211E T_211G T_211H T_211J T_211L T_211F TOTAL CUMM_TOTAL
---- ------ ------ ------ ------ ------ ------ ----- ----------
1 NULL NULL NULL NULL NULL NULL NULL NULL
Your problem is that your temp table only exists within the scope that it is created... which is within the scope of your first sp_executesql. When you call your select statement, your temp table is no longer in scope.
To fix this, you would have to build up a single string that contains everything you need to do with your temp table: your create, insert, and select all within the a single sp_executesql call.
However, you should be aware that your current approach is likely vulnerable to SQL injection if you don't have complete control over all the values that are used to build up your commands.