【问题标题】:How to suppress hyphens in SQLCMD如何在 SQLCMD 中抑制连字符
【发布时间】:2010-03-02 09:57:03
【问题描述】:

如何在此sqlcmd 命令的结果集中抑制连字符 (------------):

C:\temp>sqlcmd -d AdventureWorks -s ";" 
 -Q "SET NOCOUNT ON SELECT top 5 FirstName, LastName FROM Person.Contact;"
FirstName                                         ;LastName
--------------------------------------------------;----------------------------
Gustavo                                           ;Achong
Catherine                                         ;Abel
Kim                                               ;Abercrombie
Humberto                                          ;Acevedo
Pilar                                             ;Ackerman

C:\temp>

【问题讨论】:

    标签: sql-server sqlcmd


    【解决方案1】:

    我没有在一次地方看到所有这些信息,并认为下一个寻找它的人可能会喜欢它...

    使用 -h -1 选项从输出中删除破折号 (--------) 并使用 SET NOCOUNT ON 删除“受影响的行”。如果您要创建报告或 CSV 文件以供其他系统处理,这非常有用。

    例子:

    SQLCMD -S 127.0.0.1\SQL_SERVER_Instance -d db_name -U db_login -P password -i your_script.sql -o your_output.csv -h -1
    

    在您的 SQL 脚本中:

    SET NOCOUNT ON -- removes (rows affected from the output)
    select 'your_column_1, your_column_2'
    select * from your_table
    

    您不需要为此在您的选择语句之间使用联合。

    【讨论】:

    • 请注意,-h 和 -1 之间不能有空格。仅使用:-h-1
    • @AAA 不确定这是真的,我正在使用带有 -h -1 的脚本没有问题,我的理解是它们就像任何其他命令行开关一样 -d 或 -你,很确定你需要空间
    • 虽然这确实删除了破折号“---”,但它也为我删除了列名
    • @davidski 注意在上面的脚本中你需要有一个额外的选择来实际做列名select 'your_column_1, your_column_2' select * from your_table
    • @Atricapilla:我相信这应该是公认的答案
    【解决方案2】:

    我唯一能想到的是使用-h -1 开关删除标题并将列名作为第一行添加到 SQL 查询:

    SELECT 'FirstName' as FirstName, 'LastName' as LastName
    UNION
    SELECT top 5 FirstName, LastName FROM Person.Contact
    

    注意,如果有其他数据类型然后(var)char,则需要使用CAST(MyColumnName AS varchar(32)) as MyColumnName转换字段

    【讨论】:

    • 请在下面查看我的回答。它不包含-h -1 并回答了问题。
    【解决方案3】:

    仅使用 sqlcmd 和 Windows 命令行,不使用存储过程:

    REM Get the column headers ("set nocount on" is necessary to suppress the rows affected message)
    sqlcmd -S MyServer -Q "set nocount on;select top 0 * from MyDatabase.MySchema.MyTable" -o "MyTableColumns.csv" -s "," -W
    
    REM Remove hyphen line
    findstr /R /C:"^[^-]*$" MyTableColumns.csv > MyTableHeader.csv
    
    REM Get data without headers
    sqlcmd -S MyServer -Q "set nocount on;select * from MyDatabase.MySchema.MyTable" -o "MyTableData.csv" -h -1 -s "," -W
    REM You can also use bcp for this step
    REM bcp "select * from MyDatabase.MySchema.MyTable" queryout  "MyTableData.csv"  -c -t"," -r"\n" -S MyServer -T
    
    REM Append header and data
    type MyTableHeader.csv MyTableData.csv > MyTableDataWithHeader.csv
    

    要处理内部带有分隔符的数据(例如“Atlanta, GA”),您需要单独指定字段(而不是使用“select *”)并使用 SQL Server 中的 QUOTENAME 函数。

    【讨论】:

      【解决方案4】:

      就是这样!

      如何从这个 sqlcmd 命令的结果集中抑制连字符 (------------):

      您可以在1条命令中以简单的方式完成所有操作,无需任何脚本或文件操作!!

      sqlcmd -d AdventureWorks -s ";" -Q "SET NOCOUNT ON; SELECT top 5 FirstName, LastName FROM Person.Contact" |findstr /v /c:"---"
      

      添加set nocount on; 以删除(X rows affected) 行。 添加 |findstr /v /c:"---" 以删除下划线。 这样你就可以得到一个清晰的答案,只需要:

      FirstName                                         ;LastName
      Gustavo                                           ;Achong
      Catherine                                         ;Abel
      Kim                                               ;Abercrombie
      Humberto                                          ;Acevedo
      Pilar                                             ;Ackerman
      

      【讨论】:

      • 但是标题在哪里?问题只是为了抑制连字符。
      • 太糟糕了,sql server 没有 Oracle 中的相关命令:“set und off”...
      • 是的,这现在解决了所提出的问题。我已经删除了我的反对票。
      • 而且,如果第一列曾经返回一个以 '---' 开头的字段,那么你也会把它扔掉。
      • @Dekso 要删除 Linux 中的破折号,请使用:grep -v '---'
      【解决方案5】:

      或者也许通过 sed 对输出进行后处理:

      sqlcmd ... | sed -e '2d'
      

      删除第二行?

      你可以从http://gnuwin32.sourceforge.net/packages/sed.htm获得一个Win32 sed

      【讨论】:

        【解决方案6】:

        您可以执行以下操作:

        exec 'sqlcmd -S YourServer -E -Q "set nocount on; select * from YourTable" -s "," -W | findstr /R /C:"^[^-]*$" > yourfile.csv'
        

        这将一举创建一个带有标题的 csv 文件,没有破折号,并修剪了空白区域。基于上面 MichaelM 的回答。

        【讨论】:

          【解决方案7】:

          为了去掉连字符,我在我的存储过程中添加了一些代码,这些代码将只输出列标题。使用SQLCMD 提取数据分两部分完成。

          首先,我使用一组特殊的参数调用我的存储过程。就我而言,当我用所有 NULL 调用 SP 时,这意味着我希望拥有列标题。

          然后我再次调用SQLCMD 并将输出附加到我刚刚创建的文件中,瞧!

          创建一个空白 CSV 文件来保存列标题

          sqlcmd -S server -d database -U username -P password -o "somefile.csv" -h-1 
            -Q "exec myStoredProcedure NULL, NULL" -W -w 2000 -s"," > sometextfile.csv
          

          现在追加存储过程的输出结果

          sqlcmd -S server -d database -U username -P password -o "somefile.csv" -h-1 
            -Q "exec myStoredProcedure 2011, 10" -W -w 2000 -s"," >> sometextfile.csv
          

          注意第一个命令使用>,第二个命令使用>>。当使用一个 -> “创建或覆盖”和两个 -> “追加或创建”时。

          • -h-1 删除 SQLCMD 生成的标头
          • -W 删除尾随空格
          • -w 设置最大行宽
          • -s 定义列分隔符

          【讨论】:

            【解决方案8】:

            我不得不进行大量研究,因为这里没有一个答案完全符合我的要求。所以我要总结一下,希望它能帮助别人。

            对我来说,最简单的方法是使用sed。虽然这里已经提出了建议,但同时运行 sqlcmd 和 sed 的语法不正确。如果您使用的是 Windows,就像我一样,请前往 http://gnuwin32.sourceforge.net/packages/sed.htm 下载 sed

            我的最终命令看起来像:

            SQLCMD -m 1 -S "userpc\SQLEXPRESS" -E -i "C:\someDirectory\sqlfile.sql" -W -s "," -o "C:\someDirectory\output.csv" && sed -i 2d "C:\someDirectory\output.csv"
            

            在哪里

            --m 1 消除了“将数据库上下文更改为...”这一行
            -&& 如果第一个命令运行成功,则运行第二个命令
            -sed -i 2d 删除包含连字符的第二行并将 sed 的输出覆盖为原始输出

            请注意sed 输出文件名和sqlcmd 的输出必须匹配,否则sqlcmd 的输出将不会被正确覆盖。上面回答的sed 语句中的2d 周围不应有引号,并且存在于他们的文档中,否则您将收到错误消息。

            希望这会有所帮助!

            【讨论】:

            • 请注意,在企业环境中,这可能是一个困难的解决方案,下载和安装为 *nix 平台构建的第三方开源软件可能会导致大量 IT HumBuging..特别是如果这个过程是设计为在 Windows Server 上运行,用于正式的业务流程。
            【解决方案9】:

            如果您可以改用 PowerShell

            工作示例:

            Invoke-DbaQuery "SELECT * FROM [MyApp].[dbo].[ClientConfig] WHERE ClientID='Default'" -SqlInstance mysql.mydomain.com -ReadOnly `
              | Export-Csv -Path clientconfig-default.csv -Encoding utf8 -UseQuotes AsNeeded
            

            注意-ReadOnly 仅对集群有用,并且可能是噪声(早期优化)。但我是一名查询/比较生产数据库的开发人员,因此过于谨慎,因此尽量减少 DBA 可能注意到的负载。

            我有时使用https://docs.dbatools.io/#Copy-DbaDbTableData 将整个表从 mssql 复制到 mssql。它很快,我认为使用 BCP.EXE 或 BulkInsert。

            【讨论】:

            • 它会为十进制/浮点数写入大量尾随零,但 sqlcmd 也是如此
            【解决方案10】:

            如果您可以先输出到文件(使用-o 选项),另一个使用 的后处理选项将通过读取文件的内容来工作——同时跳过第二行-- 并将其写回给自己。

            (Get-Content "file.txt" | Where {$_.ReadCount -ne 2}) | Set-Content "file.txt"
            

            【讨论】:

            • 当你在sqlcmd中有-h -1选项时,为什么你需要使用另一个外部工具作为PS?
            • @ShaiAlon -h -1 选项完全删除标题。问题是如何只删除出现在标题行后面的连字符。
            • 请再次检查我的答案,我已经解决了。
            • 如果您有可用的 powershell,请考虑:来自github.com/sqlcollaborative/dbatoolsInvoke-DbaQuery 或来自官方 MSSQL PowerShell 模块的Invoke-SqlCmd -Query。我的工作样本:Invoke-DbaQuery "SELECT * FROM [MyApp].[dbo].[ClientConfig] WHERE ClientID='Default'" -ReadOnly -SqlInstance mysql.mydomain.com | Export-Csv -Path clientconfig-default.csv -Encoding utf8 -UseQuotes AsNeeded
            【解决方案11】:

            MichaelM 有一个不错的解决方案,但正如 slingshot 指出的那样...... findstr 可能过于激进并删除包含连字符的数据行。另一种方法是调用 sqlcommand 来获取数据集,然后使用 set /p 从输出文件中获取第一行并将其分配给一个变量。然后删除原始输出文件。接下来,将标头回显到新文件。最后,将另一个无头 sqlcmd 通过管道传输到该文件。

            sqlcmd -S server -d database -E -Q "exec myStoredProcedure" -W -o my_headers.csv -m-1
            set /p headers=< my_headers.csv
            del my_headers.csv
            echo %headers% > my_data.csv
            sqlcmd -S server -d database -E -Q "exec myStoredProcedure" -W -m-1 -h-1 >> my_data.csv
            

            Top 0 也是创建“仅标题文件”的不错选择,但前提是您使用的是 select 语句。如果您正在调用存储过程,请考虑使用 FMTONLY ON 仅从 SP 中获取标头。

            sqlcmd -S server -d database -E -Q "Set NOCOUNT ON; Set FMTONLY ON; exec myStoredProcedure" -W -o my_headers.csv -m-1

            需要注意的是,FMTONLY ON 不能用于使用 #temp 表的 SP。这是因为 FMTONLY ON 不执行 SP。它只抓取元数据。但是,如果列名来自执行前不存在的表,那么您将无法获取这些列名。

            • 特洛伊

            【讨论】:

              【解决方案12】:
              Public Sub HyphenDelete(strFilename1 As String, Hyphens As Integer)
              
              
              Const FOR_READING = 1
              Const FOR_WRITING = 2
              
              strFileName = strFilename1
              
              strCheckForString = Left("-------", Hyphens)
              Set objFS = CreateObject("Scripting.FileSystemObject")
              Set objTS = objFS.OpenTextFile(strFileName, FOR_READING)
              strContents = objTS.ReadAll
              objTS.Close
              
              arrLines = Split(strContents, vbNewLine)
              Set objTS = objFS.OpenTextFile(strFileName, FOR_WRITING)
              
              For Each strLine In arrLines
                 If Not (Left(UCase(LTrim(strLine)), Len(strCheckForString)) = strCheckForString) Then
                    objTS.WriteLine strLine
                 End If
              Next
              
              End Sub
              

              【讨论】:

                【解决方案13】:

                如果输出到文件,在成功执行后尝试以下操作:

                    findstr /v /c:"---" sqloutput.dat > finaloutput.dat
                

                我使用“---”,因为我的所有列都超过 3 个字符,并且我的数据中从未包含该字符串,但您也可以使用“-;-”来进一步降低风险或根据您的数据使用任何分隔符“;”的位置。

                【讨论】:

                • 您可以在查询后立即执行,而无需重定向到文件
                • @ShaiAlon 管道更有效,但它需要“SET NOCOUNT”,并且还增加了小的误差范围:如果只有 2 列同时包含 1 或 2 个字符,那么这将失败,或者如果使用“- ;-" 并更改分隔符。这似乎是最安全的方法,因为它保留了 sqlcmd 输出。
                【解决方案14】:

                从结果中删除破折号:

                EXEC msdb.dbo.sp_send_dbmail
                @profile_name = 'testMail',
                @recipients = 'krishan@gmail.com',
                @query = '  
                SET NOCOUNT ON
                SELECT W.* FROM (
                (SELECT CAST("id" AS VARCHAR(5) ) as id , CAST("name" AS VARCHAR(50) )as name ) 
                UNION ALL 
                
                SELECT CAST( id AS VARCHAR(5) ) AS id, CAST (name AS VARCHAR(50) ) AS name from mydb.dbo.bank
                 )W
                ' ,
                @subject = 'Test email',
                @attach_query_result_as_file = 1,
                @query_attachment_filename='filename.xls',
                @query_result_separator='   ',   
                @query_result_header = 0
                
                    -----remember @query..separator should be--Tab space----
                

                【讨论】:

                  【解决方案15】:

                  我通常按如下方式处理生成的.csv 文件:

                  sed -i '2d' "$file"  # remove 2nd line of dashes
                  sed -i '$d' "$file"  # remove last line (row count string)
                  sed -i '$d' "$file"  # remove one more empty line at the end of the file
                  

                  地点:

                  • -i 就地编辑文件...
                  • 2d 删除第 2 行,在这种情况下,虚线...
                  • $d 删除文件末尾的单行...
                  • "$file" 是 bash 变量,用于保存 .csv 文件的路径字符串。

                  【讨论】:

                    【解决方案16】:

                    这就是我最终得到的并且对我来说效果很好:

                    sqlcmd -S 12.34.56.789 -i "C:\Qry.sql" -s"," -W -w1000 | findstr /V /R /C:"^[-,]*$" > Reprt.csv
                    

                    我相信在这一点上,findstr & regex 是所有需要解释的:

                    findstr /V /R /C:"^[-,]*$"
                    

                    正则表达式声明“在开头 ^,有 - 或,[-,] 任意次数 *,直到到达行尾 $

                    /V 的意思是,给我看任何不匹配的东西。

                    它后面的&gt; 将显示重定向到一个文件。

                    我也将它添加到我的 SQL 文件中:

                    SET NOCOUNT ON;
                    

                    【讨论】:

                      【解决方案17】:

                      下面一行:

                      findstr /R /C:"^[^-]*$" MyTableColumns.csv > MyTableHeader.csv
                      

                      非常危险,因为它会删除所有包含“-”的行。 你最好看看 findstr /?并使用类似的东西:

                      findstr /B /V /C:"-----" MyTableColumns.csv > MyTableHeader.csv
                      

                      【讨论】:

                        【解决方案18】:

                        如果你想将数据假脱机,那么你可以设置以下开关:

                        设置下划线关闭;

                        【讨论】:

                        • 完全错误;这甚至不是 SQL 中的有效命令,更不用说这个问题范围内的任何其他语言了。
                        【解决方案19】:

                        我认为没有任何方法可以实现这一点 - 恐怕你必须忍受这些标题。

                        【讨论】:

                        • 更准确地说,在实用程序的当前选项中,您可以拥有标题(带连字符)或完全删除它们;但你不能有没有连字符的标题名称。
                        • -h-1 删除 SQLCMD 生成的标头 sqlcmd -S server -d database -U username -P password -o "somefile.csv" -h-1 -Q "exec myStoredProcedure NULL, NULL" -W -w 2000 -s"," &gt; sometextfile.csv
                        • 请查看我下面的帖子。任何事情都可以在没有任何其他工具的情况下完成!
                        • @ShaiAlon "任何事情都可以用 sqlcmd 工具完成"?
                        • 我不知道为什么这被否决了这么多。您必须使用 shell(管道)或 Powershell,sqlcmd.exe 本身没有编写标准 CSV 文件的选项。我认为这充分说明了现代数据科学和 devops 场景中的 MSSQL(缺乏)可用性。
                        猜你喜欢
                        • 1970-01-01
                        • 2012-02-01
                        • 1970-01-01
                        • 2014-08-12
                        • 1970-01-01
                        • 1970-01-01
                        • 2021-08-18
                        • 1970-01-01
                        • 2011-01-27
                        相关资源
                        最近更新 更多