【问题标题】:Powershell - how to only apply foreach to distinct values that are returned from a T-SQL queryPowershell - 如何仅将 foreach 应用于从 T-SQL 查询返回的不同值
【发布时间】:2021-06-02 09:34:53
【问题描述】:

我对 powershell 非常陌生 - 目前使用它从我们的 EHR 中输出 PDF 文件,该 EHR 运行在 SQL 服务器数据库上。

在我的 powershell 函数中,我有一个 tsql 查询,它为同一事件返回多行。一个事件可能包含多个问题,每个问题都有多个答案 - 因此在 t-sql 查询结果中为每个事件创建多行。
我将在底部发布我的 pshell 函数代码(减去实际的 t-sql 查询) 我的 tsql 测试查询返回这些结果: t-sql query results for test event

在 PDF 输出中,我希望输出如下所示:
活动:面对面 - FPS 测试
日期:2021 年 3 月 2 日
答案:
信仰支持
麻醉品匿名 (NA)
测试
答案:
Note_text:
测试

事件:电话(其他)
日期:2021 年 3 月 3 日
Note_text:
测试第二个事件

通过将 t-sql 查询分成不同的查询,我可以很好地输出带有多个答案的问题,并且我也可以获得要输出的事件列表,但是当我尝试将两者结合起来时它会中断.我最终得到了这样的结果:

它为“社区连接”问题的每个答案拆分一个新条目,而不是创建一个列表。

有没有办法在 powershell 中使用 foreach 来查看从 t-sql 查询返回的不同 event_log_ids 而不是使用 foreach($table.rows 中的$row)?在单个事件有多行的情况下,与同一事件相关的每一行将具有相同的 event_log_id。

pshell函数代码:`function Get-MonthlyReport-ServiceNotes-FPS([string]$templatePath,[string]$pplid,[string]$programenrollmentid,[string]$fdom,[string]$ldom){ $dbconn = ($ConfigFile.Settings.DBCONN_EVOLV);

    # html template
    $templateFilename = "$($templatePath)\mr_segment_servicenotes - FPS.html";
    $htmltemplate = Get-HTMLTemplate -htmlfilename $templateFilename;
    $htmlbody = '';

    # sql query - returns columns actual_date, event_name, note_text, answer, and event_log_id
    
    
    Try
    {
        $connection = new-object system.data.SqlClient.SQLConnection($dbconn);
        $command = new-object system.data.sqlclient.sqlcommand($sqlquery,$connection);
        $command.CommandTimeout=0;
        $connection.Open();
        $adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command;
        $dataset = New-Object System.Data.DataSet;
        $adapter.Fill($dataSet) | Out-Null;
        $connection.Close();
        $table = $dataset.Tables[0]
        $eventLogList = @($dataset.Tables[0] | select-object -Property event_log_ids | Sort-Object | Get-unique)
        

        # default content
        $htmlcontent = $htmltemplate;

        if($dataset.Tables[0].Rows.count -gt 0){         

            # add content
            foreach($row in $table.rows) {    
        
                
                # remove HTML tags and formatting from note_text
                if (-not ("$($row.note_text)" -eq $null)) {
                    $ntxt = Remove-HTMLTags -html "$($row.note_text)";
                    $htmlbody += "<tr>";
                    $htmlbody += "<td style=`"font-size: 9pt; font-weight: bold;`">Service:<br>$($row.event_name)</td>";
                    $htmlbody += "</tr>"; 
                    $htmlbody += "<tr>";
                    $htmlbody += "<td style=`"font-size: 9pt; font-weight: bold;`">event_log_id:<br>$($row.event_log_ids)</td>";
                    $htmlbody += "</tr>";
                    $htmlbody += "<tr>";
                    $htmlbody += "<td style=`"font-size: 9pt; font-weight: bold;`">Date:<br>$($row.actual_date)</td>";
                    $htmlbody += "</tr>";
                    $htmlbody += "<tr>";
                    $htmlbody += "<td style=`"font-size: 9pt; font-weight: bold;`">Community Connection:<br>$($row.answer)</td>";
                    $htmlbody += "</tr>";
                    $htmlbody += "<tr>";
                    $htmlbody += "<td style=`"font-size: 9pt;`">$($ntxt)<br>"
                    $htmlbody += "<hr style=`"border-top: dotted 1px;`" /></td>";
                    $htmlbody += "</tr>";
                    
            
                    
                 
                }
            }

            # assemble html
            if (-not ([string]::IsNullOrEmpty($htmlbody))) { 
                 $htmlcontent = $htmlcontent.Replace("{{table-set}}",$($htmlbody));
            } else {
                $nodata = "<tr><td style=`"font-size: 9pt;`" colspan=`"3`">No service notes were provided during this period.</td><tr>";
                $htmlcontent = $htmlcontent.Replace("{{table-set}}",$($nodata));
            } 

        } else {

             #if no data is returned
            $nodata = "<tr><td style=`"font-size: 9pt;`" colspan=`"3`">No service notes were provided during this period.</td><tr>";
            $htmlcontent = $htmlcontent.Replace("{{table-set}}",$($nodata));
        }

        # return string
        return $htmlcontent; 
    }
    Catch
    {
        $me = "Get-MonthlyReport-ServiceNotes-FPS";
        $msg = $_.Exception.Message;
        Put-EventLog -key "ERROR" -eventtype "PROCESS" -eventsource $me -description $msg;
        throw $_.Exception; 
    } 
}`

【问题讨论】:

    标签: powershell tsql foreach


    【解决方案1】:

    如果您只想要 ID,那么在 SQL 中使用DISTINCT 就很简单了。

    在 Powershell 中,您可以执行类似的操作来获取列表。

    $SqlResults | Select-Object -Property event_log_ids | Sort-Object -Unique
    

    编辑:如果您使用的是 SQL Server 2016+,则可以使用 STRING_AGG 函数将答案合并到上游列表中。

    select actual_date
    --other fields
    , string_agg(Answer, ', ') as AnswerCommaSeparated
    , string_agg(Answer, char(13)+char(10)) as AnswerNewLineSeparated
    from SomeTable
    group by actual_date
    

    【讨论】:

    • 在 t-sql 中获取 ID 不是问题,它试图让 powershell 只为每个事件日志 ID 提供一个输出,而不是为每个新行复制所有内容 - 我更新了我的初始问题为了清楚起见,我的结果的屏幕截图。突出显示的部分应该都属于一个列表,而不是被分开。我希望通过获得一个不同的 event_log_ids 列表,我可以使用 foreach 而不是每一行
    • 能否请您在问题中发布您的代码和预期结果。我猜它应该类似于一个以 id 为键的哈希表和每个 id 的答案数组,但这只是一个猜测。
    • 刚刚用功能代码和预期结果更新了问题。谢谢!
    • 不幸的是,我们还没有使用 sql server 2016。这对未来很有帮助......如果这是唯一的解决方案,我可能会尝试让我的 sql 代码做类似的事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-13
    • 2013-05-29
    • 2018-03-18
    • 2011-02-03
    • 1970-01-01
    相关资源
    最近更新 更多