2015-07-10 56 views
2

試圖創建一個將sql表寫入文件的clr作爲管道分隔符。來自CLR內部的動態sql連接字符串

未測試輸出尚未確定它是否正在嘗試創建連接字符串時遇到障礙。我希望它是動態的,因此它可以根據正在執行的SQL Server來計算連接字符串。

using System; 
using System.Data; 
using System.Data.SqlClient; 
using System.Data.SqlTypes; 
using System.Security; 
using System.Security.Principal; 
using Microsoft.SqlServer.Server; 

public partial class CLR_uspExportToFiles 
{ 
    [Microsoft.SqlServer.Server.SqlProcedure] 
    public static void uspExportToFiles(string TableOrQuery, string Delimiter, int Debug, string FilePath, string Filename) 
    { 
     var output = FilePath + Filename; 
     using (System.IO.StreamWriter file = new System.IO.StreamWriter(output)) 
     { 

      const string DATASOURCE = "Data Source="; 
      const string INITIALCATALOG = ";Initial Catalog="; 
      const string INTEGRATEDSECURITY = ";Integrated Security=True;Enlist=false;"; 

      string ConnString; 
      string InstanceName; 
      string DbName; 

      //Establish a connection in the current context to dynamically get the current 
      //Server and Database Name. 
      using (SqlConnection sysconn = new SqlConnection("context connection=true")) 
      { 
       SqlCommand GetSQLSystemProperties = new SqlCommand(); 
       GetSQLSystemProperties.Connection = sysconn; 

       sysconn.Open(); 

       //Get the current SQL Server instance name 
       GetSQLSystemProperties.CommandText = "SELECT @@Servername"; 
       InstanceName = (string)GetSQLSystemProperties.ExecuteScalar(); 

       //Get the current Database Name 
       GetSQLSystemProperties.CommandText = "SELECT DB_NAME()"; 
       DbName = (string)GetSQLSystemProperties.ExecuteScalar(); 
       sysconn.Close(); 


       //Dynamically construct the connection string to establish a connection outside 
       //of the current context, so that any error written to the error table won't be 
       //rolled back. 
       ConnString = DATASOURCE + InstanceName + INITIALCATALOG + DbName + INTEGRATEDSECURITY; 

       using (SqlConnection conn = new SqlConnection(ConnString)) 
       { 

        using (SqlCommand cmd = new SqlCommand("SELECT * FROM @TableOrQuery", conn)) 
        { 
         //cmd.CommandType = CommandType.StoredProcedure; 
         cmd.Parameters.AddWithValue("@TableOrQuery", TableOrQuery); 
         //cmd.Parameters.AddWithValue("@Del", Delimiter); 
         //cmd.Parameters.AddWithValue("@Debug", Debug); 
         //cmd.Parameters.AddWithValue("@FilePath", FilePath); 
         //cmd.Parameters.AddWithValue("@Filename", Filename); 

         using (SqlDataAdapter sda = new SqlDataAdapter()) 
         { 
          sda.SelectCommand = cmd; 
          using (DataTable dt = new DataTable()) 
          { 
           sda.Fill(dt); 
           //Build the Text file data. 
           string txt = string.Empty; 

           foreach (DataColumn column in dt.Columns) 
           { 
            //Add the Header row for Text file. 
            txt += column.ColumnName + "|"; 
           } 

           //Add new line. 
           txt += "\r\n"; 
           file.WriteLine(txt); 
           foreach (DataRow row in dt.Rows) 
           { 
            foreach (DataColumn column in dt.Columns) 
            { 
             //Add the Data rows. 
             txt += row[column.ColumnName].ToString() + "|"; 
            } 

            //Add new line. 
            txt += "\r\n"; 
            file.WriteLine(txt); 
           } 

          } 

         } 
        }; 

       } 
      } 
     } 
    } 
} 

得到一個錯誤,雖然

Msg 6522, Level 16, State 1, Procedure CLR_uspExportToFiles, Line 0 
A .NET Framework error occurred during execution of user-defined routine or aggregate "CLR_uspExportToFiles": 
System.Data.SqlClient.SqlException: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified) 
System.Data.SqlClient.SqlException: 
    at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) 
    at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) 
    at System.Data.SqlClient.TdsParser.Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, Boolean ignoreSniOpenTimeout, Int64 timerExpire, Boolean encrypt, Boolean trustServerCert, Boolean integratedSecurity, Boolean withFailover, SqlAuthenticationMethod authType) 
    at System.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean ignoreSniOpenTimeout, TimeoutTimer timeout, Boolean withFailover) 
    at System.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString connectionOptions, SqlCredential credential, TimeoutTimer timeout) 
    at System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectionOptions, SqlCredential credential, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance) 
    at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePa... 

和不知道如何解決

+0

上下文連接已經是當前服務器,爲什麼還需要另一個連接? –

+1

'「SELECT * FROM @TableOrQuery」'你不能參數化數據庫對象標識符 –

+0

謝謝,我試着在線構建它的代碼並改變它現在的工作。 也命中該錯誤亞歷克斯感謝,使用(SqlConnection的康恩=新的SqlConnection( 「上下文連接=真」)) { conn.Open()改爲 ; var sqlString = string.Format(「SELECT * FROM {0}」,TableOrQuery); – JQuery

回答

1

的幾個注意事項:

  1. ,您應該使用Sql***類型,而不是本機.NET類型。意思是,SqlString(或有時SqlChars)而不是string,SqlInt32而不是int等。請參閱Mapping CLR Parameter Data獲取完整列表。
  2. 我想你打開你的文件和數據庫連接的順序錯誤。查詢可能不會返回任何內容:並非所有查詢都返回結果集,並且出現一些錯誤。直到命令成功完成並指示返回了某些內容,我纔會打開該文件。
  3. 我看不到任何理由打開到服務器的外部連接。我看到了有關不想讓某些東西回滾的評論,但這沒有多大意義。
  4. 由於您不需要第二個外部連接,因此您不需要這兩個查詢(SELECT @@SERVERNAMESELECT DB_NAME())。
  5. 即使您確實需要(或只是想要)這兩個信息,您只需要查詢@@SERVERNAME。您可以通過Database屬性從SqlConnection獲取數據庫名稱。是的,當使用Context Connection時,它將被設置爲當前數據庫(該查詢的當前數據)。
  6. 請勿使用Parameters.AddWithValue。分別創建參數並指定SqlDbType和最大長度。
  7. 不是使用DataTable除非你絕對肯定地確信傳入的任何表永遠不會是那麼大(在數據/已用空間而不是索引方面)。 Fill方法將整個結果集吸收到內存中(即DataTable)。這很危險。您應該使用SqlDataReader,並從SqlDataReader中讀取結果集的每一行寫入該文件。
  8. 不需要txt變量。您可以通過Write方法讀出每個字段。
  9. 即使你確實想件連接成一個字符串,每行一次寫出來,你就不需要(即\r\n)追加換行符作爲由WriteLine方法來處理(同樣適用於Console.Write VS Console.WriteLine )。通過使用WriteLine和追加\r\n,每一行數據將以空行分隔。

有關一般使用SQLCLR的更多信息,請參閱我在SQL Sever Central上編寫的系列文章:Stairway to SQLCLR(需要免費註冊)。

此外,我已經編寫了一個SQLCLR存儲過程來完成此操作(將查詢的結果集轉儲到文件中),作爲SQL#庫的一部分。請注意,雖然有一個免費版本的SQL#,但DB_BulkExport存儲過程僅在完整版中可用。

+1

感謝您的意見,讓它工作雖然:) – JQuery

+0

@JQuery很高興你有它的工作。請記住,至少要點**#1 **和**#7 **。 Item **#7 **尤其可能會對您的服務器產生巨大的負面影響。 –

+0

謝謝,這是隻有一個發票提取物將永遠不會超過幾行。然而,將它用於任何表/查詢可能會更通用。已經閱讀了幾個樓梯之前,所以會給這個看看:) – JQuery