C# OdbcDataReader or DataTable.Load column name issue - c#

I was happy coding my application and I faced this issue that scary me a little bit.
I have a SQLite db file and when I try to read a table using the OdcbDataReader and load it into a table using the DataTable.Load I get different results on the column name depending on the application I'm working on.
Sometimes it returns table_name.column_name and sometimes it returns only column_name.
The code is only this:
public DataTable GetTable(string table_name)
{
table = null;
if (conn_str != null)
{
try
{
using (OdbcConnection conn = new OdbcConnection(conn_str.ToString()))
{
StringBuilder query = new StringBuilder();
query.Append("SELECT * ");
query.Append("FROM [");
query.Append(table_name + "]");
using (OdbcCommand cmd = new OdbcCommand(query.ToString(), conn))
{
conn.Open();
table = new DataTable();
using (OdbcDataReader dr = cmd.ExecuteReader())
{
DataSet ds = new DataSet();
ds.EnforceConstraints = false;
ds.Tables.Add(table);
table.Load(dr);
}
}
}
}
catch (Exception ex)
{
Debug.Print(ex.Message);
table = null;
}
}
return table;
}
The connection string used is exactly the same:
"DRIVER={SQLite3 ODBC Driver};DATABASE=databesename.db3;"
Any ideas why this is happening?

Don't resolve the issue but at least gives an workaround.
Adding a replace to column name to remove the table_name if the Reader insert it.
foreach (DataColumn col in table.Columns)
{
//Fix column names if the Reader insert the table name into the ColumnName
col.ColumnName = col.ColumnName.Replace(table_name + ".", "");
}
Code After the change:
public DataTable GetTable(string table_name)
{
table = null;
if (conn_str != null)
{
try
{
using (OdbcConnection conn = new OdbcConnection(conn_str.ToString()))
{
StringBuilder query = new StringBuilder();
query.Append("SELECT * ");
query.Append("FROM [");
query.Append(table_name + "]");
using (OdbcCommand cmd = new OdbcCommand(query.ToString(), conn))
{
conn.Open();
table = new DataTable();
using (OdbcDataReader dr = cmd.ExecuteReader())
{
DataSet ds = new DataSet();
ds.EnforceConstraints = false;
ds.Tables.Add(table);
table.Load(dr);
foreach (DataColumn col in table.Columns)
{
//Fix column names if the Reader insert the table name into the ColumnName
col.ColumnName = col.ColumnName.Replace(table_name + ".", "");
}
}
}
}
}
catch (Exception ex)
{
Debug.Print(ex.Message);
table = null;
}
}
return table;
}

Related

Fastest way to join multiple data tables from multiple functions - c#

A function in my app is returning a data table by joining the data tables getting from many other sub functions. Each sub functions are independent to each other with common primary key. Now, It takes nearly two minutes to execute the function for 50 of students. Please suggest me a best/fastest way to achieve the same.
public DataTable ShowReportOnGridivew(int class_id, string searchDate)
{
DataTable dt_students_List = null;
try
{
//====Main Table=====//
dt_students_List = GetDistinctStudentList(class_id);//there will be around minimum of 50 students
if (dt_students_List != null)
dt_students_List.PrimaryKey = new DataColumn[] { dt_students_List.Columns["student_id"] };
//Tables need to merge with main table
DataTable dt_CurrentRank = null;
DataTable dt_ScoreInEnglish = null;
DataTable dt_AcademicDetails = null;
DataTable dt_ExtraCurriculam = null;
DataTable dt_Attendance = null;
DataTable dt_Arts = null;
DataTable dt_FuelToBridger = null;
DataTable dt_FuelToAircraft = null;
DataTable dt_TeacherFeedback = null;
DataTable dt_TotalScore = null;
foreach (DataRow row in dt_students_List.Rows)
{
string student_id = row["student_id"].ToString();//primary key
//==========Current Rank================//
dt_CurrentRank = GetCurrentRank(student_id);//Binding data using sql
dt_CurrentRank.PrimaryKey = new DataColumn[] { dt_CurrentRank.Columns["student_id"] };
if (dt_CurrentRank != null)
{
dt_students_List.Merge(dt_CurrentRank);
}
//====== Score in English =====
dt_ScoreInEnglish = GetScoreInEnglish(student_id, searchDate);
dt_ScoreInEnglish.PrimaryKey = new DataColumn[] { dt_ScoreInEnglish.Columns["student_id"] };
if (dt_ScoreInEnglish != null)
{
dt_students_List.Merge(dt_ScoreInEnglish);
}
//====== Academic Details =====
dt_AcademicDetails= GetAcademicDetails(student_id);
dt_AcademicDetails.PrimaryKey = new DataColumn[] { dt_AcademicDetails.Columns["student_id"] };
if (ddt_AcademicDetails != null)
{
dt_students_List.Merge(dt_AcademicDetails);
}
//=====Similarly calling other functions and merging the columns to dt_students_List ======
}
}
catch (Exception show_error)
{
string log_data = "Response: Error- " + show_error.ToString();
obj.DatalogFile("StudentsList", log_data);
throw show_error;
}
return dt_students_List;
}
====== Each sub functions are written like below.=============
private async DataTable GetCurrentRank(string student_id)
{
DataTable dt = null;
SqlConnection con = new SqlConnection(conn);
SqlCommand cmd = null;
SqlDataReader dr = null;
string sql = string.Empty;
sql = "SELECT student_id,current_rank FROM student_details WHERE " +
" student_id = #student_id ";
cmd = new SqlCommand(sql, con);
con.Open();
try
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#student_id", student_id);
dr = cmd.ExecuteReader();
dt = new DataTable("CurrentRank");
dt.Columns.AddRange(new DataColumn[2] { new DataColumn("student_id", typeof(int)),
new DataColumn("current_rank", typeof(float))});
if (dr.HasRows)
{
dt.Load(dr);
}
string log_data = "Web App Function: GetCurrentRank \n";
log_data += "Response: " + JsonConvert.SerializeObject(dt);
obj.DatalogFile("GetCurrentRank", log_data);
return dt;
}
catch (Exception show_error)
{
string log_data = "Response: Error- " + show_error.ToString();
obj.DatalogFile("GetCurrentRank", log_data);
throw show_error;
}
finally
{
cmd.Dispose();
con.Close();
con.Dispose();
}
}
You can write multiple select statement in single stored procedure;
and get output in DataSet.
You can get all your tables in a single request:
CREATE PROCEDURE Demo
**Parameters**
AS
-- Your all functions select statements
GO;
C#:
public DataSet GetDataSet(string ConnectionString, string SpName)
{
SqlConnection conn = new SqlConnection(ConnectionString);
SqlDataAdapter da = new SqlDataAdapter();
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = SpName;
da.SelectCommand = cmd;
DataSet ds = new DataSet();
///conn.Open();
da.Fill(ds);
///conn.Close();
return ds;
}

How to modify specific cell value mysql table in c#?

I have table
itemID
storeID
qty
103
LAB
20
I want to add qantity of specific item for example:'103' stored in warehouse 'LAB'.
public void addQuantity(string store, string item, int qty)
{
con.Open();
string sql = "SELECT qty,warehouse.storeID,item.itemID FROM Item,warehouse,stocker WHERE stocker.storeID=warehouse.storeID AND stocker.itemID=item.itemID AND warehouse.storeID='"+store+"' AND Item.itemID='"+item+"' ";
using (MySqlDataAdapter adapter = new MySqlDataAdapter(sql, con))
{
using (DataTable tempTable = new DataTable())
{
adapter.Fill(tempTable);
if (tempTable.Rows.Count == 0) throw new Exception("No such product");
foreach (DataRow r in tempTable.Rows)
{
int newQty = (int)r["qty"] + qty;
if (newQty > 0)
{
r["qty"] = newQty;
qty = 0;
break;
}
else
{
MessageBox.Show("error");
}
}
using (MySqlCommandBuilder cb = new MySqlCommandBuilder(adapter))
{
adapter.UpdateCommand = cb.GetUpdateCommand();// there is error
adapter.Update(tempTable);
}
}
}
con.Close();
}
it says:"Dynamic SQL generation is not supported for multiple base tables".
what would you advice me?
If qty is integer column, you may try to:
Increment its current value by some value:
using (var updateCommand = new MySqlCommand())
{
updateCommand.CommandText = "UPDATE mytable t SET t.qty = t.qty + #newQty WHERE *...Your WHERE clause...*`"
updateCommand.Parameters.AddWithValue("#newQty", newQtyValue);`
// ...
}
Or append entire new value:
using (var updateCommand = new MySqlCommand())
{
updateCommand.CommandText = "UPDATE mytable t SET t.qty = #newQtyValue WHERE *...Your WHERE clause...*`"
updateCommand.Parameters.AddWithValue("#newQtyValue", newQtyValue);`
// ...
}
As #sticky bit said, it is preferred to use Command.Parameters.AddWithValue instead of string concat/interpolation.

No value given for one or more required parameters error - Excel

I am getting data from excel and showing it in DataGridWiew.
I have two textboxes, one is for starting index for first record and other is for last record.
Code works fine. But lets suppose starting record is 1 and ending is 10 when I change 10 to 1 or 2 it gives me an error in this line:
adapter.Fill(dataTable);
Full Code is below:
public DataSet Parse(string fileName)
{
string connectionString = string.Format("provider = Microsoft.Jet.OLEDB.4.0; data source = {0}; Extended Properties = Excel 8.0;", fileName);
DataSet data = new DataSet();
foreach (var sheetName in GetExcelSheetNames(connectionString))
{
using (OleDbConnection con = new OleDbConnection(connectionString))
{
string query = "";
var dataTable = new DataTable();
if(tbStarting.Text.Trim()=="" && tbEnding.Text.Trim() == "")
{
query = string.Format("SELECT * FROM [{0}]", sheetName);
}
else
{
query = string.Format("SELECT * FROM [{0}] where SrNo between " + int.Parse(tbStarting.Text.Trim()) + " and " + int.Parse(tbEnding.Text.Trim()) + " order by SrNo", sheetName);
}
con.Open();
OleDbDataAdapter adapter = new OleDbDataAdapter(query, con);
adapter.Fill(dataTable);
data.Tables.Add(dataTable);
con.Close();
}
}
return data;
}
static string[] GetExcelSheetNames(string connectionString)
{
OleDbConnection con = null;
DataTable dt = null;
con = new OleDbConnection(connectionString);
con.Open();
dt = con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if (dt == null)
{
return null;
}
String[] excelSheetNames = new String[dt.Rows.Count];
int i = 0;
foreach (DataRow row in dt.Rows)
{
excelSheetNames[i] = row["TABLE_NAME"].ToString();
i++;
}
return excelSheetNames;
}
Why this is happening please help me?
Looking at the code, it seems that your procedure is working when you ask to retrieve all the record in each table. But you are not showing which table (Sheet) is actually used afterwars.
Chances are, you are using the first one only.
When you submit some parameters, only one of the tables (Sheets) can fulfill those requirements. The other(s) don't, possibly because a field named [SrNo] is not present.
This causes the More Parameters Required error when trying to apply a filter.
Not related to the error, but worth noting: you don't need to recreate the whole DataSet + DataTables to filter your DataSources.
The DataSet.Tables[N].DefaultView.RowFilter can be used to get the same result without destroying all the objects each time a filter is required.
RowFilter has some limitations in the language (e.g. does not support BETWEEN, Field >= Value1 AND Field <= Value2 must be used), but it's quite effective.
This is a possible setup:
(xDataSet is a placeholder for your actual DataSet)
//Collect the values in the TextBoxes in a string array
private void button1_Click(object sender, EventArgs e)
{
string[] Ranges = new string[] { tbStarting.Text.Trim(), tbEnding.Text.Trim() };
if (xDataSet != null)
FilterDataset(Ranges);
}
private void FilterDataset(string[] Ranges)
{
if (string.IsNullOrEmpty(Ranges[0]) & string.IsNullOrEmpty(Ranges[1]))
xDataSet.Tables[0].DefaultView.RowFilter = null;
else if (string.IsNullOrEmpty(Ranges[0]) | string.IsNullOrEmpty(Ranges[1]))
return;
else if (int.Parse(Ranges[0]) < int.Parse(Ranges[1]))
xDataSet.Tables[0].DefaultView.RowFilter = string.Format("SrNo >= {0} AND SrNo <= {1}", Ranges[0], Ranges[1]);
else
xDataSet.Tables[0].DefaultView.RowFilter = string.Format("SrNo = {0}", Ranges[0]);
this.dataGridView1.Update();
}
I've modified your code you code a bit to handle those requirements.
(I've left here those filters anyway; they're not used, but if you still want them, they are in a working condition)
DataSet xDataSet = new DataSet();
string WorkBookPath = #"[Excel WorkBook Path]";
//Query one Sheet only. More can be added if necessary
string[] WBSheetsNames = new string[] { "Sheet1" };
//Open the Excel document and assign the DataSource to a dataGridView
xDataSet = Parse(WorkBookPath, WBSheetsNames, null);
dataGridView1.DataSource = xDataSet.Tables[0];
dataGridView1.Refresh();
public DataSet Parse(string fileName, string[] WorkSheets, string[] ranges)
{
if (!File.Exists(fileName)) return null;
string connectionString = string.Format("provider = Microsoft.ACE.OLEDB.12.0; " +
"data source = {0}; " +
"Extended Properties = \"Excel 12.0;HDR=YES\"",
fileName);
DataSet data = new DataSet();
string query = string.Empty;
foreach (string sheetName in GetExcelSheetNames(connectionString))
{
foreach (string WorkSheet in WorkSheets)
if (sheetName == (WorkSheet + "$"))
{
using (OleDbConnection con = new OleDbConnection(connectionString))
{
DataTable dataTable = new DataTable();
if ((ranges == null) ||
(string.IsNullOrEmpty(ranges[0]) || string.IsNullOrEmpty(ranges[1])) ||
(int.Parse(ranges[0]) > int.Parse(ranges[1])))
query = string.Format("SELECT * FROM [{0}]", sheetName);
else if ((int.Parse(ranges[0]) == int.Parse(ranges[1])))
query = string.Format("SELECT * FROM [{0}] WHERE SrNo = {1}", sheetName, ranges[0]);
else
query = string.Format("SELECT * FROM [{0}] WHERE (SrNo BETWEEN {1} AND {2}) " +
"ORDER BY SrNo", sheetName, ranges[0], ranges[1]);
con.Open();
OleDbDataAdapter adapter = new OleDbDataAdapter(query, con);
adapter.Fill(dataTable);
data.Tables.Add(dataTable);
};
}
}
return data;
}
static string[] GetExcelSheetNames(string connectionString)
{
string[] excelSheetNames = null;
using (OleDbConnection con = new OleDbConnection(connectionString))
{
con.Open();
using (DataTable dt = con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null))
{
if (dt != null)
{
excelSheetNames = new string[dt.Rows.Count];
for (int i = 0; i < dt.Rows.Count; i++)
{
excelSheetNames[i] = dt.Rows[i]["TABLE_NAME"].ToString();
}
}
}
}
return excelSheetNames;
}

Trying to read a CSV file, but values wont show in SQL database

I am reading a CSV file, but it only makes the SQL table with 2 column (ID and test)`but it wont fill those column with values from the CSV file. Here is the code I got:
public void GetDataTabletFromCSVFile2(string csv_file_path, string tablenaam)
{
string cn = ConfigurationManager.ConnectionStrings["Scratchpad"].ConnectionString;
using (SqlConnection dbConnection = new SqlConnection(cn))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = dbConnection;
cmd.CommandType = CommandType.Text;
cmd.CommandText = $#"CREATE TABLE test (
[ID] INT IDENTITY (1, 1) NOT NULL,
[testingcolumn] VARCHAR (1023) NULL,
CONSTRAINT [PK_{test}] PRIMARY KEY CLUSTERED ([ID] ASC)
)";
try
{
dbConnection.Open();
cmd.ExecuteNonQuery();
}
catch (SqlException e)
{
MessageBox.Show(e.Message.ToString(), "Error Message");
}
finally
{
dbConnection.Close();
}
}
}
string line;
System.Data.DataTable csvData = new System.Data.DataTable();
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader(csv_file_path);
while ((line = file.ReadLine()) != null)
{
DataRow newRow = csvData.NewRow();
csvData.Rows.Add(newRow);
}
file.Close();
InsertDataIntoSQLServerUsingSQLBulkCopy2(csvData, tablenaam);
}
static void InsertDataIntoSQLServerUsingSQLBulkCopy2(System.Data.DataTable csvFileData, string Tablename)
{
string cn = ConfigurationManager.ConnectionStrings["Scratchpad"].ConnectionString;
using (SqlConnection dbConnection = new SqlConnection(cn))
{
dbConnection.Open();
string sqlTrunc = "TRUNCATE TABLE " + Tablename;
SqlCommand cmd = new SqlCommand(sqlTrunc, dbConnection);
cmd.ExecuteNonQuery();
using (SqlBulkCopy s = new SqlBulkCopy(dbConnection))
{
s.ColumnMappings.Clear();
s.DestinationTableName = Tablename;
foreach (var column in csvFileData.Columns)
s.ColumnMappings.Add(column.ToString(), column.ToString());
s.WriteToServer(csvFileData);
dbConnection.Close();
}
}
}
My SQL table looks like this now:
------------
| ID | test|
------------
|null|null |
------------
While it should look like:
-------------
| ID | test |
-------------
|1 |value1|
-------------
|2 |value2|
-------------
|3 |value3|
-------------
EDIT: this didnt work either:
string line;
System.Data.DataTable csvData = new System.Data.DataTable();
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader(csv_file_path);
int i = 0;
DataColumn datecolumn = new DataColumn("ID");
datecolumn.AllowDBNull = true;
csvData.Columns.Add(datecolumn);
DataColumn datecolumn2 = new DataColumn("RunTimeGroupCheck");
datecolumn.AllowDBNull = true;
csvData.Columns.Add(datecolumn2);
while ((line = file.ReadLine()) != null)
{
var id = (i++); //Code this method
var test = (line); //Code this method
csvData.Rows.Add(id, test);
}
file.Close();
InsertDataIntoSQLServerUsingSQLBulkCopy2(csvData, tablenaam);
You need proper data types, and proper insertion.
public void GetDataTabletFromCSVFile2(string csv_file_path, string tablenaam)
{
string cn = ConfigurationManager.ConnectionStrings["Scratchpad"].ConnectionString;
using (SqlConnection dbConnection = new SqlConnection(cn))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = dbConnection;
cmd.CommandType = CommandType.Text;
// check if You really want test for table name, not tablenaam
// mind that the column name is same as the DataTable's column name!!!!
cmd.CommandText = $#"CREATE TABLE test (
[ID] INT IDENTITY (1, 1) NOT NULL,
[RunTimeGroupCheck] VARCHAR (1023) NULL,
CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED ([ID] ASC)
)";
try
{
dbConnection.Open();
cmd.ExecuteNonQuery();
}
catch (SqlException e)
{
MessageBox.Show(e.Message.ToString(), "Error Message");
}
finally
{
dbConnection.Close();
}
}
}
string line;
System.Data.DataTable csvData = new System.Data.DataTable();
DataColumn firstColumn = new DataColumn("ID", typeof(int));
firstColumn.AutoIncrement = true; // This is the thing that enables You to leave the ID column. It will autoincrement.
firstColumn.AutoIncrementSeed = 1;
firstColumn.AutoIncrementStep = 1;
csvData.Columns.Add(firstColumn);
csvData.Columns.Add(new DataColumn("RunTimeGroupCheck", typeof(string)));
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader(csv_file_path);
while ((line = file.ReadLine()) != null)
{
DataRow newRow = csvData.NewRow();
// missing filling of data. You need the line to be put somewhere.
// also mind, that the newRow["ID"] is not set to anything.
newRow["RunTimeGroupCheck"] = line;
csvData.Rows.Add(newRow);
}
file.Close();
InsertDataIntoSQLServerUsingSQLBulkCopy2(csvData, tablenaam);
}
static void InsertDataIntoSQLServerUsingSQLBulkCopy2(System.Data.DataTable csvFileData, string Tablename)
{
string cn = ConfigurationManager.ConnectionStrings["Scratchpad"].ConnectionString;
using (SqlConnection dbConnection = new SqlConnection(cn))
{
dbConnection.Open();
string sqlTrunc = "TRUNCATE TABLE " + Tablename;
SqlCommand cmd = new SqlCommand(sqlTrunc, dbConnection);
cmd.ExecuteNonQuery();
using (SqlBulkCopy s = new SqlBulkCopy(dbConnection))
{
s.ColumnMappings.Clear();
s.DestinationTableName = Tablename;
foreach (var column in csvFileData.Columns)
s.ColumnMappings.Add(column.ToString(), column.ToString());
s.WriteToServer(csvFileData);
dbConnection.Close();
}
}
}
When reading the CSV, you are not doing anything with the data read, so your DataTable is effectively empty:
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader(csv_file_path);
while ((line = file.ReadLine()) != null)
{
DataRow newRow = csvData.NewRow();
// HERE: YOU ARE MISSING PARSING line INTO newRow
csvData.Rows.Add(newRow);
}
You are forgetting to populate the datarow you are adding, you are createing your datarow correctly DataRow newRow = csvData.NewRow();, but you have to populate with the info you have in line.
while ((line = file.ReadLine()) != null)
{
DataRow newRow = csvData.NewRow();
//DataRow is empty
csvData.Rows.Add(newRow);
}
Try this
while ((line = file.ReadLine()) != null)
{
var id = extractIdFromLine(line); //Code this method
var test= extractTestFromLine(line); //Code this method
csvData.Rows.Add(id, test);
}
Check this oficial post

SQL bulk copy with mapped columns

I am trying to bulk copy from one table to another by mapping the column names as the source and destination may not have same columns always.
Source can have 8 columns and destination can have 10 .. I need to map the columns and bulk copy.
Tried the below code..didn't work..getting Error: The given ColumnName 'moduleid' does not match up with any column in data source.
Source: existingtablecolumnsPresent has [collection time],[logtime],[moduleid],[node],[reason],[time],[timestamp],[usecaseid]
Destination: dataTable.Columns has [Node],[Time],[Reason],[Moduleid],[Usecaseid]
Please advise
public static void BatchBulkCopy(DataTable dataTable, string DestinationTbl, List<string> columnMapping,string filename)
{
var program = new Program();
// Get the DataTable
DataTable dtInsertRows = dataTable;
using (SqlBulkCopy sbc = new SqlBulkCopy(program.connectionStr.ToString()))
{
try {
sbc.DestinationTableName = DestinationTbl.ToLower();
string sourceTableQuery = "Select top 1 * from " + "[" + dataTable.TableName + "]";
DataTable dtSource = SqlHelper.ExecuteDataset(program.connectionStr.ToString(), CommandType.Text, sourceTableQuery).Tables[0];
for (int i = 0; i < dataTable.Columns.Count; i++)
{ //check if destination Column Exists in Source table
if (dtSource.Columns.Cast<DataColumn>().Select(a => "[" + a.ColumnName.ToLower() + "]").Contains(dataTable.Columns[i].ToString().ToLower()))//contain method is not case sensitive
{
List<string> existingtablecolumnsPresent = dtSource.Columns.Cast<DataColumn>().Select(a => "[" + a.ColumnName.ToLower() + "]").Distinct().OrderBy(t => t).ToList();
int sourceColumnIndex = existingtablecolumnsPresent.IndexOf(dataTable.Columns[i].ToString().ToLower());//Once column matched get its index
sbc.ColumnMappings.Add(dtSource.Columns[sourceColumnIndex].ToString(), dtSource.Columns[sourceColumnIndex].ToString());//give coluns name of source table rather then destination table so that it would avoid case sensitivity
}
}
sbc.WriteToServer(dtInsertRows);
sbc.Close();
}
catch (Exception ex)
{
Log.WriteLog("BatchBulkCopy" + " - " + filename, dataTable.TableName, ex.Message.ToString());
// To move a file or folder to a new location:
//if (File.Exists(program.sourceFile + filename))
// System.IO.File.Move(program.sourceFile + filename, program.failedfiles + filename);
}
As requested (create a DataTable with the columns you want to insert in them- leave the others out. Make sure any columns you leave out are marked in the table for NULL or have a DEFAULT VALUE constraint (I can't show you how to do that unless you show me your table);
//This first method is psuedoCode to explain how to create your datatable. You need to do it in the way that makes sense for you.
public DataTable createDataTable(){
List<string> excludedColumns = new List<string>();
excludedColumns.Add("FieldToExclude");
//...
DataTable dt = new DataTable();
foreach(string col in getColumns(myTable)){
if(!excludedColumns.Contains(name)){
DataColumn dC = new DataColumn(name,type);
DataTable.Add(dC);
}
return dt;
}
public List<string> getColumns(string tableName)
{
List<string> ret = new List<string>();
using (SqlConnection conn = getConn())
{
conn.Open();
using (SqlCommand com = conn.CreateCommand())
{
com.CommandText = "select column_Name from information_schema.COLUMNS where table_name = #tab";
com.Parameters.AddWithValue("#tab", tableName);
SqlDataReader read = com.ExecuteReader();
While(read.Read()){
ret.Add(Convert.ToString(read[0]);
}
conn.Close();
}
return ret;
}
//Now, you have a DataTable that has all the columns you want to insert. Map them yourself in code by adding to the appropriate column in your datatable.
public bool isCopyInProgess = false;//not necessary - just part of my code
public void saveDataTable(string tableName, DataTable table)
{
using (SqlConnection conn = getConn())
{
conn.Open();
using (var bulkCopy = new SqlBulkCopy(conn))//, SqlBulkCopyOptions.KeepIdentity))//un-comment if you want to use your own identity column
{
// my DataTable column names match my SQL Column names, so I simply made this loop. However if your column names don't match, just pass in which datatable name matches the SQL column name in Column Mappings
foreach (DataColumn col in table.Columns)
{
//Console.WriteLine("mapping " + col.ColumnName+" ("+does_Column_Exist(col.ColumnName,"Item").ToString()+")");
bulkCopy.ColumnMappings.Add(col.ColumnName, "["+col.ColumnName+"]");
// Console.WriteLine("ok\n");
}
bulkCopy.BulkCopyTimeout = 8000;
bulkCopy.DestinationTableName = tableName;
bulkCopy.BatchSize = 10000;
bulkCopy.EnableStreaming = true;
//bulkCopy.SqlRowsCopied += BulkCopy_SqlRowsCopied;
//bulkCopy.NotifyAfter = 10000;
isCopyInProgess = true;
bulkCopy.WriteToServer(table);
}
conn.Close();
}
}
Also, use this as your bolumn checker:
public bool does_Column_Exist(string colName,string tableName)
{
bool ret = false;
using (SqlConnection conn = getConn())
{
conn.Open();
using (SqlCommand com = conn.CreateCommand())
{
com.CommandText = "select count(*) from information_schema.COLUMNS where column_name = #col and table_name = #tab";
com.Parameters.AddWithValue("#tab", tableName);
com.Parameters.AddWithValue("#col", colName);
ret = Convert.ToInt32(com.ExecuteScalar()) == 0 ? false : true;
}
conn.Close();
}
return ret;
}
Is there a specific reason you need C# for this? It seems like the path of least resistance would be to use SQL to do the job.
INSERT INTO table2
(column_name(s))
SELECT column_name(s)
FROM table1;

Categories

Resources