Skip to content

Commit d1c4019

Browse files
committed
Added option to script grid as INSERT
1 parent 61e2bf7 commit d1c4019

File tree

5 files changed

+141
-8
lines changed

5 files changed

+141
-8
lines changed

DBADashGUI/CustomReports/DBADashDataGridView.cs

Lines changed: 121 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
using System.Reflection;
1010
using System.Text;
1111
using System.Windows.Forms;
12+
using DBADashGUI.SchemaCompare;
13+
using System.Globalization;
1214

1315
namespace DBADashGUI.CustomReports
1416
{
@@ -37,7 +39,11 @@ private ToolStripMenuItem GetSaveTableMenuItem()
3739
new ToolStripMenuItem("From Data Table", Properties.Resources.DataTable_16x,
3840
(_, _) => SaveTable(false)) {ToolTipText = "Save underlying DataTable to table in SQL Server database"},
3941
new ToolStripMenuItem("From Grid", Properties.Resources.Table_16x,
40-
(_, _) => SaveTable(true)){ ToolTipText = "Save grid to table in SQL Server database" }
42+
(_, _) => SaveTable(true)){ ToolTipText = "Save grid to table in SQL Server database" },
43+
new ToolStripMenuItem("Script Data Table", Properties.Resources.SQLScript_16x,
44+
(_, _) => ScriptTable(false)) {ToolTipText = "Script underlying DataTable AS INSERT"},
45+
new ToolStripMenuItem("Script Grid", Properties.Resources.TableScript_16x,
46+
(_, _) => ScriptTable(true)){ ToolTipText = "Script grid as INSERT" }
4147
});
4248
return tsSave;
4349
}
@@ -482,9 +488,10 @@ private DataTable GetDataTableForExport(bool fromGrid)
482488
/// <param name="dataTable">The DataTable containing the schema to generate the CREATE TABLE command.</param>
483489
/// <param name="tableName">The name of the table to be created.</param>
484490
/// <returns>A string containing the SQL CREATE TABLE command.</returns>
485-
private static string GenerateCreateTableCommand(DataTable dataTable, string tableName)
491+
private static string GenerateCreateTableCommand(DataTable dataTable, string tableName, bool quoteTableName = true)
486492
{
487-
var commandText = new StringBuilder($"CREATE TABLE {tableName.SqlQuoteName()} (");
493+
var quotedTableName = quoteTableName ? tableName.SqlQuoteName() : tableName;
494+
var commandText = new StringBuilder($"CREATE TABLE {quotedTableName} (\n\t");
488495

489496
for (var i = 0; i < dataTable.Columns.Count; i++)
490497
{
@@ -505,11 +512,11 @@ private static string GenerateCreateTableCommand(DataTable dataTable, string tab
505512

506513
if (i < dataTable.Columns.Count - 1)
507514
{
508-
commandText.Append(", ");
515+
commandText.Append(",\n\t");
509516
}
510517
}
511518

512-
commandText.Append(");");
519+
commandText.Append("\n);");
513520

514521
return commandText.ToString();
515522
}
@@ -522,8 +529,8 @@ private static string GenerateCreateTableCommand(DataTable dataTable, string tab
522529
private static string ConvertToSqlType(DataColumn column)
523530
{
524531
var columnSize = column.MaxLength; // Note: Not set using DataAdapter Fill method, so types will end up being MAX
525-
const int numericPrecision = 18;
526-
const int numericScale = 0;
532+
const int numericPrecision = 28;
533+
const int numericScale = 9;
527534

528535
return column.DataType switch
529536
{
@@ -665,5 +672,112 @@ public DataTable DataGridViewToDataTable(DataGridView dgv)
665672

666673
return dt;
667674
}
675+
676+
// / <summary>
677+
// / Script DataGridView AS INSERT statements
678+
// / </summary>
679+
// / <param name="fromGrid">If true, saves the DataGridView to a table. If false, saves the underlying DataTable to a table.</param>
680+
private void ScriptTable(bool fromGrid)
681+
{
682+
const string tableName = "#DBADashGrid";
683+
try
684+
{
685+
var dt = GetDataTableForExport(fromGrid);
686+
var tableScript = GenerateCreateTableCommand(dt, tableName, false);
687+
var insertStatements = GenerateInsertStatementsWithBatching(dt, tableName, false);
688+
var header = @$"/*********************************************************
689+
----------------------------------------------------------
690+
| ____ ____ _ ____ _ |
691+
| | _ \ | __ ) / \ | _ \ __ _ ___ | |__ |
692+
| | | | || _ \ / _ \ | | | | / _` |/ __|| '_ \ |
693+
| | |_| || |_) |/ ___ \ | |_| || (_| |\__ \| | | | |
694+
| |____/ |____//_/ \_\ |____/ \__,_||___/|_| |_| |
695+
| |
696+
| SQL Server Monitoring by David Wiseman |
697+
| Copyright 2022 Trimble, Inc. |
698+
| https://dbadash.com |
699+
| https://github.com/trimble-oss/dba-dash |
700+
| Generated: {DateTime.Now:yyyy-MM-dd HH:mm:ss} |
701+
----------------------------------------------------------
702+
*********************************************************/
703+
704+
IF OBJECT_ID('tempdb..{tableName}') IS NOT NULL
705+
BEGIN
706+
DROP TABLE {tableName}
707+
END
708+
GO
709+
";
710+
var footer = $"\n\nSELECT {GetColumnList(dt)}\nFROM {tableName}\n\n--DROP TABLE {tableName}";
711+
var insertScript = header + tableScript + "\n" + string.Join("\n", insertStatements) + footer;
712+
var frm = new CodeViewer() { Code = insertScript, Language = CodeEditor.CodeEditorModes.SQL };
713+
frm.ShowDialog();
714+
}
715+
catch (Exception ex)
716+
{
717+
MessageBox.Show("Error generating script: " + ex.Message, "Error", MessageBoxButtons.OK,
718+
MessageBoxIcon.Error);
719+
}
720+
}
721+
722+
public static List<string> GenerateInsertStatementsWithBatching(DataTable dataTable, string tableName, bool quoteTableName = true)
723+
{
724+
const int batchSize = 1000;
725+
var insertStatements = new List<string>();
726+
var totalRows = dataTable.Rows.Count;
727+
var batchCount = (int)Math.Ceiling(totalRows / (double)batchSize);
728+
var quotedTableName = quoteTableName ? tableName.SqlQuoteName() : tableName;
729+
for (var batchIndex = 0; batchIndex < batchCount; batchIndex++)
730+
{
731+
var batchRows = dataTable.AsEnumerable().Skip(batchIndex * batchSize).Take(batchSize);
732+
var valuesList = batchRows.Select(row => string.Join(", ", row.ItemArray.Select((value, index) => FormatSqlValue(value, dataTable.Columns[index])))).Select(rowValues => $"({rowValues})").ToList();
733+
734+
var columnNames = GetColumnList(dataTable);
735+
var valuesClause = string.Join(",\n", valuesList);
736+
var insertStatement = $"INSERT INTO {quotedTableName} (\n\t{columnNames})\nVALUES {valuesClause};";
737+
insertStatements.Add(insertStatement);
738+
}
739+
740+
return insertStatements;
741+
}
742+
743+
private static string GetColumnList(DataTable dataTable) => string.Join(", \n\t", dataTable.Columns.Cast<DataColumn>().Select(c => c.ColumnName.SqlQuoteName()));
744+
745+
/// <summary>
746+
/// Formats a value for use in a SQL statement.
747+
/// </summary>
748+
private static string FormatSqlValue(object value, DataColumn column)
749+
{
750+
if (value == DBNull.Value)
751+
{
752+
return "NULL";
753+
}
754+
else if (column.DataType == typeof(string))
755+
{
756+
return value.ToString().SqlSingleQuoteWithEncapsulation();
757+
}
758+
else if (column.DataType == typeof(DateTime))
759+
{
760+
return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss.fff").SqlSingleQuoteWithEncapsulation();
761+
}
762+
else if (column.DataType == typeof(bool))
763+
{
764+
return (bool)value ? "1" : "0";
765+
}
766+
else if (column.DataType == typeof(byte[]))
767+
{
768+
// Convert byte array to hexadecimal string
769+
var byteArray = (byte[])value;
770+
var hexString = "0x" + BitConverter.ToString(byteArray).Replace("-", "");
771+
return hexString;
772+
}
773+
else if (column.DataType == typeof(int) || column.DataType == typeof(long) || column.DataType == typeof(short) || column.DataType == typeof(byte) || column.DataType == typeof(decimal) || column.DataType == typeof(float) || column.DataType == typeof(double))
774+
{
775+
return Convert.ToString(value, CultureInfo.InvariantCulture);
776+
}
777+
else
778+
{
779+
return value.ToString().SqlSingleQuoteWithEncapsulation();
780+
}
781+
}
668782
}
669783
}

DBADashGUI/ExtensionMethods.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,13 @@ public static SqlParameter Clone(this SqlParameter original)
418418
};
419419
}
420420

421+
/// <summary>
422+
/// Replace single ' quote with two single quotes '' and encloses in single quotes. Only to be used where input can't be parameterized
423+
/// </summary>
424+
/// <param name="value"></param>
425+
/// <returns></returns>
426+
public static string SqlSingleQuoteWithEncapsulation(this string value) => $"'{value.SqlSingleQuote()}'";
427+
421428
/// <summary>
422429
/// Replace single ' quote with two single quotes ''. Only to be used where input can't be parameterized
423430
/// </summary>
@@ -426,7 +433,7 @@ public static SqlParameter Clone(this SqlParameter original)
426433
public static string SqlSingleQuote(this string value) => value.Replace("'", "''");
427434

428435
/// <summary>
429-
/// Replicates SQL Server QUOTENAME function - wrapping text in square brackets and doubling up on right square bracket. Use SqlSingleQuote for single quotes.
436+
/// Replicates SQL Server QUOTENAME function - wrapping text in square brackets and doubling up on right square bracket. Use SqlSingleQuote/SqlSingleQuoteWithEncapsulation for single quotes.
430437
/// </summary>
431438
/// <param name="value"></param>
432439
/// <returns></returns>

DBADashGUI/Properties/Resources.Designer.cs

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

DBADashGUI/Properties/Resources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,4 +322,7 @@
322322
<data name="DataTable_16x" type="System.Resources.ResXFileRef, System.Windows.Forms">
323323
<value>..\Resources\DataTable_16x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
324324
</data>
325+
<data name="TableScript_16x" type="System.Resources.ResXFileRef, System.Windows.Forms">
326+
<value>..\Resources\TableScript_16x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
327+
</data>
325328
</root>
229 Bytes
Loading

0 commit comments

Comments
 (0)