Cursor to execute t-sql create view statement - sql

I'm looking to migrate several SQL views from one database to another. Both databases definitions are identical, so I should not have to worry about compatibility issues. I will have to perform this task on several client systems so I am looking to automate it instead of using the 'Script View As' option and manually duplicating each view.
I am brand new to cursors, so I apologize if this is a terribly simple request but I have tried several approaches and gotten nowhere. My searches of this site and others have been similarly fruitless. This is what I have come up with so far:
declare #sql nvarchar(max)
declare #view nvarchar(max)
declare #dbname nvarchar(30)
set #dbname = 'DatabaseName'
DECLARE cCursor CURSOR LOCAL FOR
SELECT VIEW_DEFINITION
from INFORMATION_SCHEMA.views
where TABLE_NAME like '%MyCriteria%'
OPEN cCursor
FETCH NEXT FROM cCursor into #view
WHILE ##FETCH_STATUS = 0
BEGIN
set #sql = 'USE ' + #dbname + ' GO ' + #view
execute #sql
FETCH NEXT FROM cCursor into #view
END
close cCursor
deallocate cCursor
I am getting an error message upon execution that says:
Msg 203, Level 16, State 2, Line 17
The name 'USE DATA14 GO CREATE VIEW
.... is not a valid identifier.
where the .... represents the create view statement I fetched from Information schema.
Any ideas what I'm doing wrong?
Thanks in advance.
EDIT:
I tried another approach that does not rely on cursors and I believe I am closer, but I am still getting errors that have me baffled:
use SourceDB
go
declare #sql nvarchar(max)
set #sql = N''
select #sql = #sql + 'USE DestDB' + CHAR(13) + CHAR(10) + 'GO' + CHAR(13) + CHAR(10) + s.definition + CHAR(13) + CHAR(10) + 'GO' + CHAR(13) + CHAR(10)
from sys.sql_modules as s
inner join sys.objects as o
on s.object_id = o.object_id
where o.type_desc = 'VIEW'
and s.definition like '%MyCriteria%'
exec data14..sp_executesql #sql
--select #sql
The text of the error message is:
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near 'GO'.
Msg 111, Level 15, State 1, Line 3
'CREATE VIEW' must be the first statement in a query batch.
Msg 102, Level 15, State 1, Line 22
Incorrect syntax near 'GO'......
and so on and so forth for each view in the list

Another option is to use Powershell. There are many ways to do it, I personally like to make a file for each script, and I am making an assumption that the views do not already exist in the new database. So this probably will not work verbatim, but should get you pointed in the right direction.
Create an export folder on the server (C:\Temp\Views)
Open the source server in the object explorer.
Navigate to the source database (/Databases/{DatabaseName})
Right click on 'Views' and select 'Start Powershell'
Run the following command which will create a file for each view:
ls | ? { $_.name -match "MyCriteria" } | %{ $_.scriptheader(0) + $_.textbody > "C:\temp\views\$($_.Schema).$($_.name).sql" }
Import the scripts into another database with
ls "C:\temp\views" | %{ invoke-sqlcmd -inputfile $_.fullname -database "DatabaseName" }

To achieve what you're looking for, you have to nest your dynamic SQL within dynamic SQL...
DECLARE #sql nvarchar(max)
DECLARE #dbname nvarchar(30)
SET #dbname = 'DatabaseName'
SET #sql = '';
SELECT #sql = #sql + '
EXEC ' + #dbname + '.sys.sp_executesql N''' + REPLACE(VIEW_DEFINITION, '''', '''''') + ''''
FROM INFORMATION_SCHEMA.views
WHERE TABLE_NAME like '%table%'
EXEC (#sql);
There is a catch though.
The double dynamic sql needs to be double escaped. Hence the REPLACE above.
By the way... The correct syntax for executing dynamic SQL is EXEC (#SQL) -- Note the brackets
Without the brackets, you're telling the server to execute a procedure. Hence the reason for your first error
Hope that helps

Related

MSSQL Dynamic SQL for table creation from view fails only when executed through job

I have a problem with my recurring table creation.
I have a bunch of views that need to be written into tables.
My approach is, that for every view there is, a table should be created and therefore I realized it with dynamic SQL. So that I don't have to touch the job every time I add a view.
My problem is, the code works fine as long as I execute it myself within SSSM.
As soon as I put it in a job and it is executed by schedule or by myself it fails. If I replace the dynamic SQL with the code it produces, the job fails as well. I even put the code into a stored procedure and just executed that from the job and that produced the same result.
The error states that it couldn't convert a nvarchar type into a datetime type.
I checked every view and ran the code for every view/table singly as well as all at once and there was no error.
Has anyone an idea what's wrong here?
Here is the dynamic SQL code that I use:
DECLARE #SQL varchar(max);
SELECT #SQL = COALESCE(#SQL + ' ', '') + 'IF OBJECT_ID(''' + REPLACE(name, 'qry_', 'tbl_') + ''', ''U'') IS NOT NULL DROP TABLE ' + QUOTENAME(REPLACE(name, 'qry_', 'tbl_')) + '; SELECT * INTO ' + QUOTENAME(REPLACE(name, 'qry_', 'tbl_')) + ' FROM ' + QUOTENAME(name) + ';'
FROM sys.views
WHERE LEFT(name, 4) = 'qry_'
EXEC (#sql);
This SQL is untested, however, this should greatly help you. Notice that I do each execution separately. Firstly, this does (actually) mean that if the dynamic SQL fails that it won't propagate out (this may not be intended, however). I also, though, have added PRINT statements so you can inspect the logs and see what was actually done; and what view was failed out. PRINT #SQL; is commented out, as (if I recall correctly), the Agent logs can only hold 8000 or 4000 characters, so printing the value of #SQL would over bloat it.
DECLARE #SQL nvarchar(MAX), #ViewName sysname;
DECLARE qry_views CURSOR FOR
SELECT [name]
FROM sys.views
WHERE [name] LIKE 'qry[_]%'
OPEN qry_views;
FETCH NEXT FROM qry_views
INTO #ViewName;
WHILE ##FETCH_STATUS = 0 BEGIN
PRINT 'Creating table from View ' + QUOTENAME(#ViewName);
SET #SQL = N'IF OBJECT_ID(''' + REPLACE(#ViewName, N'qry_', N'tbl_') + N''', ''U'') IS NOT NULL DROP TABLE ' + QUOTENAME(REPLACE(#ViewName, N'qry_', N'tbl_')) + N';' + NCHAR(10) +
N'SELECT *' + NCHAR(10) +
N'INTO ' + QUOTENAME(REPLACE(#ViewName, N'qry_', N'tbl_')) + NCHAR(10) +
N'FROM ' + QUOTENAME(#ViewName) + N';';
--PRINT #SQL;
EXEC sp_executesql #SQL;
FETCH NEXT FROM qry_views
INTO #ViewName;
END
CLOSE qry_views;
DEALLOCATE qry_views;
In the job, do you call a stored proc by using date literals, like:
exec my_proc #my_param='20180524'
? You can't do this. Assing the values to a var first, then use the var:
declare #my_value date ='20180524'
exec my_proc #my_param=#my_value

Query with variable tablename

I don't know why I keep bumping into these, but I have a small problem with a stored procedure. The only special in it is the variable Tablename:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE dbo.ProdTijdCompare
#TABLENAME SYSNAME,
#scanner nvarchar(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL NVARCHAR(MAX);
SELECT #SQL = 'select SUM(tijd) from ' + #TABLENAME + 'where Scanner = #scanner'
EXEC sp_executesql #SQL;
END
GO
The error I'm getting when executing in SSMM:
Msg 102, Level 15, State 1, Line 3
Incorrect syntax near '='.
(1 row(s) affected)
You need a space between #TableName and where:
SELECT #SQL = 'select SUM(tijd) from ' + #TABLENAME + ' where Scanner = #scanner';
This type of error is incredibly obvious if you just print out the SQL before running it.
Always quote table names in dynamic SQL to avoid SQL Injection (cf QUOTENAME)
Second, supply the #scanner parameter to the sp_executesql procedure as you can see in the sample below:
SELECT #SQL = 'select SUM(tijd) from ' + QUOTENAME(#TABLENAME) + ' where Scanner = #scanner'
EXEC sp_executesql #SQL, N'#scanner NVARCHAR(50)', #scanner;

Dynamic Sql - Creating a database - Problems with syntax

I'm having issues with a dynamic SQL script in particular this bit:EXEC('
if db_id(''' + $(db) + ''') is null
BEGIN
CREATE DATABASE ' + $(db) + '
END
The if statement part seems to work fine, I know this because if the database exists then the create database line is not run but when it needs to run I just get syntax errors near that line.
I have also tried:
CREATE DATABASE ''' + $(db) + '''
with no luck
Any Ideas?
DECLARE #DB_NAME NVARCHAR(128) = N'Test_DB'
DECLARE #Sql NVARCHAR(MAX);
IF DB_ID(#DB_NAME) IS NULL
BEGIN
SET #Sql = N' CREATE DATABASE ' + QUOTENAME(#DB_NAME)
EXECUTE sp_executesql #Sql
END
Important Note
Make sure your database name is in accordance with the Rules for Regular Identifiers

Is there a way to include go in dymanic SQL?

DECLARE #SQL VARCHAR(100)
DECLARE #dbName VARCHAR(100)--
SET #dbName = 'somedbname'--
SET #sql = 'USE [' + #dbName + ']' + CHAR(13) + CHAR(10)
SET #sql = #sql + 'GO' + CHAR(13) + CHAR(10)-- Print the command
EXEC (#sql)
When I run this it gives error Incorrect syntax near 'GO' has someone found workaround to this?
Requirement : I need to include stored procedure creation in switched database.
GO is not a SQL statement - it is a command recognized by the SQL Server utilities (e.g. sqlcmd, osql, SQL Server Management Studio code editor).
However, you can change the database without the GO command.

Use database dynamically

This execution is giving me the following error:
Msg 102, Level 15, State 1, Line 5
Incorrect syntax near 'go'.
Msg 111, Level 15, State 1, Line 11
'CREATE/ALTER PROCEDURE' must be the first statement in a query batch.
If i remove the "GO" it gives me just the second one.
Any hints of what am I missing?
declare #dbname varchar(500)
set #dbname='master'
Exec ('
Use ' + #dbname + '
go
create PROCEDURE [dbo].[krijo_database] #dbname nvarchar(2000), #Direktoria varchar(4000)
AS
BEGIN
declare #stringu nvarchar(100)
set #stringu =
''CREATE DATABASE '' + #dbname
exec (#stringu)
End
')
Answer
declare #dbname varchar(500)
set #dbname='kontabel'
Exec(
'Use ' + #dbname +'
Exec (''
create PROCEDURE [dbo].[krijo_database] #dbname nvarchar(2000), #Direktoria varchar(4000)
AS
BEGIN
declare #stringu nvarchar(100)
set #stringu =
''''create DATABASE '''' + #dbname
exec (#stringu)
End
'')
')
Actually I tried like this and it worked but I had to change quotes.
The real procedure that I would like to use is more than 50000 lines and I can't go and manually change the quotes to everything.
Is there a better way?
Two issues:
Using "GO" is incorrect... there is no SQL keyword called "GO"... that's just a hack that SQL Server Management Studio is performing for you.
You need to the CREATE PROCEDURE command in it's own context... simple.
Here's the slight modification to your script:
declare #dbname varchar(500)
set #dbname='master'
Exec ('
Use ' + #dbname + '
EXECUTE(''create PROCEDURE [dbo].[krijo_database] #dbname nvarchar(2000), #Direktoria varchar(4000)
AS
BEGIN
declare #stringu nvarchar(100)
set #stringu =
''''CREATE DATABASE '''' + #dbname
exec (#stringu)
End'')
')
So the answer is to put another "EXECUTE" command inside the first EXECUTE command. I do this all the time, a lot of times in an "sp_msforeachdb". You can nest those bad boys as long as you want.
Sometime ago I had code which was updating database structure based on scripts.
I end up with split file by 'go' and execute separately each fragment. Can you try this?
So, first exec use statement, and than exec createprocedure.
Be sure to verify that it is created in proper database
My mistake, I didn't notice something.
maybe it's the Exec inside the Exec that's causing the error?
or because your'e assigning a nvarchar(2000) to a nvarchar(100)
"Msg 102, Level 15, State 1, Line 5 Incorrect syntax near 'go'. Msg 111, Level 15, State 1, Line 11 'CREATE/ALTER PROCEDURE' must be the first statement in a query batch. " If i remove the "GO" it gives me just the second one.
try this without any use or go: create PROCEDURE '+#dbname+'.[dbo].[krijo_database] #dbname nvarchar(2000)
You can't use GO like that
It isn't a SQL command
It tells SSMS to split the batch
If you remove it, then you'll get "first in batch" error which is expected
In this case, why not just do this...
Use master
GO
create PROCEDURE [dbo].[krijo_database] #dbname nvarchar(2000), #Direktoria varchar(4000)
AS
BEGIN
declare #stringu nvarchar(100)
set #stringu = 'CREATE DATABASE ' + #dbname
exec (#stringu)
End
GO
Why do need dynamic SQL to create a stored procedure?
USE master
GO
CREATE PROCEDURE dbo.create_database #name nvarchar(100)
AS
DECLARE #sql nvarchar(100)
SET #sql = 'CREATE DATABASE ' + QUOTENAME(#name)
EXEC (#sql)
GO
What you're after can't be done I don't think.
See this article for reference
The Real procedure that i would like to use it is a very big one, more dhan 50000 lines and i can't go on an changing the quotes to everything
Microsoft SQL Server has a maximum length of varchar of 8000 characters.
http://www.databasejournal.com/features/mssql/article.php/3788256/Data-Types-in-SQL-Server-2008.htm
you should create stored procedure with that portion with variable.
I used SQl DMO!
Great feature both for 32 and 64 bit,compatible with both SQL express and server!