I am using a stored procedure to populate a table with the data that I need. I am then using BCP to copy the data to a .csv
file.
This process works, the one thing it is missing is that BCP is not copying the field names into row1 and I do not see a way to set Header=Yes
.
How can this syntax be amended to add the header row?
declare @sql varchar(8000)
select @sql = 'bcp Test12.dbo.test out C:\testfolder\123.csv -c -t, -T -S '+ @@servername
exec master..xp_cmdshell @sql
Using the Stack Overflow Q & A provided by Serg, I updated my syntax to:
Select @sql = 'bcp "Select ''abc1'', ''abc2'', ''abc3'', ''abc4'', ''abc5''
UNION ALL Select [abc1], [abc2], [abc3], [abc4],[abc5] from test" queryout "'
Set @sql = @sql + 'C:\testfolder\123.csv' + '" -c -t, -T -S '+@@servername
exec master..xp_cmdshell @sql
However, this produces an error:
Error = [Microsoft][SQL Server Native Client 10.0][SQL Server]
Conversion failed when converting date and/or time from character string.
abc3
is a datetime column. Should I convert it differently? I did not have to provide any cast/convert when I used the initial syntax.
(I also tried to use CAST([abc3] As Date)
but that threw the same error).
Best Answer
The problem with using
UNION
to include the column names is that column names are strings but the fields in the unioned query are not necessarily strings (as you discovered with that error posted in the Question). And you cannot convert names into other types such asINT
,DECIMAL
,MONEY
,DATETIME
, etc.That is because BCP.exe was converting each non-string field of the table (or result set) into a string so that it could be placed into the output file. But when you
UNION
two or more queries together, you need to ensure that each position within eachSELECT
matches that same position in all the otherSELECT
s so that a result set can be built.Hence you are left with a few options:
Use
UNION
(similar to what you attempted), but then useCONVERT
on the columns in the table that are not strings. For example (assuming thatabc1
,abc3
, andabc4
areVARCHAR
/NVARCHAR
whileacb2
isDATETIME
, andabc5
isINT
):The downside here is that you cannot use the simple syntax of just specifying the table name.
Create a text file of the header row as a separate step, then execute BCP, then concatenate the two files together. I show two examples of doing that in the following DBA.StackExchange answer: Insert custom header row in BCP output
Use .NET (SQLCLR or Console App; or PowerShell might even work) to execute the query and write the results to a text file. When using SqlCommand.ExecuteDataReader
to run the query, the returned
SqlDataReader` object will have the result set fields (names, datatypes, etc). You can use GetSchemaTable to get the result set field info.If this seems like a good option but you either can't code this or don't have the time and/or desire to, I created a SQLCLR Stored Procedure that does exactly this, called DB_BulkExport, and is included in the Full version (this is not available in the Free version) of SQL#. Sometime later this year there will be a stand-alone Console App version of this export, with additional features :-).