How to save SQL stored procedures to .sql files via batch - sql

I woud like to save my MS SQL Server 2005 stored procedures to .sql files automatically (would prefer a tool which I can call via .bat) so I don't have to click each single sproc manually and save it.
I have already found SMOscript from devio IT, but it gathers all tables and sproc which takes some time. Is there any similar tool where I can define which sproc(s) to export? Also I'm missing the USE <DB> clause which SMOScript doesn't add to exported file in contrast to the manuall export as script sproc for CREATE.

Create batch file with script (sorry about formatting, but it's really should be inline to execute batch):
osql -U %1 -P %2 -S %3 -d %4 -h-1 -Q "SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.Routines WHERE ROUTINE_TYPE = 'PROCEDURE'" -n -o "sp_list.txt"
for /f %%a in (sp_list.txt) do osql -U %1 -P %2 -S %3 -d %4 -h-1 -Q "SELECT ROUTINE_DEFINITION FROM INFORMATION_SCHEMA.Routines WHERE ROUTINE_NAME = '%%a'" -n -o "%%a.sql"
Name it "run.bat". Now, to execute batch use params:
run.bat [username] [password] [servername] [database]
on example:
run.bat sa pwd111 localhost\SQLEXPRESS master
first all stored procedure names will be stored in file sp_list.txt, then one by one in separate script files. The only issue - last line of each script with result count - I'm workin' on it :)
edited: bug in query fixed
Removing "Rows affected" line
Ok, now we need to create one more batch:
type %1 | findstr /V /i %2 > xxxtmpfile
copy xxxtmpfile %1 /y /v
del xxxtmpfile
Name it "line_del.bat". See, the first param is file to process, 2nd - string to search lines for removing. Now modify the main batch (again, sorry about formatting):
osql -U %1 -P %2 -S %3 -d %4 -h-1 -Q "SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.Routines WHERE ROUTINE_TYPE = 'PROCEDURE'" -n -o "sp_list.txt"
call line_del sp_list.txt "rows affected"
call line_del sp_list.txt "row affected"
for /f %%a in (sp_list.txt) do osql -U %1 -P %2 -S %3 -d %4 -h-1 -Q "SELECT ROUTINE_DEFINITION FROM INFORMATION_SCHEMA.Routines WHERE ROUTINE_NAME = '%%a'" -n -o "%%a.sql"
for /f %%a in (sp_list.txt) do call line_del %%a.sql "rows affected"
for /f %%a in (sp_list.txt) do call line_del %%a.sql "row affected"
See related articles:
Simple programming commands in a batch environment
osql Utility
MSSQL: How do you script Stored Procedure creation with code?
Delete certain lines in a txt file via a batch file
:) you may notice, last two are from SO!

There is an alternative in SQL Server Management Studio, scripting the database...
Expand the Object Explorer view to find the database, right click and select "Tasks : Generate Scripts"
From there you can script all object, just stored preocedures, of anything in between. There are quite a few options on one page, though the main one I change is:
- "Include IF NOT EXISTS"
By making that option "FALSE" then you just get a whole list of CREATE statements.
You can then choose to script the objects to a new query window, or a file.

Adding the SET NOCOUNT ON did indeed eliminate the need for the line_del.bat, but replacing syscomments with sys.sql_modules resulted in each stored procedure being truncated to 258 characters. So for the best results the code I used was:
sqlcmd -E -S SERVER-d DB -h-1 -Q "SET NOCOUNT ON SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.Routines WHERE ROUTINE_TYPE = 'PROCEDURE'" -o "sp_list.txt"
for /f %%a in (sp_list.txt) do sqlcmd -E -S SERVER-d DB -h-1 -Q "SET NOCOUNT ON SELECT text from dbo.syscomments WHERE id = OBJECT_ID('%%a')" -o "%%a.sql"
Which worked, and did not need the use of the line_del.bat. What I didnt get when I did the manual export using the SSMS wizard (Tasks/Generate Scripts/Stored Procedures/Select All) was the:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
at the beginning of each .sql, and the trailing GO command also. Not incredibly important but something to note. Thanks to Max Gontar, Seansilver and Lee for your contributions! I can now automate the backup of the stored procedures in the database, and apply version control.

I've used sqlcmd and -E instead of user, pass. This works fine so far, just stored procedures longer than 4000 chars will have a line break
sqlcmd -E -S SERVER -d DB -h-1 -Q "SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.Routines WHERE ROUTINE_TYPE = 'PROCEDURE'" -o "sp_list.txt"
call line_del sp_list.txt "rows affected"
call line_del sp_list.txt "row affected"
for /f %%a in (sp_list.txt) do sqlcmd -E -S SERVER -d DB -h-1 -Q "SELECT text from dbo.syscomments WHERE id = OBJECT_ID('%%a')" -o "%%a.sql"
for /f %%a in (sp_list.txt) do call line_del %%a.sql "rows affected"
for /f %%a in (sp_list.txt) do call line_del %%a.sql "row affected"
best regards
sean

I added SET NOCOUNT ON to eliminate the need for line_del.bat. Also replaced syscomments with sys.sql_modules (SQL 2005). I could also have used the OBJECT_DEFINITION function but it was slower than sys.sql_modules.
sqlcmd -E -S SERVER -d DB -h-1 -Q "SET NOCOUNT ON SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.Routines WHERE ROUTINE_TYPE = 'PROCEDURE'" -o "sp_list.txt" for /f %%a in (sp_list.txt) do sqlcmd -E -S SERVER -d DB -h-1 -Q "SET NOCOUNT ON SELECT definition from sys.sql_modules WHERE object_id = OBJECT_ID('%%a')" -o "%%a.sql"

Thanks to all above for help and leaving this here for other sqlcmd noobs like myself to find. Works on sql server 2005. objectName being a procedure, view etc name.
:reset
-- :setvar ObjectName "objectName" -- works
:setvar ObjectName objectName -- works too
declare #sql varchar(max);
set #sql = 'select text from dbo.syscomments where id = object_id(upper("' + '$(ObjectName)' + '"))';
-- exec sp_helptext $(ObjectName) -- quick n easy but gets chopped to 256 width
/* 4000 byte limit
set #sql =
'select view_definition
from information_schema.views
where upper(table_name) = upper("' + '$(ObjectName)' + '")';
*/
:out $(ObjectName).sql
exec(#sql)
go
:out stdout

Related

Using for loop bat file windows for multiple command calls

I want to export all data from sql server table to a csv, I know I can get the desired result by:
sqlcmd -S . -d database -E -s, -W -Q "SELECT * FROM TABLENAME" > file.csv
I have many tables, so I want to create a .bat file that do the work for me, I have this:
set "list = A B C D"
for %%x in (%list%) do (
sqlcmd -S . -d database -E -s, -W -Q "SELECT * FROM %%x" > %%x.csv
)
But I am getting errors I don't know (I am not an expert in bat files). Why this does not work? How can I do what I want?
Spacing is important when using set (unless you're doing math with the /A switch). As written, the variable you're setting isn't %list%. It's %list %. Change your set command as follows:
set "list=A B C D"

How to format SQLCMD output

I am using below command line to run a SQL query using SQLCMD
sqlcmd -S Server -Q "select top 100 * From people" -d people -t 10
The table has 20 columns and when i look at output command line window wraps the text and makes it difficult to read.
I want my results to be displayed the same way it displays in SQL Server Management Studio (properly formatted). I am not looking for any grids, but i need all my columns to be displayed in row 1 and the results properly beneath.
Thanks in advance.
Answer
We can set the width of each column.
C:/> sqlcmd -S my_server
> :setvar SQLCMDMAXVARTYPEWIDTH 30
> :setvar SQLCMDMAXFIXEDTYPEWIDTH 30
> SELECT * from my_table
> go
We can also set it like this: sqlcmd -S my_server -y 30 -Y 30.
Details
SQLCMDMAXVARTYPEWIDTH (-y)
It limits the number of characters that are returned for the large variable length data type
SQLCMDMAXFIXEDTYPEWIDTH (-Y)
Limits the number of characters that are returned for the following data types
Note: setting -y has serious performance implications.
See https://learn.microsoft.com/en-us/sql/tools/sqlcmd-utility
Formatting issues usually pop up due to your console window.
One solution is to output to the file and use notepad/your favorite editor:
sqlcmd -S myServer -d myDB -E -Q "select top 100 * From people"
-o "output.txt"
This is how I isolated a scalar.
sqlcmd -S xxx.xxx.xxx.xxx,xxxxx -d MyDb -U myUser -P MyPassword -h -1 -W -Q "set NOCOUNT ON; select a from b where b.id='c'"

Exporting data from a table using the BCP utility

I'm trying to export data from a table to a CSV file in an automated fashion, hence the VBScript.
Here is my code and error below:
bcp dbname "SELECT * FROM mytable" queryout C:\Test.csv -T -c -Uusername -Ppassword -Sdbservername
I've never used bcp but it looks like a command-line utility. If you want to execute that from a VBScript, you'll need to use WshShell.Run, as in the following example:
With CreateObject("WScript.Shell")
.Run "bcp dbname ""SELECT * FROM mytable"" queryout C:\Test.csv -T -c -Uusername -Ppassword -Sdbservername"
End With
Take note of the doubled quotes around your SQL statement.
bcp "SELECT * FROM mytable" queryout "C:\Test.csv" -T -c -Uusername -Ppassword -Sdbservername
You should not have dbname after bcp. I removed it. This should work.

Sqlcmd to generate file without dashed line under header, without row count

Using the following sqlcmd script:
sqlcmd -S . -d MyDb -E -s, -W -Q "select account,rptmonth, thename from theTable"
> c:\dataExport.csv
I get an csv output file containing
acctnum,rptmonth,facilname
-------,--------,---------
ALLE04,201406,Allendale Community for Senior Living-LTC APPL02,201406,Applewood Estates
ARBO02,201406,Arbors Care Center
ARIS01,201406,AristaCare at Cherry
Hill
. . .
(139 rows affected)
Is there a way to get rid of the dashed line under the column headers : -------,--------, but keep the column headers?
and also a way to get rid of the two lines used for the row count on the bottom?
I tries using parm -h-1 but that got rid of the column headers as well as the dashed line.
Solutions:
1) To remove the row count ("(139 rows affected)") you should use SET NOCOUNT ON statement. See ref.
2) To remove column headers you should use -h parameter with value -1. See ref (section Formatting Options).
Examples:
C:\Users\sqlservr.exe>sqlcmd -S(local)\SQL2012 -d Test -E -h -1 -s, -W -Q "set nocount on; select * from dbo.Account" > d:\export.txt.
or
C:\Users\sqlservr.exe>sqlcmd -S(local)\SQL2012 -d Test -E -h -1 -s, -W -Q "set nocount on; select * from dbo.Account" -o "d:\export2.txt"
The guy with the top answer didn't answer how to remove the dashed line. This is my awesome solution.
First include -h -1 which removes both the dashed line and header
Then before your select statement manually inject the header string that you need with a PRINT statement. So in your case PRINT 'acctnum,rptmonth,facilname' select..*...from...
Sorry I'm 4 years and 9 months late.
Use the following;
sqlcmd -S . -d MyDb -E -s, -h-1 -W -Q "set nocount on;select 'account','rptmonth', 'thename';select account,rptmonth, thename from theTable"
> c:\dataExport.csv
remove the header -h-1
remove row count [set nocount on;]
add header select [select 'account','rptmonth', 'thename';]
add your select [select account,rptmonth, thename from theTable;]
To remove the Row Count:
Add the below to your SQL statement
SET NOCOUNT ON;
To remove the hyphen row try the following upon successful execution:
findstr /v /c:"---" c:\dataExport.csv > c:\finalExport.csv
I use "---" as all my columns are over 3 characters and I never have that string in my data but you could also use "-,-" to reduce the risk further or any delimiter based on your data in place of the ",".
In my case worked well as :
type Temp.txt | findstr /v -- > DestFile.txt
In addition, if you want to query out all records in a table, you can code as
SET NOCOUNT ON;
SELECT SUBSTRING((SELECT ','+ COLUMN_NAME FROM
INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME=N'%table_name%' FOR XML
PATH('') ), 2, 9999);
SELECT * FROM %table_name%
Assign the above queries into a variable %query%. The the command will be looks like as below.
SQLCMD -h -1 -W -E -S %sql_server% -d %sql_dabase% -Q %query% -s"," -o output_file.csv
This is the one line solution, without doing anything inside the stored procedure to append the column headers:
sqlcmd -S . -d MyDb -E -s, -W -Q "select account,rptmonth, thename from theTable"
| findstr /v /c:"-" /b > "c:\dataExport.csv" & exit 0
What this does is it intercepts all console output and replaces the "-" char BEFORE it redirects to the output file. There is NO need to output to intermediary file. And you will need a one-liner command if you use an agent to run these commands remotely on the sql server machines, which most of the times are locked from hosting *.bat files (which you'd need for multiline commands).
I added the "exit 0" at the end to not fail the caller application overall. You may remove it starting "& exit 0" if you don't care about that.
This one liner is why I chose sqlcmd over bcp out, by the way. BCP, although optimized for speed, cannot output column headers unless doing the ugly trick within the stored proc, to append them there as a union all.
Just in case you have access to writing a bat file that contains this one liner, you MUST add #ECHO OFF before it. Otherwise the console output will also have the actual command.
Hope it helps.
With SQL Server 2017 (14.x) and later you can print header with:
SELECT string_agg(COLUMN_NAME, ', ') within group (order by ORDINAL_POSITION asc) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='YOUR_TABLE_NAME'
1.Create the file first with the header columns
2.Apprend the sqlcmd output to the file using the option -h-1
echo acctnum,rptmonth,facilname > c:\dataExport.csv
sqlcmd -S . -d MyDb -E -s, -h-1 -W -Q "select account,rptmonth, thename from theTable" >> c:\dataExport.csv
I used another solution to solve the issue of removing the dashed line below the header.
DECLARE #combinedString VARCHAR(MAX);
SELECT #combinedString = COALESCE(#combinedString + '|', '') + COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'YOUR_TABLE_NAME'
Then just use
Print #combinedString above your select statement.
I used pipe delimiter.

PostgreSQL - dump each table into a different file

I need to extract SQL files from multiple tables of a PostgreSQL database. This is what I've come up with so far:
pg_dump -t 'thr_*' -s dbName -U userName > /home/anik/psqlTest/db_dump.sql
However, as you see, all the tables that start with the prefix thr are being exported to a single unified file (db_dump.sql). I have almost 90 tables in total to extract SQL from, so it is a must that the data be stored into separate files.
How can I do it? Thanks in advance.
If you are happy to hard-code the list of tables, but just want each to be in a different file, you could use a shell script loop to run the pg_dump command multiple times, substituting in the table name each time round the loop:
for table in table1 table2 table3 etc;
do pg_dump -t $table -U userName dbName > /home/anik/psqlTest/db_dump_dir/$table.sql;
done;
EDIT: This approach can be extended to get the list of tables dynamically by running a query through psql and feeding the results into the loop instead of a hard-coded list:
for table in $(psql -U userName -d dbName -t -c "Select table_name From information_schema.tables Where table_type='BASE TABLE' and table_name like 'thr_%'");
do pg_dump -t $table -U userName dbName > /home/anik/psqlTest/db_dump_dir/$table.sql;
done;
Here psql -t -c "SQL" runs SQL and outputs the results with no header or footer; since there is only one column selected, there will be a table name on each line of the output captured by $(command), and your shell will loop through them one at a time.
Since version 9.1 of PostgreSQL (Sept. 2011), one can use the directory format output when doing backups
and 2 versions/2 years after (PostgreSQL 9.3), the --jobs/-j makes it even more efficient to backup every single objects in parallel
but what I don't understand in your original question, is that you use the -s option which dumps only the object definitions (schema), not data.
if you want the data, you shall not use -s but rather -a (data-only) or no option to have schema+data
so, to backup all objects (tables...) that begins with 'th' for the database dbName on the directory dbName_objects/ with 10 concurrent jobs/processes (increase load on the server) :
pg_dump -Fd -f dbName_objects -j 10 -t 'thr_*' -U userName dbName
(you can also use the -a/-s if you want the data or the schema of the objects)
as a result the directory will be populated with a toc.dat (table of content of all the objects) and one file per object (.dat.gz) in a compressed form
each file is named after it's object number, and you can retrieve the list with the following pg_restore command:
pg_restore --list -Fd dbName_objects/ | grep 'TABLE DATA'
in order to have each file not compressed (in raw SQL)
pg_dump --data-only --compress=0 --format=directory --file=dbName_objects --jobs=10 --table='thr_*' --username=userName --dbname=dbName
(not enough reputation to comment the right post)
I used your script with some corrections and some modifications for my own use, may be usefull for others:
#!/bin/bash
# Config:
DB=rezopilotdatabase
U=postgres
# tablename searchpattern, if you want all tables enter "":
P=""
# directory to dump files without trailing slash:
DIR=~/psql_db_dump_dir
mkdir -p $DIR
TABLES="$(psql -d $DB -U $U -t -c "SELECT table_name FROM
information_schema.tables WHERE table_type='BASE TABLE' AND table_name
LIKE '%$P%' ORDER BY table_name")"
for table in $TABLES; do
echo backup $table ...
pg_dump $DB -U $U -w -t $table > $DIR/$table.sql;
done;
echo done
(I think you forgot to add $DB in the pg_dumb command, and I added a -w, for an automated script, it is better not to have a psw prompt I guess, for that, I created a ~/.pgpass file with my password in it
I also gave the user for the command to know which password to fetch in .pgpass)
Hope this helps someone someday.
This bash script will do a backup with one file per table:
#!/bin/bash
# Config:
DB=dbName
U=userName
# tablename searchpattern, if you want all tables enter "":
P=""
# directory to dump files without trailing slash:
DIR=~/psql_db_dump_dir
mkdir -p $DIR
AUTH="-d $DB -U $U"
TABLES="$(psql $AUTH -t -c "SELECT table_name FROM information_schema.tables WHERE table_type='BASE TABLE' AND table_name LIKE '%$P%' ORDER BY table_name")"
for table in $TABLES; do
echo backup $table ...
pg_dump $AUTH -t $table > $DIR/$table.sql;
done;
echo done