I need to dynamically loop through column names and fetch the records.
Below is my table, and I am using SQL Server 2017.
-- DECLARE #cnt INT = 1;
-- WHILE #cnt < 3
-- BEGIN
-- SELECT 'Name' + #cnt FROM Emp
-- SET #cnt = #cnt + 1;
-- END;
--GO
but this query is not working.
How to loop through columns such as Name+#cnt?
Expected output:
User1
User2
User3
Emp table:
DECLARE #statement NVARCHAR(MAX) = '', #cnt INT = 1;
WHILE #cnt < 4
BEGIN
SET #statement = #statement + ' select Name' + CAST(#cnt AS VARCHAR) + ' from Emp;'
SET #cnt = #cnt + 1;
END
EXECUTE sp_executesql #statement
Dynamic SQL would be best fit for this task:
declare #sql varchar(1000) = '';
select #sql = #sql + ' select ' + name + ' from MYDATABASE.dbo.Emp ' from MYDATABASE.sys.columns
where name like 'Name[1-3]'
exec(#sql)
The query will search for column names like Name1, Name2, Name3 and construct three SELECT queries, which then will be executed by EXEC function.
NOTE: I assumed that table is in dbo schema and you need to use your database instead of MYDATABASE.
Related
I was trying to create new tables using the identifier through a list.
DECLARE #Counter INT, #TableName NVARCHAR(20)
SET #Counter = 1
WHILE (#Counter <= 20)
BEGIN
SELECT #TableName = TableName FROM [dbo].[TableList] WHERE index = #Counter
SELECT * INTO [dbo].[#TableName.combine] FROM [dbo].[#TableName] t
LEFT JOIN [dbo].[cost] c ON t.x = c.y
SET #Counter = #Counter +1
END
And it keeps saying the object of [dbo].[#TableName] is invalid, but I already have [dbo].[#TableName] as a table.
I looked over the declare table variable, but [dbo].[#TableName] already existed in the database, how can I point to the table that I want?
You need to use dynamic SQL for this.
You can build one big query using STRING_AGG and then execute it
DECLARE #sql nvarchar(max);
SELECT #sql =
STRING_AGG(CAST('
SELECT *
INTO dbo.' + QUOTENAME(tl.TableName + '.combine') + '
FROM dbo.' + QUOTENAME(tl.TableName) + ' t
LEFT JOIN dbo.cost c ON t.x = c.y;
' AS nvarchar(max)), '
' )
FROM dbo.TableList tl;
EXEC sp_executesql #sql;
I need to dynamically create X tables. The X is calculated on the fly based on a series of other calculations that get passed in. I've written the following dynamic code in an effort to create a loop and generate a create statement each time.
I can't use global tables for this project.
DECLARE #cnt_v varchar(10)
DECLARE #SQL NVARCHAR(max) = ''
DECLARE #season_counter int = 5
SET #cnt = 1
SET #cnt_v = CONVERT(varchar(10), #cnt)
WHILE #cnt <= #season_counter
BEGIN
select #SQL = #SQL + 'create table #Season_year' + #cnt_v + ' (customer_no int, order_no int, order_dt datetime, season_no int)'
exec sp_executesql #SQL
set #sql = ''
select #SQL = #SQL + 'select * from #Season_year' + #cnt_v
exec sp_executesql #SQL
select #cnt = #cnt + 1
select #cnt_v = CONVERT(varchar(10), #cnt)
select #sql = ''
END
The output of the above code is the following errors
When manually create the tables, by typing
create table #Season_year1 (customer_no int, order_no int, order_dt datetime, season_no int)'
then use my dynamic loop to insert data, update records and ultimately drop the temp tables everything works without an issue. The problem is solely creating the tables dynamically.
If this approach isn't going to work, how else could I do this?
Thank you
Each one of your dynamic sql statements is run within its own scope, so in the SELECT * FROM #Season_year5 has no idea what #Season_year5 is. In the first dynamic SQL statement it's created and destroyed all with the execution of sp_executesql. If you combine them both into a single dynamic SQL statement then you will be able to access the temp table in other statements.
DECLARE #cnt INT = 1;
DECLARE #cnt_v varchar(10)
DECLARE #SQL NVARCHAR(max) = ''
DECLARE #season_counter int = 5
SET #cnt = 1
SET #cnt_v = CONVERT(varchar(10), #cnt)
WHILE #cnt <= #season_counter
BEGIN
select #SQL = #SQL + N'create table #Season_year' + #cnt_v + N' (customer_no int, order_no int, order_dt datetime, season_no int);
select * from #Season_year' + #cnt_v + N';'
exec sp_executesql #SQL
select #cnt = #cnt + 1
select #cnt_v = CONVERT(varchar(10), #cnt)
select #sql = ''
END
Assume I have a table with 50 columns with name AMT_0,AMT_1,..AMT_49. Is there possible sum of dynamic number of column depending on Variable.
example1: SELECT SUM(AMT_0,AMT_1,AMT_2,AMT_3) FROM TBL where the Variable is equal to 4.
example2: SELECT SUM(AMT_0,AMT_1,..,AMT_23) FROM TBL where the Variable is equal to 24.
Ideally, you should redesign your database, so that AMT is normalized into rows. Then the query is far simpler and does not require dynamic SQL.
The only way to do this as it stands is with dynamic SQL, you need to make sure to check all columns exists by looking them up in system tables, and quote all the column names properly:
DECLARE #sql nvarchar(max) = N'
SELECT SUM(
' +
(
SELECT STRING_AGG(QUOTENAME(c.name), N',')
FROM sys.columns c
WHERE c.object_id = OBJECT_ID(N'TBL')
AND c.name LIKE N'AMT_%'
) + N'
)
FROM TBL
';
EXEC (#sql)
You'll need to build some dynamic SQL. Something like this should do the trick
DECLARE #var smallint;
SELECT #var = 15; -- change variable value to control # of columns summed
DECLARE #sql varchar(4000);
DECLARE #cntr smallint; -- incremental counter variable for WHILE loop
SELECT #sql = '';
SELECT #cntr = 1;
WHILE #cntr > 0 AND #cntr <= 50 AND #cntr <= #var
BEGIN
IF #sql = ''
BEGIN
SELECT #sql = 'SELECT SUM(AMT_0';
END
ELSE
SQL #sql += ' + AMT_' + CONVERT(varchar(10), (#cntr-1));
END
SELECT #cntr += 1;
END
SELECT #sql += ') FROM TBL;';
EXEC (#sql);
is it possible to do dynamic declarations?
I will explain: I have a table COLUMNAMES:
ID|Name
1|Country
2|City
3|District
4|Neighbourhood
For each record in that table I would like to do something like:
declare #i int = 1
declare #number int
set #number = (SELECT count(*) FROM COLUMNNAMES)
While #i <= #number
BEGIN
Execute ('Declare column' + #i +'varchar(25)')
Execute ('set column' + #i +' = (Select NAME from COLUMNAMES where id = ' + #i)
set #i = #i + 1
END
The idea is that I get a list of variables (strings) that I can use to create SELECT statements with dynamic table-aliases:
Execute ('Select SOMECOLUMN as ' + #columname + #i +', ANOTHERCOLUMN as ' + #columname + #i +', ATHIRDCOLUMN as ' + #columname + #i + ' FROM SOMETABLE')
Can this be done? If so, how?
Each Execute function as a different session.
So, in order to declare the variable, all the code must be in one Execute function.
No you can't declare variables like this, but you can use a temporary table with the data filled in.
Here is some help, but it is not a whole solution, just an idea what you can do instead of the not working declaration:
Create Table #ColumnNames(
NAME varchar(64)
)
While #i <= #number
BEGIN
INSERT INTO #ColumNames
Select NAME from COLUMNAMES where id = #i
set #i = #i + 1
END
DECLARE #Columns varchar(max)
SET #Columns = ''
SElECT #Columns = #Columns + NAME + ', '
FROM #ColumNames
This is not complete solution but a direction . you need to get the value 'SomeColumn' dynamically someway ,likely the way you are getting the aliases in the below solution.
declare #i int = 1
declare #number INT
DECLARE #ColName VARCHAR(25)
DECLARE #SQL VARCHAR(4000)=''
DECLARE #ColumnsWithAlias VARCHAR(4000) = ''
set #number = (SELECT count(*) FROM COLUMNNAMES)
While #i <= #number
BEGIN
Select #ColName= NAME from COLUMNAMES where id = #i)
SET #ColumnsWithAlias =#ColumnsWithAlias + 'SomeColumn'+ ' AS '+ #ColName + ' , '
set #i = #i + 1
END
SET #SQL= 'SELECT '#ColumnsWithAlias+' FROM TableName'
EXECUTE(#SQL)
It is possible to write a generic function/procedure/select/somethingElse to cross-join a table against himself 'n' times? (yes, 'n' is a given parameter : )
How would you do it?
Example
Having this table:
Value
-------
1
2
3
cross join it 2 times, would return:
Value | Value
------------------
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
Using dynamic SQL, SQL Server 2005+ (#table_name and #numCrossJoins are stored procedure parameters):
DECLARE #upperLimit INT
SET #upperLimit = 1
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = 'SELECT * FROM '+ #table_name +' '
BEGIN
WHILE (upperLimit <= #numCrossJoins)
BEGIN
SET #SQL = #SQL + 'CROSS JOIN '+ QUOTENAME(#table_name) +' '
SET #upperLimit = #upperLimit + 1
END
EXEC sp_executesql #SQL
END
You can generate dynamic sql to output as many cross joins as you need:
create table #t (value int)
insert into #t values (1)
insert into #t values (2)
insert into #t values (3)
declare #n int
set #n = 4
declare #sql varchar(max)
set #sql = 'SELECT * FROM #t t'
declare #i int
set #i = 0
while (#i <= #n)
begin
set #sql = #sql + ' cross join #t t' + CAST(#i as varchar)
set #i = #i + 1
end
print #sql
execute(#sql)
drop table #t
Try this:
SET #SQL = 'SELECT * FROM ' + replicate('[' + #table_name + '],', #N);
set #SQL = LEFT(LEN(#SQL) - 1);
EXEC sp_executesql #SQL;
If you need to come up with all possible permutations, here is an example:
All Permutations For A String