I dont know how to do this query in c#.
There are two databases and each one has a table required for this query. I need to take the data from one database table and update the other database table with the corresponding payrollID.
I have two tables in seperate databases, Employee which is in techData database and strStaff in QLS database. In the employee table I have StaffID but need to pull the PayrollID from strStaff.
Insert payrollID into Employee where staffID from strStaff = staffID from Employee
However I need to get the staffID and PayrollID from strStaff before I can do the insert query.
This is what I have got so far but it wont work.
cn.ConnectionString = ConfigurationManager.ConnectionStrings["PayrollPlusConnectionString"].ConnectionString;
cmd.Connection = cn;
cmd.CommandText = "Select StaffId, PayrollID From [strStaff] Where (StaffID = #StaffID)";
cmd.Parameters.AddWithValue("#StaffID", staffID);
//Open the connection to the database
cn.Open();
// Execute the sql.
dr = cmd.ExecuteReader();
// Read all of the rows generated by the command (in this case only one row).
For each (dr.Read()) {
cmd.CommandText = "Insert into Employee, where StaffID = #StaffID";
}
// Close your connection to the DB.
dr.Close();
cn.Close();
Assuminig, you want to add data to existing table, you have to use UPDATE + SELECT statement (as i mentioned in a comment to the question). It might look like:
UPDATE emp SET payrollID = sta.peyrollID
FROM Emplyoee AS emp INNER JOIN strStaff AS sta ON emp.staffID = sta.staffID
I have added some clarity to your question: the essential part is that you want to create a C# procedure to accomplish your task (not using SQL Server Management Studio, SSIS, bulk insert, etc). Pertinent to this, there will be 2 different connection objects, and 2 different SQL statements to execute on those connections.
The first task would be retrieving data from the first DB (for certainty let's call it source DB/Table) using SELECT SQL statement, and storing it in some temporary data structure, either per row (as in your code), or the entire table using .NET DataTable object, which will give substantial performance boost. For this purpose, you should use the first connection object to source DB/Table (btw, you can close that connection as soon as you get the data).
The second task would be inserting the data into second DB (target DB/Table), though from your business logic it's a bit unclear how to handle possible data conflicts if records with identical ID already exist in the target DB/Table (some clarity needed). To complete this operation you should use the second connection object and second SQL query.
The sample code snippet to perform the first task, which allows retrieving entire data into .NET/C# DataTable object in a single pass is shown below:
private static DataTable SqlReadDB(string ConnString, string SQL)
{
DataTable _dt;
try
{
using (SqlConnection _connSql = new SqlConnection(ConnString))
{
using (SqlCommand _commandl = new SqlCommand(SQL, _connSql))
{
_commandSql.CommandType = CommandType.Text;
_connSql.Open();
using (SqlCeDataReader _dataReaderSql = _commandSql.ExecuteReader(CommandBehavior.CloseConnection))
{
_dt = new DataTable();
_dt.Load(_dataReaderSqlCe);
_dataReaderSql.Close();
}
}
_connSqlCe.Close();
return _dt;
}
}
catch { return null; }
}
The second part (adding data to target DB/Table) you should code based on the clarified business logic (i.e. data conflicts resolution: do you want to update existing record or skip, etc). Just iterate through the data rows in DataTable object and perform either INSERT or UPDATE SQL operations.
Hope this may help. Kind regards,
Related
Currently, I’ve been working to translate a whole table and put it into another table with same schema.
Given:
Since the table data rows are more than a thousand rows, it is quite hard to translate all of that in one transaction
I also need to know its datatypes since not all of the columns are translatable.
Plan:
My initial plan is to get the users by batch(e.g. top 10 first) and put it into a “datatable”. Reason is because datatable has a column list which holds the columns datatype. This plan I think is JUST OK.
Drawback:
Putting it into a datatable, I know, would be slow. I wouldnt be able to hide it even if batch it. Just a little bit mitigate it.
On the otherhand, if I put the data into a list, instead of datatable, transaction would be faster. But this will result to another sqlcommand call to get the data type schema of the table.
Question:
Is there a way I could the best of both worlds? Faster and a one call, data value and datatype together. Note, In this case, aside from the row data, I just need the data type of the column.
One technique might be to use BulkCopy. Simply read the schema off the first table. Create the target table, define column mappings and do the bulk copy. I have seen this rip through hundreds of thousands of records in seconds.
string connectionString = GetConnectionString();
// Open a sourceConnection to the AdventureWorks database.
using (SqlConnection sourceConnection =
new SqlConnection(connectionString))
{
sourceConnection.Open();
// Perform initial schema read and create target table
// Get data from the source table as a SqlDataReader.
SqlCommand commandSourceData = new SqlCommand(
"SELECT ProductID, Name, " +
"ProductNumber " +
"FROM Production.Product;", sourceConnection);
SqlDataReader reader =
commandSourceData.ExecuteReader();
// Open the destination connection.
using (SqlConnection destinationConnection =
new SqlConnection(connectionString))
{
destinationConnection.Open();
// Set up the bulk copy object.
using (SqlBulkCopy bulkCopy =
new SqlBulkCopy(destinationConnection))
{
bulkCopy.DestinationTableName =
"dbo.BulkCopyDemoMatchingColumns";
bulkCopy.ColumnMappings.Add("SourceColumn1", "TargetColumn1");
bulkCopy.ColumnMappings.Add("SourceColumn2", "TargetColumn2");
try
{
// Write from the source to the destination.
bulkCopy.WriteToServer(reader);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
// Close the SqlDataReader. The SqlBulkCopy
// object is automatically closed at the end
// of the using block.
reader.Close();
}
}
}
}
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql/multiple-bulk-copy-operations
SQL Server provides output for inserted and updated record with the 'inserted' keyword.
I have a table representing a processing queue. I use the following query to lock a record and get the ID of the locked record:
UPDATE TOP (1) GlobalTrans
SET LockDateTime = GETUTCDATE()
OUTPUT inserted.ID
WHERE LockDateTime IS NULL
This will output a column named ID with all the updated record IDs (a single ID in my case). How can I translate this into EF in C# to execute the update and get the ID back?
Entity Framework has no way of doing that.
You could do it the ORM way, by selecting all the records, setting their LockDateTime and writing them back. That probably is not safe for what you want to do because by default it's not one single transaction.
You can span your own transactions and use RepeatableRead as isolation level. That should work. Depending on what your database does in the background, it might be overkill though.
You could write the SQL by hand. That defeats the purpose of entity framework, but it should be just as safe as it was before as far as the locking mechanism is concerned.
You could also put it into a stored procedure and call that. It's a little bit better than the above version because at least somebody will compile it and check that the table and column names are correct.
Simple Example #1 to get a data table:
I did this directly against the connection:
Changed the command.ExecuteNonQuery() to command.ExecuteReader()
var connection = DbContext().Database.Connection as SqlConnection;
using (var command = connection.CreateCommand())
{
command.CommandText = sql;
command.CommandTimeout = 120;
command.Parameters.Add(param);
using (var reader = command.ExecuteReader())
{
var resultTable = new DataTable();
resultTable.Load(reader);
return resultTable;
}
}
FYI, If you don't have an OUTPUT clause in your SQL, it will return an empty data table.
Example #2 to return entities:
This is a bit more complicated but does work.
using a SQL statement with a OUTPUT inserted.*
var className = typeof(T).Name;
var container = ObjContext().MetadataWorkspace.GetEntityContainer(UnitOfWork.ObjContext().DefaultContainerName, DataSpace.CSpace);
var setName = (from meta in container.BaseEntitySets where meta.ElementType.Name == className select meta.Name).First();
var results = ObjContext().ExecuteStoreQuery<T>(sql, setName, trackingEnabled ? MergeOption.AppendOnly : MergeOption.NoTracking).ToList();
T being the entity being worked on
I am new to C# and have been using PHP for Years.
The problem I am facing is that I want to create a method/function that will take an "sql query" as parameter and return whatever data is retrieved so that it can be used using the key/index/column_name.
What I have achieved
I have achieved is that I am able to access the data through index within the same function.
but I wont know the no. of columns that will return so I am unable to store it in an array.
Code
string ConnectionString = ConfigurationManager.ConnectionStrings["sqlcon"].ConnectionString;
MySqlConnection db;
db = new MySql.Data.MySqlClient.MySqlConnection(ConnectionString);
try
{
db.Open();
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = db;
cmd.CommandText = sql;
MySqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Console.WriteLine(rdr['areaId'].toString());
}
db.Close();
return true;
}
The problems
1. I do not know the number of Columns.
2. I cannot access the index or Column name.
I want to create an associative array of data with the column name as index and data as its data
EDIT
I am trying to build an application on C# using WPF with MySQL Database.
My first suggestion would be to use one of the micro ORMs like Dapper.net
This can be fetched via nuget. If you wish to retrieve an unknown array of data from a table, or number of tables, you could fetch it into an ExpandoObject and then enumerate over that. An example of looping over an ExpandoObject can be found here.
public Foo FetchSomeData(string query)
{
using (var cn = Connection)
{
var result = cn.Query(query);
//do something with result, and return it
return new Foo(result);
}
}
I'd have concerns about passing raw sql into the DB without at least checking it or using parameters as it could be a major security risk, especially if you allow users to generate the query and you don't vet it first.
i would like to know what is the standard/best way of doing the following:
i have a form web app in asp.net and using C#
the user will enter data into the form and click INSERT and it will insert data into 4 different tables.
the fields are:
primarykey, animal, street, country
the form allows for multiple animals, multiple streets and multiple countries per primarykey. so when i have data like this:
[1],[rhino,cat,dog],[luigi st, paul st], [russia,israel]
i need it inserted into tables like this:
table1:
1,rhino
1,cat
1,dog
table2:
1,luigi st
1, paul st
table3:
1,russia
1,israel
questions
I'm at a total loss on how to do this. if i just had one table and one set of data per primary key i would just use the InsertQuery and do it this way, but since it is multiple tables i don't know how to do this??
what control(s) should i use in order to allow user to input multiple values? currently i am just using textboxes and thinking of separating the entries by semi colons, but that's probably not the right way.
I wanted to recommend that you take advantage of the new multirow insert statement in SQL 2008 so that you can just pass a sql statement like this:
INSERT INTO table1(id,animal_name) values (1,cat),(1,dog),(1,horse)...
To your SqlCommand but I don't know how to build a statement like that w/o risking being victim of a SQL Injection Attack.
Another alternative is to define data table types in your sql database:
And then construct a DataTable in C# that matches your datatable type definition:
DataTable t = new DataTable();
t.Columns.Add("id");
t.Columns.Add("animal_name");
foreach(var element in your animals_list)
{
DaraRow r = t.NewRow();
r.ItemArray = new object[] { element.id, element.animal_name };
t.Rows.Add(r);
}
// Assumes connection is an open SqlConnection.
using (connection)
{
// Define the INSERT-SELECT statement.
string sqlInsert = "INSERT INTO dbo.table1 (id, animal_name) SELECT nc.id, nc.animal_name FROM #animals AS nc;"
// Configure the command and parameter.
SqlCommand insertCommand = new SqlCommand(sqlInsert, connection);
SqlParameter tvpParam = insertCommand.Parameters.AddWithValue("#animals", t);
tvpParam.SqlDbType = SqlDbType.Structured;
tvpParam.TypeName = "dbo.AnimalTable";
// Execute the command.
insertCommand.ExecuteNonQuery();
}
Read more here.
Or if you are familiar with Stored Procedures, same as previous suggestion but having the stored procedure receive the DataTable t as parameter.
If none of the above work for you, create a SqlTranscation from the Connection object and iterate through each row of each data set inserting the record in the appropriate table and finally commit the transaction. Example here.
Use Checkboxes on the front end. Have a service/repository to save the user data. Something like the following:
public void UpdateUserAnimals(Guid userId, string[] animals)
{
using (SqlConnection conn = new SqlConnection("connectionstring..."))
{
using (SqlCommand cmd = new SqlCommand("Insert Into UserAnimals(UserId, Animals) values (#UserId, #Animal)"))
{
conn.Open();
cmd.Parameters.AddWithValue("#UserId", userId);
foreach(string animal in animals)
{
cmd.Parameters.AddWithValue("#Animal", animal);
cmd.ExecuteNonQuery();
}
}
}
}
There are more complex solutions, but this is a simple one.
I want move data from database to another database.
I write 2 function. function 1 : I fill table from database1 into a datatable and named this DT
in function 2 I fill table in database2 with Dt and named its dtnull
I update dtnull in database 2
function 2:
{
SqlDataAdapter sda = new SqlDataAdapter();
sda.SelectCommand = new SqlCommand();
sda.SelectCommand.Connection = objconn;
sda.SelectCommand.CommandText = "Select * from " + TableName + "";
DataTable dtnull = new DataTable();
sda.Fill(dtnull);
SqlCommandBuilder Builder = new SqlCommandBuilder();
Builder.DataAdapter = sda;
Builder.ConflictOption = ConflictOption.OverwriteChanges;
string insertCommandSql = Builder.GetInsertCommand(true).CommandText;
foreach (DataRow Row in Dt.Rows)
{
dtnull.ImportRow(Row);
}
sda.Fill(dtnull);
sda.Update(dtnull);
}
If you need to copy SQL database then just back it up and restore. Alternatively use DTS services.
If it's just a few tables I think you can
right click on the table you want in the SQL Management studio
generate a create script to your clipboard
execute it
Go back to your original table and select all the rows
copy them
go to your new table and paste
No need to make this harder than it is.
You don't really need to use an update for this. You might try out this solution, it might be the easiest way for you do this.
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.aspx
If you would like a LINQ solution, I could provide you with one.
There is a lot that is left unexplained. For example, do the source table and target table have the same column structure?
Can you see both database from the same SqlConnection (i.e. are they on the same machine)? If so, you can do it all in one SQL statement. Assuming you want to copy the data from table T1 in databse DB1 to table T2 in database DB2, you would write
insert DB2.dbo.T2 select * from DB1.dbo.T1
Excecute using ExecuteNonQuery.
If the databases require different SqlConnections, I would read the data from the source using a SqlDataReader and update the target row by row. I think it would be faster than using a SqlDataAdapter and DataTable since they require more structure and memory. The Update command writes the data row by row in any event.