来自SQL Server的CSV文件

时间:2017-03-17 21:04:44

标签: sql-server powershell

我需要运行一系列查询并将结果导出到平面文件,但这个文件有点特别:

  1. 列分隔符必须是|
  2. 如果特定行的任何char或varchar列为NULL,我需要放置“在char或varchar列BU周围,我不能放置”。如果值是空字符串,那么是的,我需要放置它们。
  3. 我通过在T-SQL中构建整个记录找到了一种解决方法,但我需要为每个必须构建的新查询执行此操作。

    任何想法

3 个答案:

答案 0 :(得分:1)

这里有不同的选择:

  • 您可以使用BCP工具提取数据
  • 如果您每天必须这样做一次,可以使用Integration Services,并在SQL Agent中安排程序包。
  • 您可以使用Management Studio中的“导出向导”并选择所需的分隔符:

右键单击数据库,然后单击“导出数据”。 继续使用数据源,在数据目标中放置文件,分隔格式和(“)作为文本限定符:

enter image description here

然后选择要提取数据(或查询)的表,并指定“垂直条”作为列分隔符。 enter image description here

下一步就是运行任务(这里它还为您提供了保存SSIS包以便随时再次运行它的选项。)

希望这会对你有所帮助。

答案 1 :(得分:1)

您可以使用SQLPS模块并选择表格

Import-Module Sqlps -DisableNameChecking;
Invoke-Sqlcmd -ServerInstance "yourservername" -Database "yourdatabasename" -Query "select top 2 zonetable1, zonetable2 from dbo.yourtable"  | 
    Export-Csv "c:\temp\result.csv" -NoTypeInformation

答案 2 :(得分:0)

以下是使用PowerShell的解决方案,因为您已在问题中对其进行了标记。

  • 使用.Net库执行SQL(即与Invoke-SqlCmd相对)。这样可以避免路径更改(导入SQLPS模块的副作用),这意味着您可以通过查找数据中的DbNull来发现空值。
  • 删除那些不是请求数据的属性,而是删除DataRow对象的属性。
  • 对于我们结果中的每个属性,请检查它是否为DBNull。如果是,请将其替换为标记字符串(此字符串包含GUID,因此极不可能偶然出现在源数据中)。
  • 使用管道分隔符
  • 将数据转换为CSV
  • 将所有出现在引号中的标记替换为空白(即不带引号)。
  • 将结果写入文件

clear-host
function Invoke-SQLQuery {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$ServerInstance 
        ,
        [Parameter(Mandatory = $true)]
        [string]$Database 
        ,
        [Parameter(Mandatory = $true)]
        [string]$Query
        ,
        [Parameter(Mandatory = $false)]
        [int]$CommandTimeoutSeconds = 30 #30 is the SQL default
    )
    begin {
        $connectionString = ("Server={0};Database={1};Integrated Security=True;" -f $DbInstance,$DbCatalog)
        $connection = New-Object System.Data.SqlClient.SqlConnection
        $connection.ConnectionString = $connectionString
        $connection.Open()    
    }
    process {
        $command = $connection.CreateCommand()
        $command.CommandTimeout = $CommandTimeoutSeconds
        $command.CommandText = $query
        $result = $command.ExecuteReader()
        $table = new-object "System.Data.DataTable"
        $table.Load($result)
        $table | Convert-DataRowToPSCustomObject
    }
    end {
           $connection.Close()
    }
}
function Convert-DataRowToPSCustomObject {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]
        [System.Data.DataRow]$Row
    )
    process {
        [PSObject]($Row | Select * -ExcludeProperty RowError, RowState, Table, ItemArray, HasErrors)
    }
}
#this gives us a nice way to distinguish nulls from blanks in csv rows
function Convert-DbNullToMarker {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [PSObject]$Data
    )
    process {
        $Data | Get-Member -MemberType NoteProperty | % Name | %{
            if($Data.$_ -is [DbNull]) {
                $Data.$_ = 'DbNullMarker{fdb653bf-0810-4893-a076-e3d935d9e6ba}'
            }
        }
        $Data
    }
}

#this gives us a nice way to distinguish nulls from blanks in csv rows
function Convert-DbNullMarkerToNull {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [string]$CsvRow
    )
    process {
        $CsvRow -replace '"DbNullMarker{fdb653bf-0810-4893-a076-e3d935d9e6ba}"',''
    }
}


Invoke-SqlQuery -ServerInstance "." -Database "master" -Query "select * from (values (null, 'hello'), ('hi', 'world')) x(a, b)" | 
    Convert-DbNullToMarker -Verbose |
    ConvertTo-Csv -Delimiter '|' -NoTypeInformation |
    Convert-DbNullMarkerToNull |
    Out-File -FilePath (Join-Path $PSScriptRoot 'SqlCsvDemo.csv') -Encoding utf8 -Force