Trying to use a Case statement inside a cursor - tsql

I am trying to make the following work:
declare #ActTable as varchar(1000)
declare #cPK as VarChar(100)
declare #SQL as nvarchar(2000)
declare #FK as VarChar(100)
declare #FKRef as VarChar(200)
declare #TblRef as varchar (100)
create table #temp (
M2MTable varchar(50),
PK varchar (100),
FK Varchar(100),
FKRefTable Varchar(50))
insert into #temp
select 'slcdpm' , 'fcustno', '','' union all
select 'somast' , 'fsono', 'fcustno','slcdpm' union all
select 'soitem' , 'fsono,finumber', 'fsono','somast' union all
select 'sorels', 'fsono,finumber,frelease', 'fsono,finumber','soitem' union all
select 'qtmast', 'fquoteno', 'fcustno', 'slcdpm' union all
select 'qtitem' , 'fquoteno', 'fquoteno','qtmast' union all
select 'armast', 'fcinvoice','fcustno','scldpm' union all
select 'aritem','fcinvoice,fitem','fcinvoice','armast' union all
select 'apvend', 'fvendno','','' union all
select 'apmast','fvendno,fcinvoice','fvendno','apvend'union all
--select 'apitem','fvendno,fcinvoice,union all
select 'pomast','fpono','fvendno','apvend'union all
select 'poitem', 'fpono,fitemno','fpono','pomast' union all
select 'shmast', 'fshipno','fsokey','sorels' union all
select 'shitem','fshipno,fitemno','fshipno','shmast' -- union all
declare M2M_AddFK cursor for select M2MTable,FK,FKRefTable from #temp
open M2M_AddFK
fetch next from M2M_AddFK into #ActTable,#FK,#TblRef
while ##FETCH_STATUS = 0
Begin
case
when #FK <> ''then Set #SQL = N'alter table dbo.'+ #ActTable + ' ADD FOREIGN KEY (' + #FK + ') References DBO.' + #TblRef + '(' + #FK + ')'
Print #SQL
fetch next from M2M_AddFK into #ActTable,#FK,#TblRef
else
fetch next from M2M_AddFK into #ActTable,#FK,#TblRef
end
end
close M2M_AddFK
deallocate M2M_AddFK
drop table #temp
Please notice the Case statement:
case
when #FK <> ''then Set #SQL = N'alter table dbo.'+ #ActTable + ' ADD FOREIGN KEY (' + #FK + ') References DBO.' + #TblRef + '(' + #FK + ')'
Print #SQL
fetch next from M2M_AddFK into #ActTable,#FK,#TblRef
else
fetch next from M2M_AddFK into #ActTable,#FK,#TblRef
end
I simply want to create the alter table statement when there is a #FK value and to skip it if it's ''.
Can someone point me in the right direction?

You have to uase an IF ELSE statement.
Also, Formatting the code a little, will make it a LOT easier to read X-)
Replace the WHILE loop with
while ##FETCH_STATUS = 0
Begin
IF #FK <> ''
BEGIN
Set #SQL = N'alter table dbo.'+ #ActTable + ' ADD FOREIGN KEY (' + #FK + ') References DBO.' + #TblRef + '(' + #FK + ')'
Print #SQL
fetch next from M2M_AddFK into #ActTable,#FK,#TblRef
END
ELSE
BEGIN
fetch next from M2M_AddFK into #ActTable,#FK,#TblRef
end
end
So that your entire statement looks like
declare #ActTable as varchar(1000)
declare #cPK as VarChar(100)
declare #SQL as nvarchar(2000)
declare #FK as VarChar(100)
declare #FKRef as VarChar(200)
declare #TblRef as varchar (100)
create table #temp (
M2MTable varchar(50),
PK varchar (100),
FK Varchar(100),
FKRefTable Varchar(50))
insert into #temp
select 'slcdpm' , 'fcustno', '','' union all
select 'somast' , 'fsono', 'fcustno','slcdpm' union all
select 'soitem' , 'fsono,finumber', 'fsono','somast' union all
select 'sorels', 'fsono,finumber,frelease', 'fsono,finumber','soitem' union all
select 'qtmast', 'fquoteno', 'fcustno', 'slcdpm' union all
select 'qtitem' , 'fquoteno', 'fquoteno','qtmast' union all
select 'armast', 'fcinvoice','fcustno','scldpm' union all
select 'aritem','fcinvoice,fitem','fcinvoice','armast' union all
select 'apvend', 'fvendno','','' union all
select 'apmast','fvendno,fcinvoice','fvendno','apvend'union all
--select 'apitem','fvendno,fcinvoice,union all
select 'pomast','fpono','fvendno','apvend'union all
select 'poitem', 'fpono,fitemno','fpono','pomast' union all
select 'shmast', 'fshipno','fsokey','sorels' union all
select 'shitem','fshipno,fitemno','fshipno','shmast' -- union all
declare M2M_AddFK cursor for select M2MTable,FK,FKRefTable from #temp
open M2M_AddFK
fetch next from M2M_AddFK into #ActTable,#FK,#TblRef
while ##FETCH_STATUS = 0
Begin
IF #FK <> ''
BEGIN
Set #SQL = N'alter table dbo.'+ #ActTable + ' ADD FOREIGN KEY (' + #FK + ') References DBO.' + #TblRef + '(' + #FK + ')'
Print #SQL
fetch next from M2M_AddFK into #ActTable,#FK,#TblRef
END
ELSE
BEGIN
fetch next from M2M_AddFK into #ActTable,#FK,#TblRef
end
end
close M2M_AddFK
deallocate M2M_AddFK
drop table #temp

Related

How do i can resolve this promblem?

I have an table include 1 column ID and 12 columns month (Month01 to Month12). If i have an parameter #month=9, how can i compare to get column Month01 to Month09 without Month10, Month11, Month12. Please help me!
Simo's answer is more elegant, but below is an alternative "basic" way to do this:
DECLARE #month INT
SET #month = 9
IF #Month = 1
BEGIN
SELECT Id, Month01
FROM MonthlyData
END
IF #Month = 2
BEGIN
SELECT Id, Month01, Month02
FROM MonthlyData
END
-- Repeat for months 3-9
IF #Month = 9
BEGIN
SELECT Id, Month01, Month02, Month03, Month04,
Month05, Month06, Month07, Month08, Month09
FROM MonthlyData
END
-- Repeat for months 10-12
See my SQL Fiddle.
declare #str varchar(1000)
SELECT #str= coalesce(#str + ', ', '') + a.name
FROM (
Select name from sys.columns
where object_id = OBJECT_ID('table_months')
and isnumeric(right(name,2))= 1 and name like 'month%'
and cast(right(name,2) as int) < '03') a
-- Instead of '03' you use a variable and assign required moths number
declare #sql nvarchar(100)
set #sql = 'select ID, '+ #str+' from table_months'
exec sp_executesql #sql
you may try this out also :)
DECLARE #month int = 9
DECLARE #Sql nvarchar(100) =''
DECLARE #pos int = 1
WHILE(#pos <= #month)
BEGIN
SET #Sql = #Sql + (',month' + right('00'+ rtrim(#pos), 2))
SET #pos = #pos + 1
END
SET #Sql= 'SELECT ID ' +#Sql + ' FROM table'
EXEC sp_executesql #Sql
DECLARE #month int
DECLARE #tableName nvarchar(128)
SET #month = 9;
SET #tableName = 'months' -- YOUR TABLE's NAME
DECLARE #query nvarchar(2048)
SET #query =
'SELECT id, ' + STUFF((SELECT DISTINCT ', ' + name
FROM sys.columns WHERE name LIKE'Month%'
AND object_id = OBJECT_ID(#tableName)
AND CONVERT(INT, RIGHT(name, 2)) <= #month
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
+ ' FROM ' + #tableName;
EXEC(#query)

How to create view for all tables in database?

I want to make views from all tables already exist in database that’s hard task to catch the tables one by one and make create view XXXX as select * from Table_name .I find something that it is possible with cursor and the code is :
DECLARE #TableName sysname
DECLARE #ColumnCount INT
DECLARE #ColumnID INT
DECLARE #SelectColumn NVARCHAR(500)
DECLARE #sql NVARCHAR(max) = ''
DECLARE QUERYINFO CURSOR FOR
SELECT
t.name AS TableName,
ccount.ColumnCount,
c.column_id AS ColumnID,
CASE WHEN c.column_id <> ccount.ColumnCount
THEN c.name + ', '
ELSE c.name
END AS SelectColumn
FROM sys.tables t
INNER JOIN sys.columns c ON t.object_id=c.object_id
INNER JOIN (
SELECT object_id,COUNT(*) AS ColumnCount
FROM sys.columns
GROUP BY object_id
) ccount ON t.object_id = ccount.object_id
ORDER BY t.Name,c.column_id
OPEN QUERYINFO
FETCH NEXT FROM QUERYINFO INTO #TableName,#ColumnCount,#ColumnID,#SelectColumn
WHILE ##FETCH_STATUS = 0
BEGIN
IF #ColumnID = 1
BEGIN
SET #sql = 'CREATE VIEW v_' + #TableName + ' AS SELECT ' + #SelectColumn
END
ELSE
BEGIN
SET #sql = #sql + #SelectColumn
END
IF #ColumnID = #ColumnCount
BEGIN
SET #sql = #sql + ' FROM ' + #TableName
EXEC sys.sp_executesql #sql
SET #sql = ''
END
FETCH NEXT FROM QUERYINFO INTO #TableName,#ColumnCount,#ColumnID,#SelectColumn
END
CLOSE QUERYINFO
DEALLOCATE QUERYINFO
but it has error and I don't know how solve it
This is what I would do with dynamic SQL; checking first to see if the view exists, then creating it with all of the columns (not by using SELECT * FROM...).
DECLARE #SQL nvarchar(MAX)
SET #SQL = N''
SELECT
#SQL = #SQL +
N'IF EXISTS(SELECT 1 FROM sys.objects WHERE name = N''v_' + t.name + N''' AND type = N''V'') BEGIN DROP VIEW [v_' + t.name + '] END CREATE VIEW [v_' + t.name + N'] AS SELECT ' +
STUFF(
(SELECT N',' + c.name
FROM
sys.columns AS c
WHERE
c.OBJECT_ID = t.OBJECT_ID
ORDER BY
column_id
FOR XML PATH(''), TYPE).value('.',N'nvarchar(max)')
,1,1,N'')
+ N' FROM [' + t.name + N'];'
FROM
sys.tables AS t
EXEC sp_executesql #SQL

Altering Multiple Tables at once

I'm trying to alter multiple SQL Server 2008 R2 tables at one time.
This is my code:
use DatabaseName
go
Declare #SchemaUsed varchar(20) = 'dbo'
create table #Tables
(
TableName varchar(100), Processed int
)
insert into #Tables
select top 1 table_name, 0
from INFORMATION_SCHEMA.TABLES
where TABLE_SCHEMA = #SchemaUsed
and table_type = 'Base Table'
and (TABLE_NAME like 'PM%' )
ORDER BY TABLE_NAME
DECLARE #TableName varchar(max)
DECLARE #SQL varchar(max)
WHILE EXISTS (select top 1 'x' from #Tables where Processed = 0)
BEGIN
SET #TableName = (select top 1 TableName from #Tables where Processed = 0)
Set #SQL = 'ALTER TABLE ' + #SchemaUsed + '.' + #TableName + ' ADD [identityID] bigint IDENTITY(1, 1) NOT NULL '
-- Set #SQL = '''' + #SQL + ''''
Print #SQL
EXEC #SQL;
update #Tables
set Processed = 1
where TableName = #TableName
END
drop table #Tables
I can't get this to work to save my life and get the following error:
Lookup Error - SQL Server Database Error: The name 'ALTER TABLE
dbo.PM1GTVLV ADD [identityID] bigint IDENTITY(1, 1) NOT NULL ' is not
a valid identifier.
I've also tried multiple string variations and using sp_executesql as well.
Can someone point out where I've gone wrong?
Try
DECLARE #SQL NVARCHAR(MAX);
EXEC sp_executesql #SQL;
Instead of EXEC #sql.
As an aside, this is a much more usable version of the same code IMHO:
DECLARE #SchemaUsed VARCHAR(20) = 'dbo';
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += CHAR(13) + CHAR(10) + N'ALTER TABLE '
+ QUOTENAME(#SchemaUsed) + '.'
+ QUOTENAME(name) + ' ADD [identityID]
BIGINT IDENTITY(1,1) NOT NULL;'
FROM sys.tables
WHERE SCHEMA_NAME([schema_id]) = #SchemaUsed
AND name LIKE 'PM%';
PRINT #sql;
--EXEC sp_executesql #sql;
Or even better:
DECLARE #SchemaUsed VARCHAR(20) = 'dbo';
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += CHAR(13) + CHAR(10) + N'ALTER TABLE '
+ QUOTENAME(#SchemaUsed) + '.'
+ QUOTENAME(name) + ' ADD [identityID]
BIGINT IDENTITY(1,1) NOT NULL;'
FROM sys.tables AS t
WHERE SCHEMA_NAME([schema_id]) = #SchemaUsed
AND name LIKE 'PM%'
AND NOT EXISTS (SELECT 1 FROM sys.columns AS c
WHERE [object_id] = t.[object_id]
AND c.is_identity = 1);
PRINT #sql;
--EXEC sp_executesql #sql;
To execute a character string, EXEC requires parenthesis around the string (or character variable) as shown in the BOL syntax:
EXEC (#SQL);

T-SQL How To Count Of Records For Each Column

I have a table with over 120 columns and need to determine which column is used the least. I tried using sql queries to do this, but found T-SQL a bit simpler.
I tried the following but my count comes out as 0 for every column.
Declare data1 Cursor for select column_name
from information_schema.columns
where table_name = 'repository'
Declare #mField nvarchar(255)
Declare #count int
Open data1;
fetch next from data1 into #mField;
set #count = -1;
while ##fetch_status = 0
begin
select #count = count(#mField)
from repository where tablereference =
'central' and ( #mField!= null )
print #mField+' ' ;
print #count;
Fetch next from data1 into #mField;
end
close data1;
deallocate data1;
You can't count values like this because you are only testing if #mField is NULL. The column name isn't substituted.
COUNT ignores NULLs anyway so if you want to count non-null values, do this:
DECLARE #sql varchar(4000)
SET #sql = 'SELECT COUNT(*) AS Total '
SELECT #sql = #sql + ', COUNT(' + QUOTENAME(column_name) + ') AS ' + QUOTENAME(column_name)
from information_schema.columns
where table_name = 'repository'
SET #sql = #sql + ' FROM repository'
EXEC (#sql)
This queries the table once for all columns
You need to use some dynamic sql in the middle to acheive your aim here.
Declare data1 Cursor for select column_name
from information_schema.columns
where table_name = 'repository'
Declare #mField nvarchar(255)
Open data1;
fetch next from data1 into #mField;
while ##fetch_status = 0
begin
exec ('
declare #count int
select #count = count([' + #mField + '])
from repository where tablereference =
''central'' and ( [' + #mField + '] is not null)
if #count < 10
begin
print ''' + #mField + ' '' ;
print #count;
end
')
Fetch next from data1 into #mField;
end
close data1;
deallocate data1;
Your count(#mField) is a count of the litteral value that happens to be in #mField, its not resolving the field name into COUNT(fldBlah), you would need to use dynamic SQL for that.
Declare data1 Cursor FAST_FORWARD for select column_name
from information_schema.columns where table_name = 'repository'
Declare #mField nvarchar(255)
Declare #SQL varchar(1024)
Declare #results table (col_name varchar(128), non_nulls int)
Open data1;
fetch next from data1 into #mField;
while (##FETCH_STATUS = 0) begin
set #SQL = 'SELECT ''' + #mField + ''', count(' + #mField + ') from repository where tablereference = ''central'''
insert #results
exec(#SQL)
Fetch next from data1 into #mField;
end
close data1;
deallocate data1;
select * from #results
For an output like;
col_name non_nulls
[tablereference] 5
[another_col] 1
Where there are 5 non-null values in column tablereference etc
You need to use IS NOT NULL instead of != NULL

How to execute the stored procs from a dynamically generated query + sql server

I have a query that is dynamically fetching the stored proc names from all the databases.
Now I want to execute the stored procs and store the result in a temptable or table variable.
How to do that. Here is my SP so far
Declare #GetDBNames sysname
Declare #DynSql nvarchar(max)
Declare DBNames cursor for
Select '['+name+']' from master.dbo.sysdatabases
open DBNames
FETCH NEXT FROM DBNames into #GetDBNames
WHILE ##FETCH_STATUS=0
BEGIN
SET #DynSql = '
Select Specific_Catalog as Database_Name, Routine_Name as ''Stored Procedure Name''
From '+ #GetDBNames+'.Information_Schema.Routines '
EXEC (#DynSql)
FETCH NEXT FROM DBNames into #GetDBNames
END
Close DBNames
Deallocate DBNames
Please help.
Thanks in advance
Here's my soluton. Cursors are evil :)
Declare #DynSql nvarchar(max)
declare #result table ([Database_Name] nvarchar(128), [Stored Procedure Name] sysname)
SET #DynSql = ''
select #DynSql = #DynSql + '
Select SPECIFIC_CATALOG COLLATE DATABASE_DEFAULT as Database_Name, ROUTINE_NAME COLLATE DATABASE_DEFAULT as [Stored Procedure Name]
From ' + NAME + '.INFORMATION_SCHEMA.ROUTINES' + CHAR(13) + 'union all' + CHAR(13)
from master.dbo.sysdatabases
--remove last "union all"
SET #DynSql = left(#DynSql, LEN(#DynSql) - 10)
insert #result
exec sp_executesql #DynSql
select * from #result
INSERT [TableName] EXEC (#DynSql)
Note that if you introduce data you may want to use sp_ExecuteSQL, and you probably want to use [/] object-name escaping.