I've got table with columns and procedure to create SQL table:
DECLARE #SQLString NVARCHAR(MAX)
SELECT #SQLString =
'
'+ ColName + ' ' + ColType + ' '+ ColNullable + ',
'
FROM FS_Report_Tables WHERE TableId = 0
PRINT ('CREATE TABLE '+ 'Test' + #SQLString)
EXEC ('CREATE TABLE '+ 'Test' + #SQLString)
Current code prints only last column when I need all ( without coma at last )
Data table example:
ColumnId TableId ColName ColType ColNullable
1 0 A int NOT NULL
2 0 B int NOT NULL
How can I build SQLString with nodes from SELECT from another table?
Please try:
DECLARE #SQLString NVARCHAR(MAX)
SELECT
#SQLString = COALESCE(#SQLString + ', ', '') + ColName + ' ' + ColType + ' ' + ColNullable
from
YourTable
select #SQLString
EXEC ('CREATE TABLE YourTableName (' + #SQLString + ')')
DECLARE #SQLString NVARCHAR(MAX)
SET #SQLString = 'CREATE TABLE '+ #TableName +
'
( '+#Column1Name+' '+#Column1DataType +' '+#Column1Nullable +')
'
PREPARE stmt FROM #SQLString;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
You need to use prepared statements
SQL server provides you a stored procedure, sp_executesql which will do this task for you
Related
I was trying to pass table name and column name dynamic, this is as part of SSIS process I am trying this stored procedure below.
CREATE PROCEDURE [lnd].[Get_ANCNotullColumn]
(#PassedTableName AS NVarchar(255),
#PassedColumnName AS NVARCHAR(100))
AS
BEGIN
DECLARE #ActualTableName AS NVarchar(255)
SELECT #ActualTableName = QUOTENAME( TABLE_NAME )
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #PassedTableName
DECLARE #sql AS NVARCHAR(MAX)
SELECT #sql = 'SELECT COUNT(*) FROM ' + #ActualTableName + ';'
DECLARE #final AS NVARCHAR(MAX)
SELECT #final = #sql + 'WHERE ' + #PassedColumnName + ' IS NULL OR ' + #PassedColumnName + '='''
EXEC(#SQL)
END
On executing this, I am NOT getting count as result, instead I am getting execution success.
EXEC [lnd].[Get_ANCNotullColumn] 'lnd.ANC_LND_ItemOverride', 'comments'
I need to get the count as output.
Also my simple direct query is like this
SELECT COUNT(*)
FROM lnd.ANC_LND_ItemOverride
WHERE Comments IS NULL OR Comments = '' -- 3 is the output
I think you may need to modify you value passing and your concatenation values.
from this statement you need to remove the semi colon as it will throw error
SELECT #sql = 'SELECT COUNT(*) FROM ' + #ActualTableName + ';'
While passing blank values you need additional quotes
SELECT #final = #sql + 'WHERE ' + #PassedColumnName + ' IS NULL OR ' + #PassedColumnName + '= '''''
While execution I believe you wanted to execute final instead of SQL
I think below should give your output:
CREATE PROC [lnd].[Get_ANCNotullColumn]( #PassedTableName as NVarchar(255),#PassedColumnName AS
NVARCHAR(100))
AS
BEGIN
DECLARE #ActualTableName AS NVarchar(255)
SELECT #ActualTableName = QUOTENAME( TABLE_NAME )
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #PassedTableName
DECLARE #sql AS NVARCHAR(MAX)
SELECT #sql = 'SELECT COUNT(*) FROM ' + #ActualTableName + ' '
DECLARE #final AS NVARCHAR(MAX)
SELECT #final = #sql + 'WHERE ' + #PassedColumnName + ' IS NULL OR ' + #PassedColumnName + '='''''
EXEC(#final)
END
I have following table and values,
Tb_name column_name1 column_name2
Citator_KTLO_CC Date_Created Date_Modified
Citator_KTLO_QA Date_Created Date_Modified
I want to select dynamically column from table, so the result is like this:
Select Date_Created,Date_Modified from Citator_KTLO_CC
and in next loop it will select for second row, like
Select Date_Created,Date_Modified from Citator_KTLO_QA
How can i do this by using dynamic sql ?
any example are appreciated.
here is an example of how to do this.
Since you dont post many info I just assume that the table containing all the tablenames is called 'tables'
Also this will only work if all tables have the same column types.
-- create a test table you dont need this
create table tables (tb_name varchar(100) primary key, field1 varchar(100), field2 varchar(100))
-- fill my test table you dont need this
insert into tables values ('table1', 'field1', 'field2')
insert into tables values ('table2', 'foo1', 'foo2')
insert into tables values ('table3', 'test1', 'test2')
-- this is the actual code you need, replace the names with your real names
declare #sql varchar(max) = ''
declare #tb_name varchar(100) = ''
declare #field1 varchar(100) = ''
declare #field2 varchar(100) = ''
declare myCursor cursor for
select tb_name, field1, field2 from tables -- dont know how your table is called
open myCursor
fetch next from myCursor into #tb_name, #field1, #field2
while ##FETCH_STATUS = 0
begin
set #sql = #sql + ' select ' + #field1 + ', ' + #field2 + ' from ' + #tb_name + ' union all '
fetch next from myCursor into #tb_name, #field1, #field2
end
close myCursor
deallocate myCursor
select #sql = left(#sql, len(#sql) - 10)
exec (#sql)
EDIT:
using a where clause is possible but things will get more complicated
declare #something date = getdate()
set #sql = #sql + ' select ' + #field1 + ', ' + #field2 + ' from ' + #tb_name + ' where ' + #field1 + ' = ' + #something + ' union all '
You can use the example above to build what you need just play with it.
EDIT:
using a where clause with a date format
declare #something date = getdate()
set #sql = #sql + ' select ' + #field1 + ', ' + #field2 + ' from ' + #tb_name + ' where ' + #field1 + ' = ''' + CONVERT(varchar(8), #something, 112) + ''' union all '
DECLARE #SQL VARCHAR(1000);
SET #SQL = '
SELECT *
FROM Citator_KTLO_CC
UNION ALL
SELECT *
FROM Citator_KTLO_QA;'
EXEC (#SQL);
How about something like this. If you've more than two cols, you can use dynamic sql to generate a list of cols to then generate more dynamic sql instead of hard coding.
DROP TABLE #Test
CREATE TABLE #Test
(Tb_name NVARCHAR(15),
column_name1 NVARCHAR(12),
column_name2 NVARCHAR(13));
INSERT INTO #Test VALUES
('Citator_KTLO_CC','Date_Created','Date_Modified'),
('Citator_KTLO_QA','Date_Created','Date_Modified');
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = (SELECT STUFF((SELECT ' UNION ALL SELECT ' + Cols + ' FROM '+TbL
FROM (SELECT QUOTENAME(Tb_name) TBL,
QUOTENAME(column_name1) + ', '+
QUOTENAME(column_name2) Cols
FROM #Test) Blah
FOR XML PATH('')),1,10,''))
PRINT #SQL
EXEC sys.sp_executesql #SQL
Try this..
For selecting one row if you are running in aloop
DECLARE #sql NVARCHAR(4000)
SELECT #sql = ' select ' + column_name_1 + ',' + column_name2 + ' from ' + Tb_name
FROM < yourtable >
EXEC (#sql)
OR
DECLARE #sql NVARCHAR(4000)
SELECT #sql = 'union all select ' + column_name_1 + ',' + column_name2 + ' from ' + Tb_name
FROM < yourtable >
SET #sql =stuff(#sql,1,10,'')
EXEC (#sql)
DECLARE #ColumnList1 VARCHAR(MAX) = '''''';
DECLARE #ColumnList2 VARCHAR(MAX) = '''''';
DECLARE #ColumnNameFromTable1 VARCHAR(50);
DECLARE #ColumnNameFromTable2 VARCHAR(50);
DECLARE MyCursor1 CURSOR
FOR
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Citator_KTLO_CC'
ORDER BY ORDINAL_POSITION
DECLARE MyCursor2 CURSOR
FOR
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Citator_KTLO_QA'
ORDER BY ORDINAL_POSITION
OPEN MyCursor1
OPEN MyCursor2
FETCH NEXT FROM MyCursor1 INTO #ColumnNameFromTable1;
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM MyCursor2 INTO #ColumnNameFromTable2;
SET #ColumnList1 = #ColumnList1 + ',' + #ColumnNameFromTable1
SET #ColumnList2 = #ColumnList2 + ',' + #ColumnNameFromTable2
FETCH NEXT FROM MyCursor1 INTO #ColumnNameFromTable1;
END
CLOSE MyCursor1;
DEALLOCATE MyCursor1;
CLOSE MyCursor2;
DEALLOCATE MyCursor2;
EXEC ('SELECT ' + #ColumnList1 + ' FROM Citator_KTLO_CC UNION ALL SELECT ' +
#ColumnList2 + ' FROM Citator_KTLO_QA ')
I've got error:
Must declare the scalar variable #columns
Where is the problem? Thank you
ALTER PROCEDURE CreateTable
#tabname nvarchar(max)
as
declare #columns nvarchar(max) = null;
declare #sql nvarchar(max) = null;
select #columns=coalesce(#columns + ', ')
+colname
+ ' '
+coltype
from x_column
where colname is not null
and tabname=#tabname
order by colnum;
set #sql =IF NOT EXISTS (SELECT * FROM sys.objects WHERE
object_id=OBJECT_ID(N'[#tabname]') AND type in (N'U'))
create table ' + #tabname + ' (' + #columns + ');
print #sql;
-- execute create table
exec sp_sqlexec #sql;
GO
Try like this,
ALTER PROCEDURE CreateTable #tabname NVARCHAR(max)
AS
DECLARE #columns NVARCHAR(max) = NULL;
DECLARE #sql NVARCHAR(max) = NULL;
SELECT #columns = coalesce(#columns, ', ') + colname + ' ' + coltype
FROM x_column
WHERE colname IS NOT NULL
AND tabname = #tabname
ORDER BY colnum;
SET #sql = 'IF NOT EXISTS (SELECT * FROM sys.objects WHERE
object_id=OBJECT_ID(N[' + #tabname + ']) AND type in (N''U''))
create table [' + #tabname + '] (' + #columns + ');'
PRINT #sql;
-- execute create table
EXEC sp_sqlexec #sql;
GO
Syntax error with coalesce and for #sql the data is not loaded properly
So the below script will work:
alter PROCEDURE CreateTable
#tabname nvarchar(max)
as
declare #columns nvarchar(max) = null;
declare #sql nvarchar(max) = null;
select #columns = coalesce(#columns , ', ') + colname + ' ' + coltype
from x_column
where colname is not null
and tabname = #tabname
order by colnum;
set #sql = 'IF NOT EXISTS ( SELECT * FROM sys.objects WHERE
object_id = OBJECT_ID(N[' + #tabname + ']) AND type in (N''U''))
create table ' + #tabname + ' (' + #columns + ');'
print #sql;
-- execute create table
exec sp_sqlexec #sql;
GO
Change your query like this:
ALTER PROCEDURE CreateTable
#tabname nvarchar(max)
as
declare #columns nvarchar(max) = null;
declare #sql nvarchar(max) = null;
SELECT #columns = STUFF((SELECT ',' + colname + ' ' + coltype
FROM x_column
WHERE colname IS NOT NULL
AND tabname = #tabname
ORDER BY colnum
FOR XML PATH('')),1,1,'')
set #sql ='IF NOT EXISTS (SELECT * FROM sys.objects WHERE
object_id=OBJECT_ID(N['+#tabname+']) AND type in (N''U''))
create table [' + #tabname + '] (' + #columns + ');'
print #sql;
-- execute create table
exec sp_sqlexec #sql;
GO
use this
set #sql ='IF NOT EXISTS (SELECT * FROM sys.objects WHERE
object_id=OBJECT_ID('+#tabname+') AND type in (''U''))
create table ' + #tabname + ' (' + #columns + ')';`
I'm trying to run the following Dynamic SQL statement:
#Tbl, #Fld, and #LookupValue have all been set according to Table to search, Field (Or Column) to search and column value to compare.
DECLARE #Sql AS VARCHAR(500)
SET #Sql = 'SELECT COUNT(*)
FROM ' + #Tbl +
' WITH (NOLOCK)
WHERE ' + #Fld + ' = ''' + #LookupValue + ''''
EXEC(#Sql)
I want to store the result into a variable so I can check to see if there are any returned rows. This statement is in the middle of a WHILE construct that is checking several tables and fields.
If records are found, then I want to display:
SET #Sql = 'SELECT ' + #Fld +
' FROM ' + #Tbl +
' WITH (NOLOCK)
WHERE ' + #Fld + ' = ''' + #LookupValue + ''''
EXEC(#Sql)
Yes, you can store it in a typed variable and use sp_executesql like
DECLARE #Sql AS NVARCHAR(500);
DECLARE #cnt INT;
SET #Sql = 'SELECT #cnt = COUNT(*)
FROM ' + #Tbl +
' WITH (NOLOCK)
WHERE ' + #Fld + ' = ''' + #LookupValue + '''';
EXEC sp_executesql #Sql, N'#cnt INT OUTPUT', #cnt OUTPUT;
SELECT #cnt;
you can create a temporary table and store the count value.
if object_id('tempdb.#mycount') is null
create table #mycount ( countVal int);
DECLARE #Sql AS VARCHAR(500)
SET #Sql = 'INSERT INTO #mycount
SELECT COUNT(*)
FROM ' + #Tbl +
' WITH (NOLOCK)
WHERE ' + #Fld + ' = ''' + #LookupValue + ''''
EXEC(#Sql)
select countVal from #mycount
-- once the temp table usage is done, you can delete it
drop table #mycount
I have a field namely Modified_Dt of type Datetime in all of my tables, to keep track of last modified date and time for a record.
Now, let's say I need to know which tables has records that has been modified recently(like today).
How do I write a query for that? How do I query multiple tables?
By the way, I am using MS SQL Server 2008 R2.
USE MASTER
GO
DECLARE #ObjectName NVARCHAR(255)
DECLARE TablesList CURSOR
FOR select object_name(object_id, db_id('DBStackExchange'))
from [DBStackExchange].sys.columns
where name = 'Modified_Dt'
OPEN TablesList
FETCH NEXT FROM TablesList INTO #ObjectName
WHILE ##FETCH_STATUS = 0
BEGIN
exec
( 'If exists ( SELECT 1 FROM DBStackExchange.dbo.[' + #ObjectName
+ ']
Where convert(varchar(20),Modified_Dt,103)>=convert(varchar(20),getdate(),103))
Print ''' + #ObjectName + '''
'
)
FETCH NEXT FROM TablesList INTO #ObjectName
END
CLOSE TablesList
DEALLOCATE TablesList
Note: Replace 'DBStackExchange' with your Database name
declare #T table (T_Name nvarchar(255), M datetime)
declare #T_Name nvarchar(255), #SQLT nvarchar(max)
declare c cursor for select name from sys.tables
open c
fetch next from c into #T_Name
while ##fetch_status = 0 begin
set #SQLT = 'select top 1 ''' + #T_Name + ''', Modified_Dt from ' + #T_Name + ' order by Modified_Dt desc'
insert #T
exec sp_executesql #SQLT
fetch next from c into #T_Name
end
close c
deallocate c
select * from #T where M >= dateadd(day,datediff(day,0,getdate()),0)
Here is an answer without cursor or temporary table
DECLARE #ColumnName AS nvarchar(40) = 'Modified_Dt';
DECLARE #ModifiedSince AS datetime = '20140709';
DECLARE #sql AS nvarchar(max) = '';
-- Build a query with UNION ALL between all tables containing #ColumnName
WITH AllTables AS (
SELECT SCHEMA_NAME(Tables.schema_id) AS SchemaName
,Tables.name AS TableName
,Columns.name AS ColumnName
FROM sys.tables AS Tables
INNER JOIN sys.columns AS Columns
ON Tables.object_id = Columns.object_id
WHERE Columns.name = #ColumnName
)
SELECT #sql = #sql +
'UNION ALL SELECT ' + QUOTENAME(TableName, '''') +
', ' + QUOTENAME(ColumnName) +
' FROM ' + QUOTENAME(TableName) + CHAR(13)
FROM AllTables;
-- Create a query which selects last change from all tables
SET #sql =
'WITH AllChanges(TableName, ModifiedTime) AS ( ' +
STUFF(#sql, 1, LEN('UNION ALL'), '') + -- Remove first UNION
') ' +
'SELECT TableName ' +
' ,MAX(ModifiedTime) ' +
'FROM AllChanges ' +
'WHERE ModifiedTime > #ModifiedSince '
'GROUP BY TableName '
EXECUTE sp_executesql #sql, N'#ModifiedSince datetime', #ModifiedSince