I am trying to carry out an 'insert if not exists' statement, i am not receiving any errors and the row does not exist in the db, however it still will not add it. Executing a normal 'insert' works but not when the 'if not exists' is added.
I have also tried including BEGIN & END and it doesnt work.
Where am i going wrong??
string getStudentModuleId = "SELECT ModuleId FROM StudentModuleMarks WHERE Mark < 40";
SqlCommand myCommand = new SqlCommand(getStudentModuleId, MyConnection3);
try
{
moduleid = (int)myCommand.ExecuteScalar();
string addRepeat = "IF NOT EXISTS (SELECT * FROM StudentModules WHERE ModuleId = #moduleid AND SchoolYear = '2018') INSERT INTO StudentModules(StudentDegreeId, ModuleId, Repeat, SchoolYear, EnrolledStatus) VALUES (1,#moduleid,1,'2018','Active')";
SqlCommand command = new SqlCommand(addRepeat, MyConnection3);
command.Parameters.AddWithValue("#moduleid", moduleid);
command.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
It seems you are using sql server, For MySQL, you can follow this technique to insert record if it doesn't exist :
INSERT INTO StudentModules(StudentDegreeId, ModuleId, Repeat, SchoolYear, EnrolledStatus)
select 1,#moduleid, 1, '2018', 'Active' from dual
where NOT EXISTS (SELECT * FROM StudentModules WHERE ModuleId = #moduleid AND SchoolYear = '2018')
Please note that, in MySQL, you don't really need to have a table called dual to exist: it is a special table-name that can be used to select anything from it. And it will output a single record always with a SELECT query like above.
Related
I have a table SupplierMaster in a SQL Server database with a column SUPPLIERNAME.
I want to edit saved supplier name using stored procedure with below query
ALTER PROCEDURE [dbo].[usp_SupplierMasterUpdateDetails]
(
#SUPPLIERNAME NVARCHAR(50)
)
AS
BEGIN
UPDATE [dbo].[SupplierMaster]
SET [SUPPLIERNAME] = #SUPPLIERNAME
WHERE [SUPPLIERNAME] = #SUPPLIERNAME
END
and I run the BELOW code through "UPDATE BUTTON" to update the data.
string connString = ConfigurationManager.ConnectionStrings["dbx"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connString))
{
using (SqlCommand cmd = new SqlCommand("usp_SupplierMasterUpdateDetails", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
// Parameter
cmd.Parameters.AddWithValue("SUPPLIERNAME", AddSupplierTextBox.Text);
// Open Connection
conn.Open();
// ExecuteReader (Select Statement)
// ExecuteScalar (Select Statement)
// ExecuteNonQuery (Insert, Update or Delete)
cmd.ExecuteNonQuery();
MessageBox.Show("SUCCESSFULLY UPDATED", "Successful", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
But its not updating the selected data.
Please advice and assist me to correct the code for proper work.
You have multiple issues there.
First you need to fix your update query just as Thomas Levesque suggested.
a SQL Server table needs a primary key to be able to uniquely identify a record, for updates for example.
The easiest thing you could do is set that primary key to be identity of type int and make it self generating. Your supplier table could look like this :
SupplierID int, Primary Key, identity
SupplierName nvarchar(100)
Now, when you do an update, you would do it like this:
Update SupplierMaster
Set SupplierName = #supplierName
Where SupplierID = #suplierID
Such a SQL statement will return an int value. This return value will tell you how many SQL rows this update statement has changed. If it says 0 then it means that the SQL statement could not find that id you passed through and nothing changed. If it says 1, then the record was found and updated, if you get more than 1 you have an issue with the SQL statement and multiple rows were updated.
In your code check for this return value and that's how you determine if your update statement was successful or not.
When I use:
START TRANSACTION;
INSERT IGNORE INTO users (Name, ...) VALUES ('user1',..) ON DUPLICATE KEY UPDATE lastSeen=NOW();
SELECT LAST_INSERT_ID();
COMMIT;
When i run this query from my sql client I get the last inserted id as expected.
But what if the user already exists?(table uniquness). So no new id is created. But now when I run the same query from my sql client still i get the id as expected.
But! when I run it from my C# code and use mysql.reader to query the result I receive 0. Why is that??
If instead of SELECT LAST_INSERT_ID() I use SELECT id FROM users ORDER BY id DESC LIMIT 1 I get the right id again.
EDIT!
This is not a duplicate of the suggested topic. In that topic the answer says that the auto-incremented is not the primary key, thats not my case! also as I mark it does return the right id when i use the mysql client! The problem occures only when I run it from my c# code!
My C# code:
using (var conn = new MySqlConnection(connString))
{
try
{
conn.Open();
var command = conn.CreateCommand();
command.CommandText = strSQL;
MySqlDataReader reader;
string result = "";
try
{
reader = command.ExecuteReader();
if (reader.Read())
result = reader[0].ToString();
}
catch (Exception ex)
{
throw new MySqlException("SQL Error: " + ex.ToString());
}
reader.Close();
return result;
}
}
I have found a work around, simple CASE clause does the job:
START TRANSACTION;
INSERT IGNORE INTO users (Name, ...) VALUES ('user1',..) ON DUPLICATE KEY UPDATE lastSeen=NOW();
SELECT CASE WHEN LAST_INSERT_ID()=0 THEN (SELECT id FROM users WHERE Name = 'user1') ELSE LAST_INSERT_ID() END;
COMMIT;
Now in case the user exists, we simply query the id, If it doest not exists, the LAST_INSERT_ID() will give us the right id
From what I read there https://stackoverflow.com/a/15057619/4421474
Your code could be transformed to:
using (var conn = new MySqlConnection(connString))
{
conn.Open();
var command = conn.CreateCommand();
command.CommandText = strSQL; <-- just insert part like "START ... INSERT ... COMMIT;"
command.ExecuteNonQuery();
string result = command.LastInsertedId;
return result;
}
Sorry I am not c# expert so some syntax could be broken.
I guess this answer:
Just my 50 cents for this issue, I simply noticed that you won't get a LAST_INSERT_ID greater than 0 if your table has no AUTO_INCREMENT set to an index
that i found here MySQL: LAST_INSERT_ID() returns 0 is the good one.
I am using a trigger in SQL Server that works as required when executing a query in the query window in SQL Server Management Studio. The objective of the trigger is to take the latest value from one table (where an id corresponds to the inserted id) and add this value to the inserted row.
I am also using a DataAdapter in C# to interact with the same database that has the trigger. When I use MyAdapter.update(MyDataTable) to insert new values into the table that the trigger is assigned to, the trigger does not execute.
I have done a lot of googling but nobody else seems to have that problem so I am thinking I am missing something fundamental. I am also new to database interaction with .Net. The data adapter works properly (i.e. inserts and updates as needed) except for not firing the trigger.
Below are some excerpts from my C# code and the trigger.
CREATE TRIGGER getLatestCap
ON TestIDTable
AFTER insert
AS
BEGIN
SET NOCOUNT ON;
DECLARE #BID INT;
DECLARE #Date Date;
SET #BID = (SELECT BattID FROM inserted);
SET #Date = (SELECT Test_Date FROM inserted);
SELECT M_Cap, Cap_Date
INTO #tempTable
FROM CapDataTable
WHERE BattID = #BID;
-- Set the Test_Cap entry in TestIDTable to that capacity.
UPDATE TestIDTable
SET Test_Cap = (SELECT M_Cap
FROM #tempTable
WHERE Cap_Date = (SELECT max(Cap_Date)
FROM #tempTable))
WHERE BattID = #BID AND Test_Date = #Date;
END
GO
private void Setup()
{
try
{
string BattSelect = "SELECT * FROM " + tbl;
dt = new DataTable();
Adpt = new SqlDataAdapter(BattSelect, ConnectionStr);
builder = new SqlCommandBuilder(Adpt);
Adpt.Fill(dt);
}
catch (Exception e)
{
MessageBox.Show("While Connecting to "+tbl+": " + e.ToString());
}
}
private void UpdateDB()
{
try
{
Adpt.InsertCommand = builder.GetInsertCommand();
Adpt.UpdateCommand = builder.GetUpdateCommand();
Adpt.Update(dt);
}
catch (Exception e)
{
MessageBox.Show("While Updating " + tbl + ": " + e.ToString());
}
}
Question summary: the trigger works in SQL Server, but does fire (nor complains) when using a data adapter.
Thanks for your time and help!
Marvin
Following HABO's Tip (below original post) I modified my trigger to work for multiple inserted rows. This has solved my problem. New trigger code below:
CREATE TRIGGER getLatestCap
ON TestIDTable
AFTER insert
AS
BEGIN
SET NOCOUNT ON;
UPDATE TestIDTable
set Test_Cap = M_Cap
FROM
(SELECT C.BattID, Test_Date, M_Cap
FROM
(SELECT t.BattID, t.M_Cap, t.Cap_Date
FROM CapDataTable t
INNER JOIN(
SELECT BattID, max(Cap_Date) as Latest
FROM CapDataTable
GROUP BY BattID
) tm on t.BattID = tm.BattID and t.Cap_Date = tm.Latest)
C INNER JOIN inserted I
on C.BattID = I.BattID) as t1
INNER JOIN TestIDTable as t2
on t1.BattID = t2.BattID AND t1.Test_Date = t2.Test_Date
END
GO
Thanks for your help!
Your firing the trigger after INSERT. With the SQLDataAdapter you're performing an UPDATE. Those are two very different types of transactions.
Try setting your trigger to ON UPDATE. That should do the trick.
I have to insert a value and before inserting i have to check either a value exists or not. how can i achieve it in a simple way?
public int AddCountry(string cntName)
{
try
{
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}
SqlCommand sqlCmd = new SqlCommand("INSERT INTO Country VALUES(" +
cntName + ")", conn);
sqlCmd.Parameters.AddWithValue("#Country_Name", cntName);
}
catch (Exception)
{
throw;
}
}
ignoring some of the other issues in your code, you should look at IF NOT EXISTS
IF NOT EXISTS
(
SELECT 1
FROM Country
WHERE Country_Name = #countryName
)
INSERT INTO Country (Country_Name) values (#countryName)
First thing to do would be to move the insert SQL into a stored procedure. This would give you 2 benefits - a single DB call to do the work and it would get rid of the SQL Injection problem you have with the code supplied.
Then in the stored procedure, check for the value before inserting.
DECLARE #count INT
SELECT #count = COUNT(*) FROM Country WHERE Name = #countryName
IF #count <= 0 BEGIN
// INSERT HERE
END
Can you use a WHERE statement within an INSERT INTO statement in SQL?
here is what i am currently trying to do.
INSERT INTO AssetComponents(ComponentID, ComponentDescription)
VALUES (#ComponentType, #CompDescr)
WHERE (AssetTagNumber = #TagNo)
But the compiler is having an issue with the WHERE statement.
thanks
***UPDATE****
This is the full code that i am using so far with amendments
protected void AddBut_Click(object sender, EventArgs e)
{
//still passing the Asset tag number forward here
var ID = Request.QueryString["Id"];
string sql = "";
using (SqlConnection con = new SqlConnection("Data Source: *******************)
{
sql = "IF (AssetTagNumber = #TagNo) " +
"BEGIN " +
"INSERT INTO AssetComponents(ComponentID, ComponentDescription) " +
"VALUES (#ComponentType, #CompDescr) " +
"END ";
using (SqlCommand cmd = new SqlCommand(sql, con))
{
// try
// {
cmd.Parameters.AddWithValue("#TagNo", ID);
cmd.Parameters.AddWithValue("#ComponentType", TypeDDL.Text.Trim());
cmd.Parameters.AddWithValue("#CompDescr", DescrTB.Text.Trim());
con.Open();
cmd.ExecuteNonQuery();
con.Close();
Response.Redirect("ComponentDetails.aspx");
// }
// catch (SqlException ex) { MessageBox.Show(" "); }
// catch (Exception ex) { MessageBox.Show(" "); }
}
}
}
Im sorry i was not clear enough first time around.
What i want to do is insert a new record with a clause that says if this record has an existing PK then use this key to insert another entry for that record
Apologies once again
Why don't you just use IF-clause?
IF (AssetTagNumber = #TagNo)
BEGIN
INSERT INTO AssetComponents(ComponentID, ComponentDescription)
VALUES (#ComponentType, #CompDescr)
END
For statements with WHERE script should look similar to:
INSERT INTO AssetComponents(ComponentID, ComponentDescription)
SELECT #ComponentType, #CompDescr
FROM <table>
WHERE (AssetTagNumber = #TagNo)
You can not "conditionally insert" like that. The WHERE clause is only available for SELECT, UPDATE or DELETE.
To check whether you need to INSERT a new record, you need to use IF, as in:
IF NOT EXISTS (SELECT ...)
INSERT INTO ...
if EXISTS (select * from AssetComponents where AssetTagNumber = #TagNo)
Begin
INSERT INTO AssetComponents(ComponentID, ComponentDescription)
(#ComponentType, #CompDescr)
End
Use this:
UPDATE AssetComponents
Set ComponentID=#ComponentType, ComponentDescription=#CompDesc
Where AssetTagNumber = #TagNo
WHERE clause is something that helps to filter record, so it preferably uses with either SELECT or UPDATE. For INSERT we normally use IF NOT EXISTS clause.
See Examples:
http://social.msdn.microsoft.com/Forums/sqlserver/en-US/724ab6f3-413f-4c59-9b68-776f3ecfa899/insert-if-not-exists-into
http://msdn.microsoft.com/en-us/library/ms174335.aspx
Also, after looking at documentation, we can see that INSERT statement has NO support for WHERE clause.
If records already exists you can perform eith UPDATE or DELETE with INSERT operations.
You can try like:
IF NOT EXISTS (SELECT * FROM AssetComponents WHERE (AssetTagNumber = #TagNo))
INSERT INTO AssetComponents(ComponentID, ComponentDescription) VALUES (#ComponentType, #CompDescr)
ELSE
--UPDATE fields
Consider INSERT SELECT:
INSERT INTO AssetComponents(ComponentID, ComponentDescription)
SELECT [fill out here] AS ComponentID,
[fill out here] AS ComponentDescription
FROM somesource
WHERE [condition]
This is a specialty of MS SQL Server so will not work in other databases. It sort of requires that your data are already in another table or other source that you can query.