每周末自动从sql server运行25个报告

时间:2015-12-03 00:24:26

标签: sql-server

我有25个报告,我需要从Sql Server 2008中提取这些结果。截至目前,对于25个报告,我已经准备好了Sql脚本并且我单独运行并将每个报告结果复制到Microsoft Excel每个选项卡。

每周运行这25个报告的最佳自动化方法是什么,结果应填充到Excel表格中。

这25份报告的主要目的是清理报告。每周处理这些报告的业务团队,在修复数据后,结果应该逐渐减少。

感谢您的回复。

谢谢, MSS

1 个答案:

答案 0 :(得分:2)

这是一个可能的解决方案;还有很多其他的,取决于您的具体要求......

我建议使用此方法,因为听起来您的报告只是SQL语句;这将为您自动化当前手动执行的操作提供最省力的解决方案。

1)为每个报告创建一个文本文件,该文件包含SQL语句:

--Filename: Statement1.sql
--example report/query

select c.name CustomerName
, sum(o.amount) OrderTotal
from Customer c
inner join CustomerOrder o
on o.CustomerId = c.Id
order by c.name

2)创建一个包含所有上述报告的文件名的平面文件(reports.csv),以及输出的工作表名称:

SqlScriptFile,SheetName
Statement1.sql,CustomerOrderTotals
Statement2.sql,AverageCustomerSpend
anotherStatement.sql,Sheet3

3)使用以下powershell脚本(Run-Reports.ps1)运行这些语句。

param 
(
    [string]$DbInstance = 'myDbServer\myInstance'
    ,
    [string]$DbCatalog = 'myDatabase'
    ,
    [string]$ScriptListFilename = 'reports.csv'
    ,
    [string]$OutputExcelFilename = 'MyReports.xlsx'
    ,
    [string]$Delimiter = ','
)

function Execute-SQL
{
    [CmdletBinding()]
    param
    (
        [parameter(Mandatory = $true)]
        [string]$DbInstance
        ,
        [parameter(Mandatory = $true)]
        [string]$DbCatalog 
        ,
        [parameter(Mandatory = $true)]
        [string]$Query   
        ,
        [parameter(Mandatory = $false)]
        [int]$CommandTimeoutSeconds = 30
    )
    begin
    {
        $connection = New-Object System.Data.SqlClient.SqlConnection
        $connection.ConnectionString = "Server=$DbInstance;Database=$DbCatalog;Integrated Security=True"
        $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 | Select-Object * -ExcludeProperty RowError, RowState, Table, ItemArray, HasErrors
    }
    end
    {
        $connection.Close()    
    }
}

function Create-ExcelOuputObject
{
    [CmdletBinding()]
    param
    (
        [parameter(Mandatory = $true)]
        [string]$SheetName
        ,
        [parameter(Mandatory = $true)]
        [scriptblock]$DataGenerator
    )
    process
    {
        write-output (new-object -TypeName PSCustomObject -Property @{
            SheetName = $SheetName
            DataGenerator = $DataGenerator
        })
    }    
}

function Out-ExcelSheet
{
    [CmdletBinding()]
    param
    (
        [parameter(Mandatory = $true)]
        $WorkSheet
        ,
        [parameter(Mandatory = $false)]
        [string[]]$Header = $null
        ,
        [parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [PSCustomObject]$DataRow
    )
    begin
    {
        [long]$r = 0
    }
    process
    {
        $r++
        [long]$c = 0
        if($Header -eq $null) 
        {
            $Header = $DataRow | Get-Member -MemberType NoteProperty | select -ExpandProperty Name
            $Header | 
            %{
                $c++
                $WorkSheet.cells.Item($r,$c) = $_
            }  
            $r++
            $c = 0
        }
        $Header | 
        %{
            $c++
            $WorkSheet.cells.Item($r,$c) = $DataRow."$_"
        }
    }
}

function Out-Excel
{
    [CmdletBinding()]
    param
    (
        [parameter(Mandatory = $true)]
        [string]$OutFilename
        ,
        [parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [PSCustomObject]$ExcelOuputObject
    )
    begin
    {
        $excel = New-Object -ComObject Excel.Application
        $excel.DisplayAlerts = $False
        $excel.Visible = $true
        $workbook = $excel.Workbooks.Add()
        $workbook.Sheets.Count..2 | %{$workbook.Sheets[$_].Delete()}
        $sheet = $workbook.Sheets[1]
    }
    process
    {
        $sheet.Name = $ExcelOuputObject.SheetName
        $ExcelOuputObject.DataGenerator.Invoke() | Out-ExcelSheet -WorkSheet $sheet
        $sheet = $workbook.Sheets.Add()
    }
    end
    {
        $sheet.Delete()
        #$workbook.Sheets[$workbook.Sheets.Count].Delete()
        $OutFilename = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutFilename)
        $workbook.SaveAs($OutFilename)
    }
}

clear-host
[PSCustomObject[]]$Reports = Import-Csv $ScriptListFilename -Delimiter $Delimiter
$Reports | 
%{
    [string]$Query = Get-Content $_.SqlScriptFile
    $scriptBlockString = "Execute-SQL -DbInstance '$DbInstance' -DbCatalog '$DbCatalog' -Query @""`n$Query`n""@"
    Create-ExcelOuputObject `
    -SheetName $_.SheetName `
    -DataGenerator ([scriptblock]::Create($scriptBlockString))
} | Out-Excel -OutFilename $OutputExcelFilename 

4)使用Windows任务计划程序运行此计划此报告。 有关此文章的更多信息,请参阅http://blogs.technet.com/b/heyscriptingguy/archive/2012/08/11/weekend-scripter-use-the-windows-task-scheduler-to-run-a-windows-powershell-script.aspx

其他选项

  • @ [MrE]提到了Excel数据源。这将允许您的用户打开一个电子表格,其内容链接到SQL源;这样您就可以点击刷新并查看最新数据。如果您不希望用户访问实时数据库,则查询既复杂又耗时,或者您需要一个固定时间点的数据,您可以安排任务将查询结果输出到专用表(也许在另一个数据库中帮助隔离安全性)然后将Excel指向那些。更多信息:https://support.office.com/en-nz/article/Connect-a-SQL-Server-database-to-your-workbook-22c39d8d-5b60-4d7e-9d4b-ce6680d43bad
  • @ [Bacon Bits]建议SSRS。如果您具有SSRS开发技能,那么这是一个很好的选择,因为它是专为SQL设计的报告解决方案,并允许您创建订阅(可以将结果邮寄给用户的预定作业)。更多信息:https://msdn.microsoft.com/en-us/library/dd255234.aspx
  • @ [Nick.McDermaid]谈到了SQL Agent。如果您需要安排任务以将报告运行到报告表(如上面的Excel注释中所述),或者让系统邮寄结果,这是理想的选择。如果你需要与PowerShell集成(根据我的主要答案)它的位置不太好,因为这需要启用cmdshell(https://msdn.microsoft.com/en-us/library/ms175046.aspx),这是一个安全风险。更多信息:https://msdn.microsoft.com/en-GB/library/ms191439.aspx
  • 鉴于您正在使用此信息来辅助数据清理活动,另一个选项可能是创建此数据的信息中心,以便在数据被修复后自动从信息中心移除,从而帮助您那些正在研究其他人已经实时解决的人。有许多工具集可以创建这样的仪表板;我在快速谷歌之后找到的是http://htsql.org/;虽然你可以使用.Net技术同样地构建一些东西(例如使用ASP.Net,或者如果你不熟悉编码更简单的LightSwitch解决方案:https://msdn.microsoft.com/en-us/library/dn284529.aspx)。
  • 很多甚至更多。