How to use TAB as column separator in SQLCMD - sql-server

SQLCMD supports the -s parameter to specify the column separator, but I couldn't figure how how to represent the tab (CHAR(9)) character. I have tried the following but both don't work:
sqlcmd -S ServerName -E -Q"select * from mytable" -s"\t" -o results.txt
sqlcmd -S ServerName -E -Q"select * from mytable" -s'\t' -o results.txt
Any ideas how to do this in SQLCMD?

In a batch file, putting a tab between the double quotes works.
sqlcmd -S ServerName -E -Q"select * from mytable" -s" " -o results.txt
to do the same in a PowerShell file use escaped double quotes wrapped around an escaped tab
sqlcmd -S ServerName -E -Q"select * from mytable" -s `"`t`" -o results.txt

It's difficult to get unformatted results from SQLCMD.
If you want to create a tab-delimited output file, BCP might be a better bet:
bcp "select * from mytable" queryout results.txt -S server -T -c

Found a good answer here: SQLCMD outfile as tab delimited text file
Open Notepad
Paste this: sqlcmd -S (local) -E -s"<TAB>" -Q "select * from sys.dm_exec_query_stats" -o MyOutput.txt -h-1 -W
Highlight <TAB>, then hit the Tab key
Save the file as MyBatch.bat
Run MyBatch.bat

I've tried numerous times to pass the actual TAB character in to SQLCMD, and I simply can't get it to take it. My favorite work-around to-date is to pass SQLCMD the ASCII "Unit Separator", which is hex 0x1F, and can be entered on the command line by typing Ctrl-_ (control underscore, which on a US keyboard becomes ctrl-shift-'-' (the '-' next to the '0' on the top row of the keyboard).
The advantage of using the 'Unit Separator' is that is is HIGHLY unlikely to be present in text of any description, and was designed specifically for this purpose (see https://en.wikipedia.org/wiki/Delimiter)
Having got SQLCMD to do that for me, I then pipe it's output though a Unix-style translate command as:
tr '\037' '\t'
The \037 is octal for the 'Unit Separator', and \t represents the tab character, 'tr' will translate BOTH of these for us, we don't need to rely on any quoting tricks in our scripts or shells.
To get 'tr' on windows, you can install the CoreUtils package from GnuWin32 (see http://gnuwin32.sourceforge.net/packages/coreutils.htm) or go heavy-weight and install a full Unix environment such as Cygwin (http://cygwin.com/).
Putting the two together we get:
sqlcmd ... -h-1 -W -k -r1 -s^_ ... | tr '\037' '\t'
and this will give you your output with tabs.
Look up the other options I've used above, they're essential for trying to get clean output from SQLCMD (in order; no headers, trim white-space, CRLF to spaces, errors to STDERR (not your output file!) and the '^_' is how the Unit Separator will appear on the command line). You'll also need to add "SET NOCOUNT ON;" to your query or sql script, otherwise you'll get the row-count as a trialling message appearing in your output!

A similar answer to one posted above, but it's simpler in a way that I think is significant.
Open your text editor
Press Tab
Highlight the chunk of whitespace (the tab) created
Copy and paste that into the spot in your SQL command
Even though this tab is represented as a wide chunk of whitespace, it is a single character.
The other answer had some unnecessary stuff about pasting the whole command with "<TAB>" in it. I think that throws people off (it certainly threw me off).

To work in the Command Prompt window instead in batch file, this is the only way that I have found to solve it:
sqlcmd -S ServerName -E -d database_Name -Q"select col1, char(9), col2, char(9), col3, char(9), col4, char(9), col5 from mytable" -o results.txt -W -w 1024 -s "" -m 1

tldr: use ALT+009 the ascii tab code for the separator character
In the example, replace {ALTCHAR} with ALT+009 (hold the ALT key and enter the digits 009)
sqlcmd -E -d tempdb -W -s "{ALTCHAR}" -o junk.txt -Q "select 1 c1,2 c2,3 c3"
Edit junk.txt. Tabs will be between columns.
For other command line options:
sqlcmd -?
Note: The shell converts the ALT char to ^I, but if you try the command by typing -s "^I", you won't get the same results.

Use dynamic sql with CHAR(9):
SET #cmd ='SQLCMD -S MyServer -d MyDatabase -E -W -Q "SELECT * FROM MyTable" -s"' + CHAR(9) + '" -o "MyFilePath.txt"'

Try using horizontal scroll bars with cmd.exe or powershell. Right click shortcut and click properties for repeated use, or right click title bar and click properties after opening then click layout tab. In screen buffer size set width and height to 8000 and then unselect wrap text output on resize (important). Click ok. Then restore down by clicking button next to minimize. You should see horizontal and vertical scroll bars. You can maximize window now and scroll in any direction. Now you can see all records in database.

I had this problem while trying to run sqlcmd on terminal. I got it working by entering a tab character (copying from text editor didn't work for me).
Press cntrl + v then tab.
How to enter a tab char on command line?

To achieve this using sqlcmd you need to use the Tab character like so: \t
An example query exporting a single sql database table into a text file using a tab delimiter is as follows:
sqlcmd -S ServerName -d databaseTableName -Q "SELECT * FROM TABLE_NAME" -o C:\backups\tab_delimiter_bakup.txt -s"\t"

If on Linux then this will work as the -s (col_separator)
-s "$(printf "t" | tr 't' '\t')" or
SQLCMDCOLSEP="$(printf "t" | tr 't' '\t')" sqlcmd -S ...

Related

Recursive BCP import won't work in a batch file

I'm importing a set of data files in a folder into a SQL Server table. I'm able to run a recursive bcp if I enter it manually on the command line, but it doesn't work if I put it in a batch file.
The command is:
for /r %i in (*) do bcp databasename.dbo.tablename in %i -c -t -S servername -U username -P password -t "|"
The error returned is -c was unexpected at this time. If I remove the -c I get -t was unexpected at this time, and so on.
The problem was that the filenames ended up with space and dash characters when loaded to %i and these were interpreted as meaningful parts of the bcp command, which of course screwed it up. The simple but annoying solution is to make sure the directory names and filenames don't have spaces or dashes.

SSMS output delimited files with headers

Is there a way using SSMS or other tool to output about 600 tables from a SQL Server database. The catch is they need to have column headers.
Basically I need to dump 600+ tables with a bar '|' delimiter, and they need to all have column names in the first row.
If I remember right you should be able to use the command line sqlcmd tool to export data together with headers. Something like this:
sqlcmd -S localhost -d YourDatabase
-E -Q “SELECT * FROM YourTable” -o “CSVData.csv” -W -w 1024 -s”|”
You'll have to look into the options to get them right.

csv output from windows batch + sqlcmd only returns first column

i have looked all over the internet and cant seem to find a solution to this problem.
i am trying to output query results as a CSV through using a combination of sqlcmd and windows batch. here is what i have so far:
sqlcmd.exe -S %DBSERVER% -U %DBUSER% -P %DBPASS% -d %USERPREFIX% -Q "SELECT Username, UserDOB, UserGender FROM TABLE" -o %USERDATA%\%USERPREFIX%\FACT_BP.CSV -h-1 -s","
is there something i'm missing here? some setting that only looks at the first column of the query results?
any advice at all would be a huge help - i'm lost.
Here is the reference page from MSDN on SQLCMD.
http://technet.microsoft.com/en-us/library/ms162773.aspx
I placed this command in a batch file in C:\temp as go.bat.
sqlcmd -S(local) -E -dmaster
-Q"select cast(name as varchar(16)), str(database_id,1,0), create_date from sys.databases"
-oc:\temp\sys.databases.csv -h-1 -s,
Notice I hard coded the file name and removed the "" around the field delimiter.
I get the expected output below.
Either the command does not like the system variables or something else is wrong. Please try my code as a base line test. It works for SQL 2012.
Also, the number of lines is always dumped to file. You must clear this out of the file. That is why I do not use SQLCMD for ETL.
Why not use BCP instead?
I have writing several articles on my website.
http://craftydba.com/?p=1584

Using variables in SQLCMD for Linux

I'm running the Microsoft SQLCMD tool for Linux (CTP 11.0.1720.0) on a Linux box (Red Hat Enterprise Server 5.3 tikanga) with Korn shell. The tool is properly configured, and works in all cases except when using scripting variables.
I have an SQL script, that looks like this.
SELECT COLUMN1 FROM TABLE WHERE COLUMN2 = '$(param1)';
And I'm running the sqlcmd command like this.
sqlcmd -S server -d database -U user -P pass -i input.sql -v param1="DUMMYVALUE"
When I execute the above command, I get the following error.
Sqlcmd: 'param1=DUMMYVALUE': Invalid argument. Enter '-?' for help.
Help lists the below syntax.
[-v var = "value"...]
Am I missing something here?
You don't need to pass variables to sqlcmd. It auto picks from your shell variables:
e.g.
export param1=DUMMYVALUE
sqlcmd -S $host -U $user -P $pwd -d $db -i input.sql
In the RTP version (11.0.1790.0), the -v switch does not appear in the list of parameters when executing sqlcmd -?. Apparently this option isn't supported under the Linux version of the tool.
As far as I can tell, importing parameter values from environment variables doesn't work either.
If you need a workaround, one way would be to concatenate one or more :setvar statements with the text file containing the commands you want to run into a new file, then execute the new file. Based on your example:
echo :setvar param1 DUMMYVALUE > param_input.sql
cat input.sql >> param_input.sql
sqlcmd -S server -d database -U user -P pass -i param_input.sql
You can export the variable in linux. After that you won't need to pass the variable in sqlcmd. However, I did notice you will need to change your sql script and remove the :setvar command if it doesn't have a default value.
export dbName=xyz
sqlcmd -Uusername -Sservername -Ppassword -i script.sql
:setvar dbName --remove this line
USE [$(dbName)]
GO
I think you're just not quoting the input variables correctly. I created this bash script...
#!/bin/bash
# Create a sql file with a parameterized test script
echo "
set nocount on
select k = '-db', v = '\$(db)' union all
select k = '-schema', v = '\$(schema)' union all
select '-', 'static'
go" > ./test.sql
# capture input variables
DB=$1
SCHEMA="${2:-dbo}"
# Exec sqlcmd
sqlcmd -S 'localhost\lemur' -E -i ./test.sql -v "db=${DB}" -v "schema=${SCHEMA}"
... and tested it like so:
$ ./test.sh master
k v
------- ------
-db master
-schema dbo
- static

SQL Server BCP: How to put quotes around all fields?

I have this BCP command:
'bcp DBName..vieter out c:\test003.txt -c -T /t"\",\"" -S SERVER'
The output CSV I get does not put quotes around the field names, instead it puts it around the commas! How can I get the /t"\",\"" to put quotes around all fields.
Thanks all
Setting the row terminator in addition to the field terminator should do the trick
'bcp DBName..vieter out c:\test003.txt -c -T -t"\",\"" -r"\"\n\"" -S SERVER'
This will likely work, but miss off the leading " for the first field of the first line, and perhaps the last field of the last line - I'm not sure, just guessing really, no server here!
or try using QUOTENAME to wrap text fields (you could also wrap numbers, but that isn't normally required.)
'bcp "SELECT id, age, QUOTENAME(name,'"') FROM DBName..vieter" queryout c:\test003.txt -c -T -t"," -S SERVER'
You need to use CHAR(34) for the quote. This page has more details: http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=153000
Alternatively, if you are fine for Powershell based script, you can try with below code, which does automatic quoting.
Invoke-sqlcmd -ConnectionString "Server=SERVERNAME, `
3180;Database=DATABASENAME;Trusted_Connection=True;" `
-Query "SET NOCOUNT ON;SELECT * FROM TABLENAME" -MaxCharLength 700 | `
Export-Csv -NoTypeInformation -path C:\temp\FileName.csv -Encoding UTF8
bcp "SELECT char(34) + * +char(34) FROM atable queryout "C:\temp\out.csv" -T -N -c /t"\",\""
This will put quotes before and after each field (including the first and the last).
Here are the list of commands i used .
BCP "DECLARE #colnames VARCHAR(max);SELECT #colnames = COALESCE(#colnames + ',', '') + column_name from databaseName.INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='tableName'; select #colnames;" queryout "C:\HeadersOnly.csv" -r"\n\"" -c -T -Uusername -Ppassword -SserverName
bcp databaseName.schema.tableName out "C:\EmployeeDatawithoutheaders.csv" -T -t"\",\"" -r"\"\n\"" -c -Uusername -Ppassword -SserverName
copy /b C:\HeadersOnly.csv+C:\EmployeeDatawithoutheaders.csv C:\EmployeeData.csv
del C:\HeadersOnly.csv
del C:\EmployeeDatawithoutheaders.csv
I guess your goal was to clearly seperate field values by using an unique identifier so that import procedure doesn't have an issue.
I had same issue and found this workaroud useful: Using an unusual field terminator, for example | or even a string /#/ can be very unique and shouldn't mess with your string content. You also can HEX-Values (limited, see https://learn.microsoft.com/en-us/sql/tools/bcp-utility?view=sql-server-2017)
export
bcp DB.dbo.Table out /tmp/output2.csv -c -t "/#/" -U sa -P secret -S localhost
import
bcp TargetTable in /tmp/output2.csv -t "/#/" -k -U sa -P secret -S localhost -d DBNAME -c -b 50000
The actual workable answer, that removes the leading quote, is to :
A) generate format file with bcp :
bcp db.schema.tabel format nul -c -x -f file.xml -t"\",\"" -r"\"\r\n" -T -k
B) edit that file to manually copy field 1 to field 0 above, as the first field, set Max_Length=1 and remove the separator and one quot the was in field1
<FIELD ID="0" xsi:type="CharTerm" TERMINATOR="\"" MAX_LENGTH="1" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
The trick works, as you are adding a field (interface to the file) to detect the first seprator, which results in an always null-value, but not add a row (interface for the query output).

Resources