экспорт таблицы в файл с заголовками столбцов (именами столбцов) с помощью утилиты bcp и SQL Server 2008
Я видел несколько хаков, чтобы попытаться получить утилиту bcp для экспорта имен столбцов вместе с данными. Если все, что я делаю, это сброс таблицы в текстовый файл, что является самым простым методом добавления заголовков столбцов bcp?
вот команда bcp, которую я сейчас использую:
bcp myschema.dbo.myTableout myTable.csv /SmyServer01 /c /t, -T
13 ответов
проще всего использовать и использовать union all
чтобы связать список столбцов с фактическим содержимым таблицы
bcp "select 'col1', 'col2',... union all select * from myschema.dbo.myTableout" queryout myTable.csv /SmyServer01 /c /t, -T
пример:
create table Question1355876
(id int, name varchar(10), someinfo numeric)
insert into Question1355876
values (1, 'a', 123.12)
, (2, 'b', 456.78)
, (3, 'c', 901.12)
, (4, 'd', 353.76)
этот запрос вернет информацию с заголовками в первой строке. (Обратите внимание на приведения числовых значений)
select 'col1', 'col2', 'col3'
union all
select cast(id as varchar(10)), name, cast(someinfo as varchar(28))
from Question1355876
команда bcp будет:
bcp "select 'col1', 'col2', 'col3' union all select cast(id as varchar(10)), name, cast(someinfo as varchar(28)) from Question1355876" queryout myTable.csv /SmyServer01 /c /t, -T
этот метод автоматически выводит имена столбцов с данными строки с помощью BCP.
скрипт записывает один файл для заголовков столбцов (чтение из INFORMATION_SCHEMA.COLUMNS
table) затем добавляет другой файл с данными таблицы.
конечный результат объединяется в TableData.csv
, который имеет заголовки и данные строки. Просто замените переменные среды вверху, чтобы указать имя сервера, базы данных и таблицы.
set BCP_EXPORT_SERVER=put_my_server_name_here
set BCP_EXPORT_DB=put_my_db_name_here
set BCP_EXPORT_TABLE=put_my_table_name_here
BCP "DECLARE @colnames VARCHAR(max);SELECT @colnames = COALESCE(@colnames + ',', '') + column_name from %BCP_EXPORT_DB%.INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='%BCP_EXPORT_TABLE%'; select @colnames;" queryout HeadersOnly.csv -c -T -S%BCP_EXPORT_SERVER%
BCP %BCP_EXPORT_DB%.dbo.%BCP_EXPORT_TABLE% out TableDataWithoutHeaders.csv -c -t, -T -S%BCP_EXPORT_SERVER%
set BCP_EXPORT_SERVER=
set BCP_EXPORT_DB=
set BCP_EXPORT_TABLE=
copy /b HeadersOnly.csv+TableDataWithoutHeaders.csv TableData.csv
del HeadersOnly.csv
del TableDataWithoutHeaders.csv
обратите внимание, что если вам нужно поставить учетные данные, замените параметр-T на-U my_username-P my_password
этот метод имеет преимущество всегда иметь имена столбцов в синхронизации с таблицей с помощью INFORMATION_SCHEMA.COLUMNS
. Недостатком является то, что он создает временные файлы. Microsoft действительно должна исправить утилиту bcp для поддержки этого.
это решение использует трюк конкатенации строк SQL из здесь в сочетании с идеями bcp от здесь
хорошей альтернативой является SqlCmd, поскольку она включает заголовки, но имеет обратную сторону добавления пробелов вокруг данных для удобства чтения человеком. Для очистки результатов можно объединить программу SqlCmd с утилитой GnuWin32 sed (stream editing). Вот пример, который сработал для меня, хотя я не могу гарантировать, что он пуленепробиваемый.
сначала экспортируйте данные:
sqlcmd -S Server -i C:\Temp\Query.sql -o C:\Temp\Results.txt -s" "
на -s" "
- символ табуляции в двойных кавычках. Я понял, что тебе нужно бежать. эта команда через пакетный файл, в противном случае командная строка Windows будет рассматривать вкладку как команду автоматического завершения и заменит имя файла вместо вкладки.
Если Запрос.sql содержит:
SELECT name, object_id, type_desc, create_date
FROM MSDB.sys.views
WHERE name LIKE 'sysmail%'
тогда вы увидите что-то вроде этого в результатах.txt
name object_id type_desc create_date ------------------------------------------- ----------- ------------------- ----------------------- sysmail_allitems 2001442204 VIEW 2012-07-20 17:38:27.820 sysmail_sentitems 2017442261 VIEW 2012-07-20 17:38:27.837 sysmail_unsentitems 2033442318 VIEW 2012-07-20 17:38:27.850 sysmail_faileditems 2049442375 VIEW 2012-07-20 17:38:27.860 sysmail_mailattachments 2097442546 VIEW 2012-07-20 17:38:27.933 sysmail_event_log 2129442660 VIEW 2012-07-20 17:38:28.040 (6 rows affected)
Далее разберем текст с помощью sed:
sed -r "s/ +\t/\t/g" C:\Temp\Results.txt | sed -r "s/\t +/\t/g" | sed -r "s/(^ +| +$)//g" | sed 2d | sed $d | sed "/^$/d" > C:\Temp\Results_New.txt
отметим, что 2d
команда означает удаление второй строки, означает чтобы удалить последнюю строку, и "/^$/d"
удаляет все пустые строки.
очищенный файл выглядит так (хотя Я заменил вкладки на |
чтобы их можно было визуализировать здесь):
name|object_id|type_desc|create_date sysmail_allitems|2001442204|VIEW|2012-07-20 17:38:27.820 sysmail_sentitems|2017442261|VIEW|2012-07-20 17:38:27.837 sysmail_unsentitems|2033442318|VIEW|2012-07-20 17:38:27.850 sysmail_faileditems|2049442375|VIEW|2012-07-20 17:38:27.860 sysmail_mailattachments|2097442546|VIEW|2012-07-20 17:38:27.933 sysmail_event_log|2129442660|VIEW|2012-07-20 17:38:28.040
Я пытался понять, как это сделать в последнее время, и хотя мне нравится самое популярное решение наверху, оно просто не будет работать для меня, поскольку мне нужны имена псевдонимов, которые я ввел в скрипт, поэтому я использовал некоторые пакетные файлы (с некоторой помощью коллеги) для выполнения пользовательских имен таблиц.
пакетный файл, который инициирует bcp имеет строку в нижней части сценария, который выполняет другой сценарий, который объединяет файл шаблона с именами заголовков И файла это было просто экспортировано с bcp, используя приведенный ниже код. Надеюсь, это поможет кому-то еще, кто был в моей ситуации.
echo Add headers from template file to exported sql files....
Echo School 0031
copy e:\genin\templates\TEMPLATE_Courses.csv + e:\genin31\courses0031.csv e:\genin\finished\courses0031.csv /b
У меня была та же проблема. Мне нужно было экспортировать заголовок столбца с помощью утилиты SQL server bcp.Таким образом, я экспортировал таблицы "заголовки" с данными в тот же экспортированный файл за один раз.
DECLARE @table_name VARCHAR(50) ='mytable' DECLARE @columnHeader VARCHAR(8000) SELECT @columnHeader = COALESCE(@columnHeader+',' ,'')+ ''''+column_name +'''' FROM Nal2013.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME=@table_name SELECT @raw_sql = 'bcp "SELECT '+ @columnHeader +' UNION ALL SELECT * FROM mytable" queryout c:\datafile.csv -c -t, -T -S '+ @@servername EXEC xp_cmdshell @raw_sql
удачи в кодировании :)
из всего, что я знаю, BCP экспортирует только данные - я не думаю, что есть способ заставить его экспортировать строку заголовка с именами столбцов.
один общий метод, чтобы решить эту проблему, заключается в использовании представления над вашими фактическими данными для экспорта, который в основном делает объединение всех двух операторов:
- первое заявление, чтобы вернуть одну строку с заголовками столбцов
- фактические данные для экспорта
а затем используйте bcp в этом представлении, вместо вашей основной таблицы данных напрямую.
Марк
вот довольно простая хранимая процедура, которая также делает трюк..
CREATE PROCEDURE GetBCPTable
@table_name varchar(200)
AS
BEGIN
DECLARE @raw_sql nvarchar(3000)
DECLARE @columnHeader VARCHAR(8000)
SELECT @columnHeader = COALESCE(@columnHeader+',' ,'')+ ''''+column_name +'''' FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @table_name
DECLARE @ColumnList VARCHAR(8000)
SELECT @ColumnList = COALESCE(@ColumnList+',' ,'')+ 'CAST('+column_name +' AS VARCHAR)' FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @table_name
SELECT @raw_sql = 'SELECT '+ @columnHeader +' UNION ALL SELECT ' + @ColumnList + ' FROM ' + @table_name
--PRINT @raw_SQL
EXECUTE sp_executesql @raw_sql
END
GO
все версии делают вещи немного по-разному. Это версия, которую я разрабатывал на протяжении многих лет. Эта версия, похоже, учитывает все проблемы, с которыми я столкнулся. Просто заполните набор данных в таблицу, а затем передайте имя таблицы этой хранимой процедуре.
Я называю эту хранимую процедуру так:
EXEC @return_value = *DB_You_Create_The_SP_In*.[dbo].[Export_CSVFile]
@DB = N'*YourDB*',
@TABLE_NAME = N'*YourTable*',
@Dir = N'*YourOutputDirectory*',
@File = N'*YourOutputFileName*'
есть также две другие переменные:
- @NullBlanks -- это займет любое поле, которое не имеет значения и null это. Это полезно, потому что в истинном смысле CSV спецификация каждая точка данных должна иметь кавычки вокруг них. Если вы есть большой набор данных, это позволит сэкономить вам достаточное количество пространства не имея "" (две двойные кавычки) в этих областях. Если вы не найдете это полезным, то установите его в 0.
- @IncludeHeaders -- у меня есть одна хранимая процедура для вывода CSV файлы, поэтому у меня есть этот флаг в случае, если мне не нужны заголовки.
Это позволит создать хранимая процедура:
CREATE PROCEDURE [dbo].[Export_CSVFile]
(@DB varchar(128),@TABLE_NAME varchar(128), @Dir varchar(255), @File varchar(250),@NULLBLANKS bit=1,@IncludeHeader bit=1)
AS
DECLARE @CSVHeader varchar(max)='' --CSV Header
, @CmdExc varchar(max)='' --EXEC commands
, @SQL varchar(max)='' --SQL Statements
, @COLUMN_NAME varchar(128)='' --Column Names
, @DATA_TYPE varchar(15)='' --Data Types
DECLARE @T table (COLUMN_NAME varchar(128),DATA_TYPE varchar(15))
--BEGIN Ensure Dir variable has a backslash as the final character
IF NOT RIGHT(@Dir,1) = '\' BEGIN SET @Dir=@Dir+'\' END
--END
--BEGIN Drop TEMP Table IF Exists
SET @SQL='IF (EXISTS (SELECT * FROM '+@DB+'.INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ''TEMP_'+@TABLE_NAME+''')) BEGIN EXEC(''DROP TABLE ['+@DB+'].[dbo].[TEMP_'+@TABLE_NAME+']'') END'
EXEC(@SQL)
--END
SET @SQL='SELECT COLUMN_NAME,DATA_TYPE FROM '+@DB+'.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME ='''+@TABLE_NAME+''' ORDER BY ORDINAL_POSITION'
INSERT INTO @T
EXEC (@SQL)
SET @SQL=''
WHILE exists(SELECT * FROM @T)
BEGIN
SELECT top(1) @DATA_TYPE=DATA_TYPE,@COLUMN_NAME=COLUMN_NAME FROM @T
IF @DATA_TYPE LIKE '%char%' OR @DATA_TYPE LIKE '%text'
BEGIN
IF @NULLBLANKS = 1
BEGIN
SET @SQL+='CASE PATINDEX(''%[0-9,a-z]%'','+@COLUMN_NAME+') WHEN ''0'' THEN NULL ELSE ''"''+RTRIM(LTRIM('+@COLUMN_NAME+'))+''"'' END AS ['+@COLUMN_NAME+'],'
END
ELSE
BEGIN
SET @SQL+='''"''+RTRIM(LTRIM('+@COLUMN_NAME+'))+''"'' AS ['+@COLUMN_NAME+'],'
END
END
ELSE
BEGIN SET @SQL+=@COLUMN_NAME+',' END
SET @CSVHeader+='"'+@COLUMN_NAME+'",'
DELETE top(1) @T
END
IF LEN(@CSVHeader)>1 BEGIN SET @CSVHeader=RTRIM(LTRIM(LEFT(@CSVHeader,LEN(@CSVHeader)-1))) END
IF LEN(@SQL)>1 BEGIN SET @SQL= 'SELECT '+ LEFT(@SQL,LEN(@SQL)-1) + ' INTO ['+@DB+'].[dbo].[TEMP_'+@TABLE_NAME+'] FROM ['+@DB+'].[dbo].['+@TABLE_NAME+']' END
EXEC(@SQL)
IF @IncludeHeader=0
BEGIN
--BEGIN Create Data file
SET @CmdExc ='BCP "'+@DB+'.dbo.TEMP_'+@TABLE_NAME+'" out "'+@Dir+'Data_'+@TABLE_NAME+'.csv" /c /t, -T'
EXEC master..xp_cmdshell @CmdExc
--END
SET @CmdExc ='del '+@Dir+@File EXEC master..xp_cmdshell @CmdExc
SET @CmdExc ='ren '+@Dir+'Data_'+@TABLE_NAME+'.csv '+@File EXEC master..xp_cmdshell @CmdExc
END
else
BEGIN
--BEGIN Create Header and main file
SET @CmdExc ='echo '+@CSVHeader+'> '+@Dir+@File EXEC master..xp_cmdshell @CmdExc
--END
--BEGIN Create Data file
SET @CmdExc ='BCP "'+@DB+'.dbo.TEMP_'+@TABLE_NAME+'" out "'+@Dir+'Data_'+@TABLE_NAME+'.csv" /c /t, -T'
EXEC master..xp_cmdshell @CmdExc
--END
--BEGIN Merge Data File With Header File
SET @CmdExc = 'TYPE '+@Dir+'Data_'+@TABLE_NAME+'.csv >> '+@Dir+@File EXEC master..xp_cmdshell @CmdExc
--END
--BEGIN Delete Data File
SET @CmdExc = 'DEL /q '+@Dir+'Data_'+@TABLE_NAME+'.csv' EXEC master..xp_cmdshell @CmdExc
--END
END
--BEGIN Drop TEMP Table IF Exists
SET @SQL='IF (EXISTS (SELECT * FROM '+@DB+'.INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ''TEMP_'+@TABLE_NAME+''')) BEGIN EXEC(''DROP TABLE ['+@DB+'].[dbo].[TEMP_'+@TABLE_NAME+']'') END'
EXEC(@SQL)
последняя версия sqlcmd добавляет -w
возможность удалить дополнительное пространство после значения поля; однако он не помещает кавычки вокруг строк, что может быть проблемой в CSV при импорте значения поля, содержащего запятую.
Я успешно достиг этого с помощью кода ниже. Поставить ниже код в новое окно запроса SQL Server и попробовать
CREATE TABLE tempDBTableDetails ( TableName VARCHAR(500), [RowCount] VARCHAR(500), TotalSpaceKB VARCHAR(500),
UsedSpaceKB VARCHAR(500), UnusedSpaceKB VARCHAR(500) )
-- STEP 1 ::
DECLARE @cmd VARCHAR(4000)
INSERT INTO tempDBTableDetails
SELECT 'TableName', 'RowCount', 'TotalSpaceKB', 'UsedSpaceKB', 'UnusedSpaceKB'
INSERT INTO tempDBTableDetails
SELECT
S.name +'.'+ T.name as TableName,
Convert(varchar,Cast(SUM(P.rows) as Money),1) as [RowCount],
Convert(varchar,Cast(SUM(a.total_pages) * 8 as Money),1) AS TotalSpaceKB,
Convert(varchar,Cast(SUM(a.used_pages) * 8 as Money),1) AS UsedSpaceKB,
(SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB
FROM sys.tables T
INNER JOIN sys.partitions P ON P.OBJECT_ID = T.OBJECT_ID
INNER JOIN sys.schemas S ON T.schema_id = S.schema_id
INNER JOIN sys.allocation_units A ON p.partition_id = a.container_id
WHERE T.is_ms_shipped = 0 AND P.index_id IN (1,0)
GROUP BY S.name, T.name
ORDER BY SUM(P.rows) DESC
-- SELECT * FROM [FIINFRA-DB-SIT].dbo.tempDBTableDetails ORDER BY LEN([RowCount]) DESC
SET @cmd = 'bcp "SELECT * FROM [FIINFRA-DB-SIT].dbo.tempDBTableDetails ORDER BY LEN([RowCount]) DESC" queryout "D:\Milind\export.xls" -U sa -P dbowner -c'
Exec xp_cmdshell @cmd
--DECLARE @HeaderCmd VARCHAR(4000)
--SET @HeaderCmd = 'SELECT ''TableName'', ''RowCount'', ''TotalSpaceKB'', ''UsedSpaceKB'', ''UnusedSpaceKB'''
exec master..xp_cmdshell 'BCP "SELECT ''TableName'', ''RowCount'', ''TotalSpaceKB'', ''UsedSpaceKB'', ''UnusedSpaceKB''" queryout "d:\milind\header.xls" -U sa -P dbowner -c'
exec master..xp_cmdshell 'copy /b "d:\Milind\header.xls"+"d:\Milind\export.xls" "d:/Milind/result.xls"'
exec master..xp_cmdshell 'del "d:\Milind\header.xls"'
exec master..xp_cmdshell 'del "d:\Milind\export.xls"'
DROP TABLE tempDBTableDetails
вы должны быть в состоянии решить эту проблему с одним представлением cte и одним пакетным файлом, содержащим код bcp. Сначала создайте представление. Поскольку, его относительно прямо вперед, я не создал временную таблицу, обычно я делаю
CREATE VIEW [dbo].[vwxMySAMPLE_EXTRACT_COLUMNS]
AS
WITH MYBCP_CTE (COLUMN_NM, ORD_POS, TXT)
AS
( SELECT COLUMN_NAME
, ORDINAL_POSITION
, CAST(COLUMN_NAME AS VARCHAR(MAX))
FROM [INFORMATION_SCHEMA].[COLUMNS]
WHERE TABLE_NAME = 'xMySAMPLE_EXTRACT_NEW'
AND ORDINAL_POSITION = 1
UNION ALL
SELECT V.COLUMN_NAME
, V.ORDINAL_POSITION
, CAST(C.TXT + '|' + V.COLUMN_NAME AS VARCHAR(MAX))
FROM [INFORMATION_SCHEMA].[COLUMNS] V INNER JOIN MYBCP_CTE C
ON V.ORDINAL_POSITION = C.ORD_POS+1
AND V.ORDINAL_POSITION > 1
WHERE TABLE_NAME = 'xMySAMPLE_EXTRACT_NEW'
)
SELECT CC.TXT
FROM MYBCP_CTE CC INNER JOIN ( SELECT MAX(ORD_POS) AS MX_CNT
FROM MYBCP_CTE C
) SC
ON CC.ORD_POS = SC.MX_CNT
Теперь создайте пакетный файл. Я создал это в своем временном каталоге, но я ленив.
cd\
CD "C:\Program Files\Microsoft SQL Server0\Tools\Binn"
set buildhour=%time: =0%
set buildDate=%DATE:~4,10%
set backupfiledate=%buildDate:~6,4%%buildDate:~0,2%%buildDate:~3,2%%time:~0,2%%time:~3,2%%time:~6,2%
echo %backupfiledate%
pause
приведенный выше код просто создает дата добавления в конец файла.. Затем первый оператор bcp с представлением рекурсивного cte для соедините все вместе.
bcp "SELECT * FROM [dbo].[vwxMYSAMPLE_EXTRACT_COLUMNS] OPTION (MAXRECURSION 300)" queryout C:\Temp\Col_NM%backupfiledate%.txt -c -t"|" -S MYSERVERTOLOGINTO -T -q
bcp "SELECT * FROM [myDBName].[dbo].[vwxMYSAMPLE_EXTRACT_NEW] " queryout C:\Temp16_PHYSDATA_ALL%backupfiledate%.txt -c -t"|" -S MYSERVERTOLOGINTO -T -q
теперь объединить их вместе с помощью команды copy
copy C:\Temp\Col_NM%backupfiledate%.txt + C:\Temp16_PHYSDATA_ALL%backupfiledate%.txt C:\Temp16_PHYSDATA_ALL%backupfiledate%.csv
всех установить
ниже вы найдете другой способ сделать то же самое. Эта процедура также принимает параметр имя схемы в случае, если оно необходимо для доступа к таблице.
CREATE PROCEDURE Export_Data_NBA
@TableName nchar(50),
@TableSchema nvarchar(50) = ''
AS
DECLARE @TableToBeExported as nvarchar(50);
DECLARE @OUTPUT TABLE (col1 nvarchar(max));
DECLARE @colnamestable VARCHAR(max);
select @colnamestable = COALESCE(@colnamestable, '') +COLUMN_NAME+ ','
from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @TableName
order BY ORDINAL_POSITION
SELECT @colnamestable = LEFT(@colnamestable,DATALENGTH(@colnamestable)-1)
INSERT INTO @OUTPUT
select @colnamestable
DECLARE @selectstatement VARCHAR(max);
select @selectstatement = COALESCE(@selectstatement, '') + 'Convert(nvarchar(100),'+COLUMN_NAME+')+'',''+'
from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @TableName
order BY ORDINAL_POSITION
SELECT @selectstatement = LEFT(@selectstatement,DATALENGTH(@selectstatement)-1)
DECLARE @sqlstatment as nvarchar(max);
SET @TableToBeExported = @TableSchema+'.'+@TableToBeExported
SELECT @sqlstatment = N'Select '+@selectstatement+N' from '+@TableToBeExported
INSERT INTO @OUTPUT
exec sp_executesql @stmt = @sqlstatment
SELECT * from @OUTPUT