I'm using SQL Server 2008.
I'm trying to script out all my stored procedures, and it's very easy to do in SSMS by right clicking my database, then going to Tasks -> Generate Scripts. I set my options and all is good.
I would like to get the actual T-SQL that the script wizard is executing so that I don't have to go through and select all of my options every single time I want to do it. I want to just open the script and hit run. Is there a way to copy the script that the wizard itself is executing? Or do I just have to do it manually every time?
You can do this with a pretty simple powershell script using the SMO Framework. You will need to have SQL Server Management Studio installed for the framework to get picked up. You should look into this further, but the basic framework will be:
[Void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO")
$srv = new-object "Microsoft.SqlServer.Management.SMO.Server" 'MyServer'
$db = New-Object "Microsoft.SqlServer.Management.SMO.Database"
$db = $srv.Databases['MyDatabase']
$scr = New-Object "Microsoft.SqlServer.Management.Smo.Scripter"
$scr.Server = $srv
$scr.options.filename = 'C:\SomeFolder\MyExports.SQL'
$db.StoredProcedures | where-object {$_.IsSystemObject -eq $False} | %{$scr.Script($_)}
You may need to alter some additional options. MSDN has a pretty thorough overview of the framework here.
Essentially the above will script out all the stored procs in a database to whatever file you specify. SMO is the framework that SSMS uses so it should be identical.
If all you're after is "script all procedures," and it's a one-time thing, you can open Object Explorer Details in Management Studio, highlight Stored Procedures in Object Explorer, then Ctrl + A, right-click, script as > ...
If you want a slightly more automated way, there are several schema comparison products on the market so that you don't have to care about the script that Management Studio uses to generate the script for a single object. As a bonus, it will be much easier to synchronize other, more complicated objects - just try to generate the script for a table yourself, and you will see it is no picnic. I go over many options in this blog post.
Related
I need to create a CSV file from a stored procedure that runs everyday on SQL Server with shipping details.
What would be the best way to go about this?
The solution we found best was to call the stored procedure using Powershell and have a task running in windows scheduler everyday which runs the Powershell.
Another option is BCP, or bulk command protocol. You essentially can either build this into the stored proc, or exclusively in the sql server agent job that runs it, or in an SSIS package. Wherever you prefer.
Here’s a link to Microsoft’s BCP utility:
https://learn.microsoft.com/en-us/sql/tools/bcp-utility?view=sql-server-ver15
It is important to note you may need to enable some more advanced options in SQL Server. It is highly configurable though, including the ability to dump entire tables to a csv file.
I don't know about Oracle but for SQL Server the easiest method I found was to use PowerShell.
$hostname = hostname
Invoke-Sqlcmd -ServerInstance $hostname -Database master -Query "select * from sys.sysdatabases" | Export-Csv "d:\result.csv" -NoTypeInformation
gives a CSV file at desired location.
If your SQL Server is at remote location, please make sure your server can connect to said SQL Server and if any certificate/encryption is in place then you have all that is necessary.
Has anyone else met a similar problem to the one described below?
I am having a problem deploying a SQL server 2012 dacpac database upgrade with Powershell. The details are as follows:
Its a dacpac file built for sql server 2012 and I'm trying to apply it to a sql server 2012 database via Powershell run from the command line when logged in as administrator.
Exception calling "Deploy" with "4" argument(s): "Unable to determine the identity of domain."
At ... so.ps1:17 char:8
+ $d.Deploy($dp, $TargetDatabase,$true,$DeployOptions)
The redacted script (logging and literals changed) is as follows:
[System.Reflection.Assembly]::LoadFrom("C:\Program Files (x86)\Microsoft SQL Server\110\DAC\bin\Microsoft.SqlServer.Dac.dll") | Out-Null
$d = new-object Microsoft.SqlServer.Dac.DacServices ("... Connection string ...")
$TargetDatabase = "databasename"
$fullDacPacPath = "c:\temp\...\databasename.dacpac"
# Load dacpac from file & deploy to database named pubsnew
$dp = [Microsoft.SqlServer.Dac.DacPackage]::Load($fullDacPacPath)
$DeployOptions = new-object Microsoft.SqlServer.Dac.DacDeployOptions
$DeployOptions.IncludeCompositeObjects = $true
$DeployOptions.IgnoreFileSize = $false
$DeployOptions.IgnoreFilegroupPlacement = $false
$DeployOptions.IgnoreFileAndLogFilePath = $false
$DeployOptions.AllowIncompatiblePlatform = $true
$d.Deploy($dp, $TargetDatabase,$true,$DeployOptions)
Here is some supporting information:
Dac framework version is 11.1
The script throws the error when run on the command line:
ie. Powershell -File databaseupgrade.ps1
but not when run in the Powershell integrated script environment
Similar scripts work from the command line for other dacpacs.
Research on the web might suggest that it might be something to do with the size of dacpac. The ones that work are all smaller than the one that does not and this link mentions a figure of 1.3mb which the file size of the failing dacpac just exceeds. If anyone can confirm that this is the problem can you also suggest a solution?
Update
The following script exhibits the same behavior ie. works in PS Ide not from command line.
[Reflection.Assembly]::LoadWithPartialName("System.IO.IsolatedStorage")
$f = [System.IO.IsolatedStorage.IsolatedStorageFile]::GetMachineStoreForDomain();
Write-Host($f.AvailableFreeSpace);
I believe this issue here (at least in our case) is actually when the dacpac is working with a database that utilizes multiple filegroups. When doing the comparison for deployment my hypothesis is that it's utilizing the IsolatedStorage for the different files.
The link above was helpful, but it was not the entry as much as the last comment on that blog by Tim Lewis. I modified his code to work in native powershell. Putting this above the SMO assembly load should fix this issue:
$replacementEvidence = New-Object System.Security.Policy.Evidence
$replacementEvidence.AddHost((New-Object System.Security.Policy.Zone ([Security.SecurityZone]::MyComputer)))
$currentAppDomain = [System.Threading.Thread]::GetDomain()
$securityIdentityField = $currentAppDomain.GetType().GetField("_SecurityIdentity", ([System.Reflection.BindingFlags]::Instance -bOr [System.Reflection.BindingFlags]::NonPublic))
$securityIdentityField.SetValue($currentAppDomain,$replacementEvidence)
Edit - this answer is incorrect, see the link added in the original question for information about the real root cause.
It sounds like you're trying to connect with Windows Authentication and that's the cause of the failure (see this post as it seems to cover the error message you're getting). Change your connection string to use SQL Authentication or ensure that the user your powershell script is running as both has a domain-joined identity and has permissions to access the server. Basically, this is a SQL connection issue not a DAC issue.
It's been a few days now so I don't think a proper explanation will be forthcoming. I'll just post this as our workaround for anyone else who finds themselves in this situation.
There is a Microsoft command line program SqlPackage.exe that is fairly easy to get hold of. It will silently deploy a dacpac, can be executed in Powershell and has parameters that support all the options that we need.
If we use this instead of the Dac services assembly directly the domain problem does not arise.
Given a detached SQL Server Primary Data File (.mdf) how can you get the list of data and log files that exist inside that file? The goal is to use the Server.AttachDatabase SMO method to attach the database. But the database may have multiple data and/or log files so I need to get the list in order to add them to the StringCollection parameter of the method.
What I need is the equivalent of select * from sys.files for a detached mdf. SQL Server Management Studio does this when you use it to manually attach a database so I know it can be done.
If it's a single MDF file, if there are other MDF files I don't think the MDF file can tell you that directly.
And you can always try to attach an MDF file without a log file by using the CREATE DATABASE ... FOR ATTACH_REBUILD_LOG option.
In SMO you can do this using the AttachDatabase method specifying RebuildLog for AttachOptions.
Of course this all assumes the .mdf file is healthy - it will only be usable if it was cleanly detached.
Management Studio probably has some proprietary way of reading the file headers, but these aren't documented and you're not going to be able see what SSMS is doing using Profiler or the like.
If you are typically creating .mdf files for distribution of some kind, I really strongly recommend using backup/restore instead. You can learn a lot more about a .BAK file and the data/log files its database represents, using documented and public methods such as RESTORE FILELISTONLY.
Finally figured this one out. The undocumented command DBCC checkprimaryfile(N'blah.mdf',3) gives the info needed.
It took me a while to find it, but in SMO, you use EnumDetachedLogFiles and EnumDetachedLogFiles.
# PowerShell
$servername = "sqlserver\instance"
$mdf = "S:\DATA\mydb.mdf"
[void][Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO")
$filestructure = New-Object System.Collections.Specialized.StringCollection
$server = New-Object Microsoft.SqlServer.Management.Smo.Server $servername
# Here you can automatically determine the database name, or set it manually
$dbname = ($server.DetachedDatabaseInfo($mdf) | Where { $_.Property -eq "Database name" }).Value
foreach ($file in $server.EnumDetachedDatabaseFiles($mdf)) {
$null = $filestructure.add($file)
}
foreach ($file in $server.EnumDetachedLogFiles($mdf)) {
$null = $filestructure.add($file)
}
Enumerate detached database file structures
SMO Attach/Detach Recipes
I have approximately 100 SQL views that are a variation of this:
select * from RTC.dbo.MyTable
...now I find I need to change the name of the RTC table to something else. Rather than edit one view at a time, is there a way to script out all their drop/create statements to a text file so that I can do a global replacement?
In SSMS right click the database, go to Tasks and select there 'Generate Scripts...'. Select 'Views', select the views you want exported, export.
I'd use PowerShell. If you're not using SQL 2008 Client Tools, install them. Then get the PowerShell client, add the registered snapins (plenty of information out there on how to do that), and then use the directory structure to get to the folder representing your Views.
Then script them using something like:
Get-ChildItems | % {$_.Script()}
Use ScriptOptions to tell it to use an Alter script.
And replace "RTC." with the new database name... and run them using sqlcmd.
PowerShell actually becomes a really nice deployment option too.
I'd like to automate the script generation in SQL Server Management Studio 2008.
Right now what I do is :
Right click on my database, Tasks, "Generate Scripts..."
manually select all the export options I need, and hit select all on the "select object" tab
Select the export folder
Eventually hit the "Finish" button
Is there a way to automate this task?
Edit : I want to generate creation scripts, not change scripts.
SqlPubwiz has very limited options compared to the script generation in SSMS. By contrast the options available with SMO almost exactly match those in SSMS, suggesting it is probably even the same code. (I would hope MS didn't write it twice!) There are several examples on MSDN like this one that show scripting tables as individual objects. However if you want everything to script correctly with a 'full' schema that includes 'DRI' (Declarative Referential Integrity) objects like foreign keys then scripting tables individually doesn't work the dependencies out correctly. I found it is neccessary to collect all the URNs and hand them to the scripter as an array. This code, modified from the example, works for me (though I daresay you could tidy it up and comment it a bit more):
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Sdk.Sfc;
// etc...
// Connect to the local, default instance of SQL Server.
Server srv = new Server();
// Reference the database.
Database db = srv.Databases["YOURDBHERE"];
Scripter scrp = new Scripter(srv);
scrp.Options.ScriptDrops = false;
scrp.Options.WithDependencies = true;
scrp.Options.Indexes = true; // To include indexes
scrp.Options.DriAllConstraints = true; // to include referential constraints in the script
scrp.Options.Triggers = true;
scrp.Options.FullTextIndexes = true;
scrp.Options.NoCollation = false;
scrp.Options.Bindings = true;
scrp.Options.IncludeIfNotExists = false;
scrp.Options.ScriptBatchTerminator = true;
scrp.Options.ExtendedProperties = true;
scrp.PrefetchObjects = true; // some sources suggest this may speed things up
var urns = new List<Urn>();
// Iterate through the tables in database and script each one
foreach (Table tb in db.Tables)
{
// check if the table is not a system table
if (tb.IsSystemObject == false)
{
urns.Add(tb.Urn);
}
}
// Iterate through the views in database and script each one. Display the script.
foreach (View view in db.Views)
{
// check if the view is not a system object
if (view.IsSystemObject == false)
{
urns.Add(view.Urn);
}
}
// Iterate through the stored procedures in database and script each one. Display the script.
foreach (StoredProcedure sp in db.StoredProcedures)
{
// check if the procedure is not a system object
if (sp.IsSystemObject == false)
{
urns.Add(sp.Urn);
}
}
StringBuilder builder = new StringBuilder();
System.Collections.Specialized.StringCollection sc = scrp.Script(urns.ToArray());
foreach (string st in sc)
{
// It seems each string is a sensible batch, and putting GO after it makes it work in tools like SSMS.
// Wrapping each string in an 'exec' statement would work better if using SqlCommand to run the script.
builder.AppendLine(st);
builder.AppendLine("GO");
}
return builder.ToString();
What Brann is mentioning from the Visual Studio 2008 SP1 Team Suite is version 1.4 of the Database Publishing Wizard. It's installed with sql server 2008 (maybe only professional?) to \Program Files\Microsoft SQL Server\90\Tools\Publishing\1.4. The VS call from server explorer is simply calling this. You can achieve the same functionality via the command line like:
sqlpubwiz help script
I don't know if v1.4 has the same troubles that v1.1 did (users are converted to roles, constraints are not created in the right order), but it is not a solution for me because it doesn't script objects to different files like the Tasks->Generate Scripts option in SSMS does. I'm currently using a modified version of Scriptio (uses the MS SMO API) to act as an improved replacement for the database publishing wizard (sqlpubwiz.exe). It's not currently scriptable from the command line, I might add that contribution in the future.
Scriptio was originally posted on Bill Graziano's blog, but has subsequently been released to CodePlex by Bill and updated by others. Read the discussion to see how to compile for use with SQL Server 2008.
http://scriptio.codeplex.com/
EDIT: I've since started using RedGate's SQL Compare product to do this. It's a very nice replacement for all that sql publishing wizard should have been. You choose a database, backup, or snapshot as the source, and a folder as the output location and it dumps everything nicely into a folder structure. It happens to be the same format that their other product, SQL Source Control, uses.
I wrote an open source command line utility named SchemaZen that does this. It's much faster than scripting from management studio and it's output is more version control friendly. It supports scripting both schema and data.
To generate scripts run:
schemazen.exe script --server localhost --database db --scriptDir c:\somedir
Then to recreate the database from scripts run:
schemazen.exe create --server localhost --database db --scriptDir c:\somedir
You can use SQL Server Management Object (SMO) to automate SQL Server 2005 management tasks including generating scripts: http://msdn.microsoft.com/en-us/library/ms162169.aspx.
If you're a developer, definitely go with SMO. Here's a link to the Scripter class, which is your starting point:
Scripter Class
I don't see powershell with SQLPSX mentioned in any of these answers... I personally haven't played with it but it looks beautifully simple to use and ideally suited to this type of automation tasks, with tasks like:
Get-SqlDatabase -dbname test -sqlserver server | Get-SqlTable | Get-SqlScripter | Set-Content -Path C:\script.sql
Get-SqlDatabase -dbname test -sqlserver server | Get-SqlStoredProcedure | Get-SqlScripter
Get-SqlDatabase -dbname test -sqlserver server | Get-SqlView | Get-SqlScripter
(ref: http://www.sqlservercentral.com/Forums/Topic1167710-1550-1.aspx#bm1168100)
Project page: http://sqlpsx.codeplex.com/
The main advantage of this approach is that it combines the configurablity / customizability of using SMO directly, with the convenience and maintainability of using a simple existing tool like the Database Publishing Wizard.
In Tools > Options > Designers > Table and Database Designers there's an option for 'Auto generate change scripts' that will generate one for every change you make at the time you save it.
You can do it with T-SQL code using the INFORMATION_SCHEMA tables.
There are also third-party tools - I like Apex SQL Script for precisely the use you are talking about. I run it completely from the command-line.
If you want to a Microsoft solution you can try: Microsoft SQL Server Database Publishing Wizard 1.1
http://www.microsoft.com/downloads/details.aspx?FamilyId=56E5B1C5-BF17-42E0-A410-371A838E570A&displaylang=en
It create a batch process you can run anytime you need to rebuild the scripts.
Try new SQL Server command line tools to generate T-SQL scripts and monitor Dynamic Management Views.
Worked for me like charm. It is a new python based tool from Microsoft that runs from command line.
Everything works like described on the Microsoft page (see link below)
Worked for me with SQL 2012 server.
You install it with pip:
$pip install mssql-scripter
Command parameter overview as usual with h for help:
mssql-scripter -h
Hint:
If you log in to SQL-Server via Windows authentication, just leave away Username and password.
https://cloudblogs.microsoft.com/sqlserver/2017/05/17/try-new-sql-server-command-line-tools-to-generate-t-sql-scripts-and-monitor-dynamic-management-views/
I've been using DB Comparer - Its free and no fuss script entire DB and can compare to another DB and also produce a Diff script . Excellent for Development to Production change scripts.
http://www.dbcomparer.com/
From Visual Studio 2008 SP1 TeamSuite :
In the Server Explorer / Data Connections tab, there's a publish to provider tool which does the same as "Microsoft SQL Server Database Publishing Wizard", but which is compatible with MS Sql Server 2008.
There is also this simple command line tool I build for my needs.
http://mycodepad.wordpress.com/2013/11/18/export-ms-sql-database-schema-with-c/
It can export an entire db, and it tries to export encrypted objects. Everything is stored in folders and separate sql files for easy file comparison.
Code is also available on github.
I am using VS 2012(for DBs on MSSQL Server 2008) compare database has an option to save it, the comparison and options. This is essentially what are your settings for delivery. After that you can do update or generate script.
I just find it it a little bit awkward to load it from file later(drag and drop from windows explorer) as I do not see the file in solution explorer.