Database Handling in C# - c#

I'm having some problems on my application since I'm not very experienced on the database handling, so far I've created my database with a table, and what I wanted to do is to show a specific data from the table as a variable.
My application has to do with chemical elements, therefore the table "elements" has all of them. I was thinking of making a random element generator using a random number to get any of the elements in the table with a query or something.
Random ra = new Random();
int random_anumber = ra.Next(1, 9);
SqlConnection con = new SqlConnection(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\Francisco\Documents\FormData.mdf;Integrated Security=True;Connect Timeout=30");
SqlDataAdapter adp = new SqlDataAdapter("SELECT * FROM elements", con);
I was thinking on putting the random_anumber instead of the "*" but it's still not showing a single element. Since I don't know how to show them of convert the data into a variable.

The "*" in the SQL statement is a field name selector and not a filter. So changing the * to something else won't limit your query to a single element. You have to add a where clause for that.
To solve this you can either use the SqlDataAdapter onto a DataSet and use the DataTable within the DataSet to grab a random row by using the random number as the index or run a simple query. I recommend running a query if all you need to do with this data is display a random element.
--- Update ---
MS SQL Server Statement:
SELECT TOP 1 * FROM table
ORDER BY NEWID()
MySQL Statement:
SELECT * FROM table
ORDER BY RAND()
LIMIT 1
The * is a wildcard character that select all columns/fields of the table. You can change the to a comma delimited list of columns/fields you want to retrieve from the database.

Hope that the Table elements having a unique Key Field(let it be element_id) then you can access the Random Element by Specifying the ID in the Where Clause, Then your Query will be like The following:
string querySQL="SELECT * FROM elements Where element_id=#id";
SqlCommand cmd = new SqlCommand(querySQL, con) // con is the Connection
cmd.Parameters.AddWithValue("#id", random_anumber);
// Get data using Adapter

This is how I do it everyday:
Note: Here you can see that I use Sqlite in my example. You can use SQL by removing the Lites and using the right classes in SQL respectively.
string ConnectionString = "data source={0}; initial catalog={1}; integrated security=true; application name= <Your App Name>" providerName="System.Data.SqlClient";
string DatabasePath = "<Your Path to your database>";
string commandstring = "SELECT * FROM elements";
using (SQLiteCommand MyCommand = new SQLiteCommand(commandstring, Connection))
{
using (SQLiteDataReader MyReader = MyCommand.ExecuteReader())
{
while (MyReader.Read())
{
// Here is your result:
// You can do anything that you want with it.
// The 0 shows the first column. If your result returns more than one column, //you can use other numbers like 1,2..n to get other columns out of your data //reader.
MyReader.GetString(0);
}
}
}`

Related

Insert foreign key into table with SQL query using C#

I have a database with 3 tables Identification, Identification_group and Group.
The Identification_group table has 2 foreign key columns, Identificaiton_id and Group_id.
In my form you can select the Group Number and it returns the right Group_id to the Identification_group table.
Is it possible to write a SQL query that uses the last Identification_id and the Group_id (from the selection field in my form) and writes this to the Identification_group table?
string sqlquery1 = "Insert into [dbo].[identification_group] (fk_group_id,fk_identification_id values (#fk_group_id,#fk_identification_id;";
SqlCommand schreiben = new SqlCommand(sqlquery1, myConnection);
myConnection.Open();
schreiben.Parameters.AddWithValue("#fk_identification_id", intidentification_id);
schreiben.Parameters.AddWithValue("#fk_group_id", Wil_Jls_idComboBox.SelectedValue);
schreiben.CommandText = sqlquery;
schreiben.ExecuteNonQuery();
myConnection.Close();
Sorry for the bad formatting, first time posting here.
Thank you in advance
Please try the below:
You have an issue with your SQL statement whereby you did not close the brackets. Also, you only need the # symbol in the SQL statement, and not in the C# code.
// Create the query
string query = "Insert into [identification_group] (fk_group_id, fk_identification_id) values (#fk_group_id, #fk_identification_id)";
// Create the SQL command
SqlCommand schreiben = new SqlCommand(query, myConnection);
// Open the SQL connection
myConnection.Open();
// Bind the parameters
schreiben.Parameters.AddWithValue("fk_identification_id", intidentification_id);
schreiben.Parameters.AddWithValue("fk_group_id", Wil_Jls_idComboBox.SelectedValue);
// Bind the command
schreiben.CommandText = query;
// Execute the command
schreiben.ExecuteNonQuery();
// Close the connection
myConnection.Close();

Copying data from one database to another - Out of Memory Exception

I have a task where i want to copy all data from one database to another database & skipping 2 tables. There are more than 200 tables.
I have table structure ready for my 2nd databas.
So as a solution i created a page & on a button click i have below code :-
DataSet ds = new DataSet();
string connectionString = "Data Source=COMP112\\MSSQLSERVER2014;Initial Catalog=HCMBL;Integrated Security=True;Persist Security Info=True";
SqlConnection con = new SqlConnection(connectionString);
//render table name from database
string sqlTable = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' and TABLE_Schema='" + Session["SchemaName"].ToString() + "' and TABLE_NAME!='ENTRY' and TABLE_NAME!='OT' and TABLE_NAME!='BL_ENTRY' and TABLE_NAME!='BL_OT'";
con.Open();
SqlDataAdapter da = new SqlDataAdapter();
SqlCommand cmd = new SqlCommand(sqlTable, con);
cmd.CommandType = CommandType.Text;
da.SelectCommand = cmd;
da.Fill(ds);
con.Close();
//render connection string from WebConfig file
string strcon = ConfigurationManager.ConnectionStrings["SPSchema"].ConnectionString;
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
if (!(ds.Tables[0].Rows[i]["TABLE_NAME"].ToString().Contains("Asp")))
{
string deleteQuery = "Truncate table " + Session["SchemaName"].ToString() + "." + ds.Tables[0].Rows[i]["TABLE_NAME"];
con.Open();
SqlCommand cmdDelete = new SqlCommand(deleteQuery, con);
cmdDelete.ExecuteNonQuery();
con.Close();
DataSet dataSet = new DataSet();
SqlConnection conn = new SqlConnection(strcon);
conn.Open();
string selectData = "select * from " + Session["SchemaName"].ToString() + "." + ds.Tables[0].Rows[i]["TABLE_NAME"];
SqlCommand command = new SqlCommand(selectData, conn);
DataTable dataTable = new DataTable();
SqlDataAdapter dataAdapter = new SqlDataAdapter(selectData, conn);
dataAdapter.FillSchema(dataSet, SchemaType.Mapped);
dataAdapter.Fill(dataSet);
dataTable = dataSet.Tables[0];
conn.Close();
if (dataSet.Tables[0].Rows.Count > 0)
{
//Connect to second Database and Insert row/rows.
SqlConnection conn2 = new SqlConnection(connectionString);
conn2.Open();
SqlBulkCopy bulkCopy = new SqlBulkCopy(conn2);
bulkCopy.DestinationTableName = Session["SchemaName"].ToString() + "." + ds.Tables[0].Rows[i]["TABLE_NAME"].ToString();
bulkCopy.WriteToServer(dataTable);
conn2.Close();
}
}
}
As i run the above code after inserting data in less than 10 tables, it gives out of memory exception & program crashes.
How to handle this? I tried increasing the memory capacity of SQL Server but still same error.
Is there any other way to achieve the task?
What you are doing is very far from the best solution. You are using an ASP.NET MVC process to get all data of your entire database into memory, and then outputting it to another database. If your database is anything more than small and trivial, that will most definitely fill your process's alotted memory.
This type of task should never be done through the memory of a process, but rather using some form of Backup/Restore pattern.
You should look into SSIS projects and create an extract, transfer, and load (ETL) solution, which can be triggered from your ASP.NET MVC solution asynchronously.
An SSIS solution can be triggered from C# code in this way:
var app = new Application();
var package = app.LoadPackage("compiled-package.dtsx", null);
var results = package.Execute();
See this question for a little more information (not specifically about duplicating databases, but has information about triggering SSIS packages from code): How to execute an SSIS package from .NET?
Alternatively
You also have the option of running a query against both databases at once, however this requires some additional plumbing to be done. The user account of your ASP.NET MVC solution needs to have access to both databases. If your databases are hosted on different servers, you also need to link one server to the other: Create linked servers
To perform an insert directly from the output of a select, consider this:
string source = "NAME_OF_SOURCE_DATABASE";
string target = "NAME_OF_TARGET_DATABASE";
string schema = Session["SchemaName"].ToString();
string table = ds.Tables[0].Rows[i]["TABLE_NAME"];
// Uncomment this if you need to deal with autoincrement columns
/*string idInsQuery = $"SET IDENTITY_INSERT {target}.{schema}.{table} ON";
var idInsCommand = new SqlCommand(idInsQuery, conn);
idInsCommand.ExecuteNonQuery();*/
string insQuery = $"INSERT INTO {target}.{schema}.{table} SELECT * FROM {source}.{schema}.{table}";
var insCommand = new SqlCommand(insQuery, conn);
insCommand.ExecuteNonQuery();
// Uncomment this if you need to deal with autoincrement columns
/*string idInsQuery2 = $"SET IDENTITY_INSERT {target}.{schema}.{table} OFF";
var idInsCommand2 = new SqlCommand(idInsQuery2, conn);
idInsCommand2.ExecuteNonQuery();*/
This will only work if the table structures are identical. There might be problems with autoincrement ids or columns with default values, too.
This will copy data from a table in database 1 to a table in database 2
Insert into db2.dbo.table2 (col1,col2)
Select col1,col2 from db1.dbo.table1
Run this sql statement and the data will be copied without a round trip to your app.
Let me know if you find my approach is useful.
First of all, why you want to write down one whole application to do this job while SQL Server have inherited property to do it.
My approach would be configure an Linked Server and configure it which tables you want to copy and which one not.
https://learn.microsoft.com/en-us/sql/relational-databases/linked-servers/create-linked-servers-sql-server-database-engine
Secondly, You can just write down simple stored procedure and schedule that in your sql server to push into another server database as per your schedule. In this way you can control it in N number of ways. I mean about controlling any dependencies(Table level or Business level).
To do this in t-sql, you can use the following system stored procedures to schedule a daily job. This example schedules daily at 1:00 AM. See Microsoft help for details on syntax of the individual stored procedures and valid range of parameters.
DECLARE #job_name NVARCHAR(128), #description NVARCHAR(512), #owner_login_name NVARCHAR(128), #database_name NVARCHAR(128);
SET #job_name = N'Some Title';
SET #description = N'Periodically do something';
SET #owner_login_name = N'login';
SET #database_name = N'Database_Name';
-- Delete job if it already exists:
IF EXISTS(SELECT job_id FROM msdb.dbo.sysjobs WHERE (name = #job_name))
BEGIN
EXEC msdb.dbo.sp_delete_job
#job_name = #job_name;
END
-- Create the job:
EXEC msdb.dbo.sp_add_job
#job_name=#job_name,
#enabled=1,
#notify_level_eventlog=0,
#notify_level_email=2,
#notify_level_netsend=2,
#notify_level_page=2,
#delete_level=0,
#description=#description,
#category_name=N'[Uncategorized (Local)]',
#owner_login_name=#owner_login_name;
-- Add server:
EXEC msdb.dbo.sp_add_jobserver #job_name=#job_name;
-- Add step to execute SQL:
EXEC msdb.dbo.sp_add_jobstep
#job_name=#job_name,
#step_name=N'Execute SQL',
#step_id=1,
#cmdexec_success_code=0,
#on_success_action=1,
#on_fail_action=2,
#retry_attempts=0,
#retry_interval=0,
#os_run_priority=0,
#subsystem=N'TSQL',
#command=N'EXEC my_stored_procedure; -- OR ANY SQL STATEMENT',
#database_name=#database_name,
#flags=0;
-- Update job to set start step:
EXEC msdb.dbo.sp_update_job
#job_name=#job_name,
#enabled=1,
#start_step_id=1,
#notify_level_eventlog=0,
#notify_level_email=2,
#notify_level_netsend=2,
#notify_level_page=2,
#delete_level=0,
#description=#description,
#category_name=N'[Uncategorized (Local)]',
#owner_login_name=#owner_login_name,
#notify_email_operator_name=N'',
#notify_netsend_operator_name=N'',
#notify_page_operator_name=N'';
-- Schedule job:
EXEC msdb.dbo.sp_add_jobschedule
#job_name=#job_name,
#name=N'Daily',
#enabled=1,
#freq_type=4,
#freq_interval=1,
#freq_subday_type=1,
#freq_subday_interval=0,
#freq_relative_interval=0,
#freq_recurrence_factor=1,
#active_start_date=20170101, --YYYYMMDD
#active_end_date=99991231, --YYYYMMDD (this represents no end date)
#active_start_time=010000, --HHMMSS
#active_end_time=235959; --HHMMSS
Let me know in case you need more details on this.
Thanks,
Ayan

Dynamically print number of rows updated

The company that I work for has large databases, millions of records in a single table. I have written a C# program that migrates tables between remote servers.
I first create all the tables using SMO without copying data and then the data insertion is done after all the tables have been created.
During the record insertion since there are so many records the console window remains blank until all the rows have been inserted. Due to the sheer volumes of data this takes a long time.
What I want now is a way to print n rows updated like in MSSQL import export data wizard.
The insert part is just a simple insert into select * query.
It sounds like you might be using SqlCommands, if so here is a sample
using (SqlConnection connection = new SqlConnection(Connection.ConnectionString) )
{
using(SqlCommand command = new SqlCommand("insert into OldCustomers select * from customers",connection))
{
connection.Open();
var numRows = command.ExecuteNonQuery();
Console.WriteLine("Affected Rows: {0}",numRows);
}
}
You definitely need to look on OUTPUT clause. There are useful examples on MSDN.
using (SqlConnection conn = new SqlConnection(connectionStr) )
{
var sqlCmd = "
CREATE TABLE #tmp (
InsertedId BIGINT
);
INSERT INTO TestTable
OUTPUT Inserted.Id INTO #tmp
VALUES ....
SELECT COUNT(*) FROM #tmp";
using(SqlCommand cmd = new SqlCommand(sqlCmd,conn))
{
conn .Open();
var numRows = command.ExecuteNonQuery();
Console.WriteLine("Affected Rows: {0}",numRows);
}
}
Also I suggest to use stored procedure for such purposes.

store values from database into combobox

I'm trying to write a program using SQL and OleDB and I get an error while the Program is running.
the program first counts the number of rows in the table(access table which called 'tblCodons')
and storage the number as integer in j.
then the program stores all the rows (from a specific column which called 'codonsFullName') in comboBox1.
the code is below
I get this ERROR:System.Data.OleDb.OleDbException (0x80040E14): Invalid SQL statement;Required values​​' DELETE ',' INSERT ',' PROCEDURE ',' SELECT 'or' UPDATE
the code:
int j=0;
OleDbConnection conn1 = new OleDbConnection(connectionString);
conn1.Open();
string sqlCount= "SET #j= SELECT COUNT(tblCodons.codonsFullName) FROM tblCodons";
OleDbCommand counter = new OleDbCommand(sqlCount, conn1);
counter.ExecuteNonQuery();
conn1.Close();
OleDbConnection conn2 = new OleDbConnection(connectionString);
conn2.Open();
string sqlFill = "SELECT tblCodons.codonsFullName FROM tblCodons";
OleDbCommand fill = new OleDbCommand(sqlFill, conn2);
fill.ExecuteNonQuery();
OleDbDataReader dataReader = fill.ExecuteReader();
dataReader.Read();
for (int i = 0; i < j; i++)
{
comboBox1.Items.Add(dataReader.GetString(i));
}
You seem to need the count only for the loop. Also I do not understand why you are executing fill.ExecuteNonQuery() before executing is as a reader.
Also setting #j (if it did work) in a sql query has no scope to a local variable j in the code you are trying to set.
You should only need the following code (apologies for any syntax errors)
OleDbConnection conn2 = new OleDbConnection(connectionString);
conn2.Open();
string sqlFill = "SELECT tblCodons.codonsFullName FROM tblCodons";
OleDbCommand fill = new OleDbCommand(sqlFill, conn2);
OleDbDataReader dataReader = fill.ExecuteReader();
int j = 0;
if (dataReader.HasRows)
{
while(dataReader.Read())
{
comboBox1.Items.Add(dataReader.GetString(0));
j++;
}
}
Hope that helps
Leaving this answer here as an explanation for fixing your code as it currently exists, but also want to point out that I recommend going with Kamal's solution; it only queries the database once.
This line is probably your error:
string sqlCount= "SET #j= SELECT COUNT(tblCodons.codonsFullName) FROM tblCodons";
change to
string sqlCount= "SELECT COUNT(tblCodons.codonsFullName) FROM tblCodons";
You'll want to change your code to obtain the result of that first query like this:
j = counter.ExecuteScalar();
First, as Kamal Mentioned you can't directly set a variable from a sql query as you are trying to do and as the exception states only "SELECT" , "INSERT","UPDATE" and "DELETE" commands can be use in a query.
Second, I don't know why you need to get the record counts before getting the actual data but if it's really necessary you can write your query like this :
var query="SELECT COUNT(tblCodons.codonsFullName) FROM tblCodons;SELECT tblCodons.codonsFullName FROM tblCodons;";
Then you can execute both query using a single DataReader. When you execute DataReader.ExequteQuery() it will contain two results.the first one has access to the count and the second one has access to actual data.
Here's an example

Problem while printing a maximum value obtained from the database

I am trying to find the MAX number from a database field,The query below returns me the maximum value if i run it in SQL Enterprise Manager but i am not able to print the value in numbwe. Please help me to print the MAX value obtained from the database.
SqlConnection MyConnection = new SqlConnection("Data Source=localhost;Initial Catalog=hcgoa;User Id=sa;Password=;");
SqlCommand MyCmd = new SqlCommand("SELECT MAX([no]) AS Expr1 FROM jmain", MyConnection);
MyConnection.Open();
SqlDataReader myReader = MyCmd.ExecuteReader();
if (myReader.Read())
{
string numbwe = myReader["no"].ToString();
Response.Write("Max no. is : " + numbwe);
}
You need to use Expr1 as the key, not no.
That's because you're doing:
SqlCommand MyCmd = new SqlCommand("SELECT MAX([no]) AS Expr1 ...
(note the AS clause) so the column is named Expr1. Hence:
string numbwe = myReader["Expr1"].ToString();
should do it.
Although, in fairness to those who come after you, Expr1 is not a very descriptive identifier. Consider the possibility of changing it to something like MaxNum (both in the select and the key, of course).
You should look at the ExecuteScalar() instead if you are going to return a single value.
MSDN: Use the ExecuteScalar method to
retrieve a single value (for example,
an aggregate value) from a database.
This requires less code than using the
ExecuteReader method, and then
performing the operations that you
need to generate the single value
using the data returned by a
SqlDataReader.
You're trying to print the value of a column that doesn't exist in the query result. Your query returns a column named Expr1, not a column named "no"
Change
string numbwe = myReader["no"].ToString();
to
string numbwe = myReader["Expr1"].ToString();
should be string numbwe = myReader["Expr1"].ToString();
as you are specifying your column name in sql statement Expr1
SELECT MAX([no]) AS Expr1

Categories