2013-04-03 77 views
1

我一直有相當的時間試圖弄清楚這一點。讓我試着解釋我正在努力完成的事情,希望我能夠清楚。Powershell SQL查詢結果convertto-XML

我向MSSQL數據庫發送兩個查詢並接收它們。下面的代碼是完美的,但是我想在寫入XML文件之前操作XML的格式。我目前得到3列(serviceGroupName,numAccounts,numDevices)我想完成以下兩件事之一:

1)添加一個名爲「ReportType」的新列,並填寫「Monthly」或「Total」,具體取決於如果它是foreach循環的第一遍或第二遍(SQLQuery1是月度報告,並且SQLQuery2是自開始以來的總數)

2)創建一個新的PSObject並使其填充相應的信息,例如它接收的數據(serviceGroupName,numAccounts,numDevices)

以下是我目前的代碼。正如我所說,它確實工作,它產生了一個XML,但如果可能的話,我想在管道之前添加一些更多信息到ConvertTo-XML。

### Dates to use 
$Date = (Get-Date -f MM-dd-yyyy) 
$FDoTM = ((Get-Date -Day 01).AddMonths(0)).AddDays(0) 
$LDo2PM = ((Get-Date -Day 01).AddMonths(-1)).AddDays(-1) 
$TempDir = "C:\Temp" 
$WebDir =  @("\\x.x.x.x\c$\inetpub\wwwroot\Reports\Accounts","\\x.x.x.x\c$\inetpub\wwwroot\Reports\Accounts") 

### Something 

$OutputXML = "$Date-Monthly-AccountReport.xml" 

### Connection settings, uses windows authentication 

$DBServer = "OMMITED" 
$databasename = "OMMITED" 
$Connection = new-object system.data.sqlclient.sqlconnection #Set new object to connect to sql database 
$Connection.ConnectionString ="server=$DBServer;database=$databasename;trusted_connection=True" # Connectiongstring setting for local machine database with window authentication 
Write-host "Connection Information:" -foregroundcolor yellow -backgroundcolor black 
$Connection #List connection information 


### Connect to Database and Run Query 

$SqlCmd = New-Object System.Data.SqlClient.SqlCommand #setting object to use sql commands 

$OutputHeader1 = "This Month's counts" 
$SqlQuery1 = @" 

SET NOCOUNT ON; 

WITH AccountDeviceStats(serviceGroupName,numAccounts,numDevices) 
AS 
(
    SELECT svg.name,COUNT(acct.serviceGroupId) as Accounts, NULL FROM bm_account acct WITH  (NOLOCK) 
    INNER JOIN bm_servicegroup svg WITH (NOLOCK) ON svg.servicegroupId = acct.serviceGroupId 

    where acct.CreateStamp between '$($LDo2PM)' and '$($FDoTM)' 
GROUP BY acct.serviceGroupId,svg.name 
UNION ALL 
SELECT svg.name, NULL, COUNT(device.serviceGroupId) as Devices FROM bm_device device WITH (NOLOCK) 
INNER JOIN bm_servicegroup svg WITH (NOLOCK) ON svg.servicegroupId = device.serviceGroupId, bm_account acct 

where device.accountID=acct.accountId and acct.CreateStamp between '$($LDo2PM)' and '$($FDoTM)' 
GROUP BY device.serviceGroupId,svg.name 
) 
SELECT ad1.serviceGroupName,ad1.numAccounts,ad2.numDevices FROM AccountDeviceStats ad1 
INNER JOIN AccountDeviceStats ad2 ON ad1.serviceGroupName = ad2.serviceGroupName 
WHERE ad1.numAccounts IS NOT NULL AND ad2.numDevices IS NOT NULL 
ORDER BY numAccounts DESC,numDevices DESC 
"@ 

$OutputHeader2 = "Total Counts" 
$SqlQuery2 = @" 

SET NOCOUNT ON; 

WITH AccountDeviceStats(serviceGroupName,numAccounts,numDevices) 
AS 
(
SELECT svg.name,COUNT(acct.serviceGroupId) as Accounts, NULL FROM bm_account acct WITH  (NOLOCK) 
INNER JOIN bm_servicegroup svg WITH (NOLOCK) ON svg.servicegroupId = acct.serviceGroupId 

where acct.CreateStamp < '12-31-2099' 
GROUP BY acct.serviceGroupId,svg.name 
UNION ALL 
SELECT svg.name, NULL, COUNT(device.serviceGroupId) as Devices FROM bm_device device WITH (NOLOCK) 
INNER JOIN bm_servicegroup svg WITH (NOLOCK) ON svg.servicegroupId = device.serviceGroupId, bm_account acct 

where device.accountID=acct.accountId and acct.CreateStamp < '12-31-2099' 
GROUP BY device.serviceGroupId,svg.name 
) 
SELECT ad1.serviceGroupName,ad1.numAccounts,ad2.numDevices FROM AccountDeviceStats ad1 
INNER JOIN AccountDeviceStats ad2 ON ad1.serviceGroupName = ad2.serviceGroupName 
WHERE ad1.numAccounts IS NOT NULL AND ad2.numDevices IS NOT NULL 
ORDER BY numAccounts DESC,numDevices DESC 
"@ 

$sqlQueries = @($SqlQuery1, $SqlQuery2) 

$Results = @() 

Foreach ($Query in $sqlQueries){ 
    $Connection.open() 
    Write-host "Connection to database successful." -foregroundcolor green -backgroundcolor black 
    $SqlCmd.CommandText = $Query 
    $SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter 
    $SqlAdapter.SelectCommand = $SqlCmd 
    $SqlCmd.Connection = $Connection 
    $DataSet = New-Object System.Data.DataSet 
    $SqlAdapter.Fill($DataSet) 
    $Connection.Close() 

$Results += $DataSet.Tables[0] 

($Results | ConvertTo-XML -NoTypeInformation).Save("$TempDir\$OutputXML") 
} 

if ((Get-ChildItem $TempDir -filter "$Date-*.xml").count -gt 0){  
Foreach ($file in (Get-ChildItem $TempDir -filter "$Date-*.xml" -recurse)){ 
    Foreach ($webserver in $WebDir){ 
     Copy-Item $file.fullname "$webserver\$file" -force 
     } 
    Remove-Item $file.fullname -force 
    } 
} 

這裏是XML

<?xml version="1.0"?> 
<Objects> 
    <Object> 
    <Property Name="serviceGroupName">ServiceGroup1</Property> 
    <Property Name="numAccounts">15</Property> 
    <Property Name="numDevices">28</Property> 
    <Property Name="RowError" /> 
    <Property Name="RowState">Unchanged</Property> 
    <Property Name="Table"> 
     <Property>System.Data.DataRow</Property> 
    </Property> 
    <Property Name="ItemArray"> 
     <Property>ServiceGroup1</Property> 
     <Property>15</Property> 
     <Property>28</Property> 
    </Property> 
    <Property Name="HasErrors">False</Property> 
    </Object> 
    <Object> 
    <Property Name="serviceGroupName">ServiceGroup1</Property> 
    <Property Name="numAccounts">45</Property> 
    <Property Name="numDevices">69</Property> 
    <Property Name="RowError" /> 
    <Property Name="RowState">Unchanged</Property> 
    <Property Name="Table"> 
     <Property>System.Data.DataRow</Property> 
    </Property> 
    <Property Name="ItemArray"> 
    <Property>ServiceGroup1</Property> 
    <Property>45</Property> 
    <Property>69</Property> 
</Property> 
<Property Name="HasErrors">False</Property> 

而最後一件事的輸出格式。如果可以從XML中刪除多餘的膨脹,就可以看到它將數據輸出翻倍,因爲它會創建一個名爲ItemArray的節點,其中包含所有相同的信息。

我希望這很容易理解。如果您需要更多信息,請告訴我。並提前感謝您提供任何幫助。

回答

1

我認爲你所需要做的就是在PowerShell腳本中更新你的兩個T-SQL查詢。第一個,添加如下代碼如下:


...., "Monthly" as ReportType FROM AccountDeviceStats ad1... 
第二個,像添加以下代碼:


...., "Total" as ReportType FROM AccountDeviceStats ad1... 

### Dates to use 
$Date = (Get-Date -f MM-dd-yyyy) 
$FDoTM = ((Get-Date -Day 01).AddMonths(0)).AddDays(0) 
$LDo2PM = ((Get-Date -Day 01).AddMonths(-1)).AddDays(-1) 
$TempDir = "C:\Temp" 
$WebDir =  @("\\x.x.x.x\c$\inetpub\wwwroot\Reports\Accounts","\\x.x.x.x\c$\inetpub\wwwroot\Reports\Accounts") 

### Something 

$OutputXML = "$Date-Monthly-AccountReport.xml" 

### Connection settings, uses windows authentication 

$DBServer = "OMMITED" 
$databasename = "OMMITED" 
$Connection = new-object system.data.sqlclient.sqlconnection #Set new object to connect to sql database 
$Connection.ConnectionString ="server=$DBServer;database=$databasename;trusted_connection=True" # Connectiongstring setting for local machine database with window authentication 
Write-host "Connection Information:" -foregroundcolor yellow -backgroundcolor black 
$Connection #List connection information 


### Connect to Database and Run Query 

$SqlCmd = New-Object System.Data.SqlClient.SqlCommand #setting object to use sql commands 

$OutputHeader1 = "This Month's counts" 
$SqlQuery1 = @" 

SET NOCOUNT ON; 

WITH AccountDeviceStats(serviceGroupName,numAccounts,numDevices) 
AS 
(
    SELECT svg.name,COUNT(acct.serviceGroupId) as Accounts, NULL FROM bm_account acct WITH  (NOLOCK) 
    INNER JOIN bm_servicegroup svg WITH (NOLOCK) ON svg.servicegroupId = acct.serviceGroupId 

    where acct.CreateStamp between '$($LDo2PM)' and '$($FDoTM)' 
GROUP BY acct.serviceGroupId,svg.name 
UNION ALL 
SELECT svg.name, NULL, COUNT(device.serviceGroupId) as Devices FROM bm_device device WITH (NOLOCK) 
INNER JOIN bm_servicegroup svg WITH (NOLOCK) ON svg.servicegroupId = device.serviceGroupId, bm_account acct 

where device.accountID=acct.accountId and acct.CreateStamp between '$($LDo2PM)' and '$($FDoTM)' 
GROUP BY device.serviceGroupId,svg.name 
) 
SELECT ad1.serviceGroupName,ad1.numAccounts,ad2.numDevices, ""Monthly"" as ReportType FROM AccountDeviceStats ad1 
INNER JOIN AccountDeviceStats ad2 ON ad1.serviceGroupName = ad2.serviceGroupName 
WHERE ad1.numAccounts IS NOT NULL AND ad2.numDevices IS NOT NULL 
ORDER BY numAccounts DESC,numDevices DESC 
"@ 

$OutputHeader2 = "Total Counts" 
$SqlQuery2 = @" 

SET NOCOUNT ON; 

WITH AccountDeviceStats(serviceGroupName,numAccounts,numDevices) 
AS 
(
SELECT svg.name,COUNT(acct.serviceGroupId) as Accounts, NULL FROM bm_account acct WITH  (NOLOCK) 
INNER JOIN bm_servicegroup svg WITH (NOLOCK) ON svg.servicegroupId = acct.serviceGroupId 

where acct.CreateStamp < '12-31-2099' 
GROUP BY acct.serviceGroupId,svg.name 
UNION ALL 
SELECT svg.name, NULL, COUNT(device.serviceGroupId) as Devices FROM bm_device device WITH (NOLOCK) 
INNER JOIN bm_servicegroup svg WITH (NOLOCK) ON svg.servicegroupId = device.serviceGroupId, bm_account acct 

where device.accountID=acct.accountId and acct.CreateStamp < '12-31-2099' 
GROUP BY device.serviceGroupId,svg.name 
) 
SELECT ad1.serviceGroupName,ad1.numAccounts,ad2.numDevices, ""Total"" as ReportType FROM AccountDeviceStats ad1 
INNER JOIN AccountDeviceStats ad2 ON ad1.serviceGroupName = ad2.serviceGroupName 
WHERE ad1.numAccounts IS NOT NULL AND ad2.numDevices IS NOT NULL 
ORDER BY numAccounts DESC,numDevices DESC 
"@ 

$sqlQueries = @($SqlQuery1, $SqlQuery2) 

$Results = @() 

Foreach ($Query in $sqlQueries){ 
    $Connection.open() 
    Write-host "Connection to database successful." -foregroundcolor green -backgroundcolor black 
    $SqlCmd.CommandText = $Query 
    $SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter 
    $SqlAdapter.SelectCommand = $SqlCmd 
    $SqlCmd.Connection = $Connection 
    $DataSet = New-Object System.Data.DataSet 
    $SqlAdapter.Fill($DataSet) 
    $Connection.Close() 

$Results += $DataSet.Tables[0] 

($Results | ConvertTo-XML -NoTypeInformation).Save("$TempDir\$OutputXML") 
} 

if ((Get-ChildItem $TempDir -filter "$Date-*.xml").count -gt 0){  
Foreach ($file in (Get-ChildItem $TempDir -filter "$Date-*.xml" -recurse)){ 
    Foreach ($webserver in $WebDir){ 
     Copy-Item $file.fullname "$webserver\$file" -force 
     } 
    Remove-Item $file.fullname -force 
    } 
} 
+0

嗯..這似乎並沒有工作,它通過一些錯誤,當我試圖運行它。它說「無效的列名」每月「。」我可能在錯誤的地方添加了它,我嘗試了2個地方,試圖將它添加到Order語句之前和之後。然後我嘗試在最初的FROM語句中添加「Monthly」作爲ReportType,我在其中抓取其他列名稱。 – chamele0n 2013-04-04 03:37:05

+0

更新答案,添加完整的代碼,您檢查是否已經在同一位置添加常量列。 – ljh 2013-04-04 05:31:05

+0

這很好。非常感謝。不知道如果我手動添加它時,我設法輸入錯誤信息。 – chamele0n 2013-04-04 20:50:03

0

原來的問題詢問如何從XML除去膨脹爲好。我一直在尋找一種解決方案,其中從SQL結果中生成的XML必須採用絕對特定的格式,並使用正確的標籤和所有內容。我發現,一旦你有你的數據集對象($ DataSet),那麼如果你看看有什麼方法和屬性可用,($ DataSet | gm),那麼其中一個是GetXML()。

這會自動格式化SQL輸出,使得每個返回的列(或列別名)作爲單獨的標記返回(儘管注意,它不會爲空值生成空標記),因此在此實例中,如果使用$ DataSet.GetXML()我預計會看到輸出的東西沿線

<NewDataSet> 
    <Table> 
    <serviceGroupName>ServiceGroup1</serviceGroupName> 
    <numAccounts>15</numAccounts> 
    <numDevices>28</numDevices> 
    </Table> 
</NewDataSet> 

所以沒有膨脹!因爲這只是一系列的字符串,你可以像($ Dataset.GetXML())這樣做。替換('NewDataSet','OuterTag')。替換('Table','InnerTag')到爲XML提供更好的標籤。一旦你滿意這個可以輸出

SET-CONTENT -PATH $xmlfilename -VALUE '<?xml version="1.0" ?>' 

或類似的文件,然後從您的getXML追加輸出()方法,讓你擁有更整潔格式化一段XML的!

($DataSet.GetXML()).Replace('NewDataSet','OuterTagName').Replace('Table','InnerTagName') | ADD-CONTENT -PATH $xmlfilename