23 August 2011

ODBC (SQL Server) to CSV

I recently had need of a quick tool to pull data from a SQL Server database into a CSV file.
The following is quick and dirty, but it did the trick!

namespace ODBC_TO_CSV
{
  using System;
  using System.Data.Odbc;
  using Regex = System.Text.RegularExpressions.Regex;
  using StringBuilder = System.Text.StringBuilder;

  /// <summary>
  /// Main program
  /// 

  internal class Program
  {
    /// <summary>
    /// Main routine.
    /// 

    /// The args.
    private static void Main(string[] args)
    {
      var identity = System.Security.Principal.WindowsIdentity.GetCurrent();
      System.Threading.Thread.CurrentPrincipal = new System.Security.Principal.WindowsPrincipal(identity);

      try
      {
        var mapper = new Mapper(args);
        Program.GetData(mapper.SQL, mapper.DSN, mapper.OutFile);
      }
      catch (Exception ex)
      {
        Console.WriteLine("{0}:{1}", ex.GetType(), ex.Message);
      }
    }

    /// 
    /// Gets the data.
    ///</summary>
    /// The SQL.
    /// The DSN.
    /// The out file.
    private static void GetData(string sql, string dsn, string outFile)
    {
      Regex doubleQuote = new Regex("\\"");
      Regex newLine = new Regex("\\r\\n");

      Func<string, string> quote = input => String.Format("\\"{0}\\",", input);
      Func<string, string> removeBad = input =>
      {
        input = doubleQuote.Replace(input, "\\"\\"");
        input = newLine.Replace(input, "\\n");
        return input;
      };
      Func<StringBuilder, string> trim = builder => builder.ToString().Trim(new char[] { ,  });

      using (var conn = new OdbcConnection(dsn))
      {
        using (var cmd = conn.CreateCommand())
        {
          cmd.CommandText = sql;
          cmd.CommandType = System.Data.CommandType.Text;
          cmd.Connection.Open();
          using (var reader = cmd.ExecuteReader())
          {
            using (var writer = new System.IO.StreamWriter(outFile) { AutoFlush = true })
            {
              int records = 0;
              while (reader.Read())
              {
                int fieldCount = reader.FieldCount;
                if (records == 0)
                {
                  var header = new StringBuilder();
                  for (int i = 0; i < fieldCount; i++)
                  {
                    header.AppendFormat(quote(reader.GetName(i)));
                  }

                  writer.WriteLine(trim(header));
                  writer.Flush();
                }

                var builder = new StringBuilder();
                for (int i = 0; i < fieldCount; i++)
                {
                  object raw = reader.GetValue(i);
                  string value = String.Empty;

                  if (raw.GetType() == typeof(byte[]))
                  {
                    value = "0x";
                    foreach (byte item in raw as byte[])
                    {
                      value += item.ToString("X2");
                    }
                  }
                  else if (raw.GetType() == typeof(DateTime))
                  {
                    value = ((DateTime)raw).ToUniversalTime().ToString("o");
                  }
                  else
                  {
                    value = raw.ToString();
                  }
                  
                  builder.Append(quote(removeBad(value)));
#if DEBUG
                  Console.WriteLine(value);
#endif
                }

                writer.WriteLine(trim(builder));
                records += 1;
              }

              Console.WriteLine("Wrote {0} records", records);
              writer.Flush();
              writer.Close();
            }

            cmd.Connection.Close();
          }
        }
      }
    }
  }
}




namespace ODBC_TO_CSV
{
  using System;

  /// 
  /// Maps command line arguments to typed variables (by position)
  /// 

  public class Mapper
  {
    /// 
    /// Initializes a new instance of the  class.
    /// 

    /// The args.
    public Mapper(string[] args)
    {
      if (args.Length != 3)
      {
        throw new Exception("Expected three arguments");
      }
      else
      {
        this.SQL = args[0];
        this.DSN = String.Format("DSN={0}", args[1]);
        this.OutFile = args[2];
      }
    }

    /// 
    /// Prevents a default instance of the  class from being created.
    /// 

    private Mapper()
    {
      // no default ctor
    }
    
    /// 
    /// Gets or sets the SQL.
    /// 

    /// 
    /// The SQL.
    /// 

    public string SQL { get; set; }

    /// 
    /// Gets or sets the DSN.
    /// 

    /// 
    /// The DSN.
    /// 

    public string DSN { get; set; }

    /// 
    /// Gets or sets the out file.
    /// 

    /// 
    /// The out file.
    /// 

    public string OutFile { get; set; }
  }
}



No comments: