I have the following situation:
In my database, I have a table called Person. A person has an ID. In my conceptual model, student is inherited from person, so I have another table called Student.
I wrote C# code to insert into the Student table:
string query = "INSERT INTO Person (ID, ...) VALUES("id",...);";
MySqlCommand command = new MySqlCommand(query, connection);
command.ExecuteNonQuery();
query = "INSERT INTO Student (..., ID) VALUES(...,"id");";
command.ExecuteNonQuery();
Obviously, I need to add values into the Person class first, because every student is a person. So, after I did that, I try to add the rest of the Student data into the table.
The problem is that I am getting this error:
Duplicate entry (id) for key "PRIMARY"
which I don't understand, since this key needs to be the same.
The exception message is pretty clear:
Duplicate entry (id) for key "PRIMARY"
You ARE duplicating the ID on a table.
You didn't tell in which line this is happening, so, let's assume both possibilities (and that the error is not elsewhere).
The exception is happening when you are trying to insert into table PERSON.
In this case,if the PRIMARY KEY of this table was AUTO INCREMENT, this wouldn't be possible. If it isn't, and you are inserting the ID of the record by yourself, your code is not creating the ID's correctly and is inserting a value that already exists in the table.
To check if this is the case during runtime, just make a select for the ID you are trying to insert BEFORE actually inserting it:
string query = "SELECT count(*) FROM Person WHERE ID = " + id;
MySqlCommand command = new MySqlCommand(query, connection);
int count = (int)command.ExecuteScalar();
if (count > 0)
{
//You already inserted this ID. Warn the user
}
You are getting the exception on when inserting into table STUDENT
First, lets assume that the ID you are inserting into STUDENT that you're showing here is not the PRIMARY KEY of the table student, but only a FK (foreign key) to table PERSON.
In this case, the same fro the item 1 applies here. You ARE entering a duplicate id in the table. Use the same approach from item 1 to verify this.
But if the ID from PERSON is really the same ID from STUDENT (a ONE to ONE relationship), what's the problem?
Exactly the same. You are entering a duplicated ID.
So, no matter where the error is happening, you are allowing your code to try to insert a DUPLICATE ID (primary key) in the table.
Again, you must be creating the ID's manually, as an auto-increment primary key would not cause this problem (UNLESS you are manually setting the ID, in which case MySQL would use this value instead of the automatic value).
If you are creating the ID's manually, you MUST ensure that they are not duplicates.
I don't even know if this should be called an answer or a hack, but it worked:
string query = "INSERT INTO Person (ID, ...) VALUES(id, ...);
INSERT INTO Student (..., ID) VALUES(..., (select ID from Person WHERE Person.ID = id));";
MySqlCommand command = new MySqlCommand(query, connection);
Related
I am using the following code in order to insert some data into my SQL Server table. There isn't any error shown, but the table doesn't insert the values. What is wrong with it?
string sqlTxt1 = "INSERT INTO Users (ChatId , UserName) VALUES (#ChatId, #from)";
SqlCommand cmd1 = new SqlCommand(sqlTxt1, con);
cmd1.Parameters.AddWithValue("#ChatId", 12345);
cmd1.Parameters.AddWithValue("#from", "usrnm");
con.Open();
cmd1.ExecuteNonQuery();
//int recordsAffected =cmd1.ExecuteNonQuery();
con.Close();
As I put the code in a button and set the ChatId in the table as a primary key, I get an error when I click it twice, so I think the code is correct, but why the table doesn't get those values in the first click?
It should be string sqlTxt1 = "INSERT INTO Users (ChatId , UserName) VALUES (#ChatId, #from)";. You need to pass #from also.
You are inserting not updating the table. So when you click the second time, it tries to insert the record with the same primary key into the table again. You cannot insert the same value for the primary key in the table more than once, it will be a primary key violation. The primary key is always unique.
I am attempting to relocate information in my postgresql database during a migration. data stored in one table is being separated into a many with a table linking them via foreign keys.
Old table: itemsInBag
ID
name
baglabel
New tables: item, itemsInBag, bag
item
Id
Name
itemsInBag
Id
ItemId
BagId
bag
Id
BagLabel
Currently I have these SQL statements to try to link them together. This is done after the new tables and fields have been added and before the itemsInBag fields are dropped.#
migrationBuilder.Sql(
"INSERT INTO items (Name)" +
"SELECT (name) FROM itemsInBag");
migrationBuilder.Sql(
"INSERT INTO bag baglabel" +
"SELECT DISTINCT baglabel FROM itemsInBag");
migrationBuilder.Sql(
"UPDATE itemsInBag SET bagid =(SELECT id FROM bag WHERE bag.baglabel = itemsInBag.baglabel)"
);
migrationBuilder.Sql(
"UPDATE itemsInBag SET itemid =(SELECT id FROM items WHERE items.name = itemsInBag.name)"
);
I am receiving this error when trying to run the migration
$exception {"23505: could not create unique index \"IX_itemsinbag_bagid_itemid\""} Npgsql.PostgresException
"Key (bagid, itemid)=(0, 0) is duplicated."
From everything I have read it would seem this is the right way to do it. Is there a better way of doing this? Is there something I am missing?
UPDATE: if I move the unique constraint on bagid and itemid to after the SQL statements i get this error
$exception {"23503: insert or update on table \"itemsinbag\" violates foreign key constraint \"FK_itemsinbag_bag_bagid\""} Npgsql.PostgresException
"Key (bagid)=(0) is not present in table \"bag\"
Figured out the solution to this. It was all a matter of arranging where the Indices and foreign key constraints were in relation to my SQL statements. The Foreign key constraints needed to be created after the tables data had been rearranged. There was also an error after where the items table did not exist on the insert. The schema needed to be included such that the final SQL statements were as follows:
migrationBuilder.Sql(
"INSERT INTO schema.items (Name)" +
"SELECT name FROM schema.itemsInBag");
migrationBuilder.Sql(
"INSERT INTO schema.bag (baglabel)" +
"SELECT DISTINCT baglabel FROM schema.itemsInBag");
migrationBuilder.Sql(
"UPDATE schema.itemsInBag SET bagid =(SELECT id FROM schema.bag WHERE schema.bag.baglabel = schema.itemsInBag.baglabel)"
);
migrationBuilder.Sql(
"UPDATE schema.itemsInBag SET itemid =(SELECT id FROM schema.items WHERE schema.items.name = schema.itemsInBag.name)"
);
I am new to sql. I have added 2 new tables in database. The primary key of first is a foreign key in the other. The type of the keys is integer. Now I want to generate the keys in the code and assign it to new data so that the association between different rows of the tables is right. How do I ensure uniqueness of keys and also get the latest key from the db so that there are no errors while saving.
If I had used guids then I would have assigned a new guid to the primary key and then assigned the same to the foreign key in the other table. Also there are multiple clients and one server which is saving the data.
The data to be inserted in both the tables is decided in the c# code and is not derived from the row inserted in the primary table. Even if get the id in db then also the relation between the rows should be stored in some form from the code because after that it is lost.
The only viable way to do this is to use INT IDENTITY that the SQL Server database offers. Trust me on this one - you don't want to try to do this on your own!
Just use
CREATE TABLE dbo.YourTableOne(ID INT IDENTITY(1,1), ...other columns...)
and be done with it.
Once you insert a row into your first table, you can retrieve the value of the identity column like this:
-- do the insert into the first table
INSERT INTO dbo.YourTableOne(Col1, Col2, ...., ColN)
VALUES (Val1, Val2, ...., ValN)
DECLARE #NewID INT
-- get the newly inserted ID for future use
SELECT #NewID = SCOPE_IDENTITY()
-- insert into the second table, use first table's new ID for your FK column
INSERT INTO dbo.YourTableTwo (FKColumn, ......) VALUES(#NewID, ......)
Update: if you need to insert multiple rows into the first table and capture multiple generated ID values, use the OUTPUT clause:
-- declare a table variable to hold the data
DECLARE #InsertedData TABLE (NewID INT, ...some other columns as needed......)
-- do the insert into the first table
INSERT INTO dbo.YourTableOne(Col1, Col2, ...., ColN)
OUTPUT Inserted.ID, Inserted.Col1, ..., Inserted.ColN INTO #InsertedData(NewID, Col1, ..., ColN)
VALUES (Val1, Val2, ...., ValN)
and then go from there. You can get any values from the newly inserted rows into the temporary table variable, which will then allow you to decide which new ID values to use for which rows for your second table
As #marc_s said using Database managed keys is more viable. But in cases there is no much load on the database, for example because there are few users who work simultanously, I will use another easier method. That's I get the last id, I try to add new record, and if I encountered error for duplicate, I will try again. I limited this to 3 trials for my application and there's a 300 ms timeout between each trial. Dont forget that this approach has serious limitations. In my application, there are very few users, the work load is very low, and the connection is a local one so this will do job well. Perhaps in other applications you need to adjust the delay, and in some cases, the approach might completely fail. Here's the code,
I have two tables, Invoices and Invoices_Items the column which relates them is invoice_id:
byte attempts = 0;
tryagain: //Find last invoice no
OleDbCommand command = new OleDbCommand("SELECT MAX(invoice_id) FROM Invoices"
, myconnection);
int last_invoice_id = 0;
try
{
last_invoice_id = (int)command.ExecuteScalar();
}
catch (InvalidCastException) { };
// text_invoice_number.Text = Convert.ToString(last_invoice_id + 1);
try
{
command = new OleDbCommand(#"INSERT INTO Invoices
(invoice_id,patient_id,visit_id,issue_date,invoice_to,doctor_id,assistant_id)
VALUES(?,?,?,?,?,?,?)",myconnection);
// We use last_invoice_id+1 as primary key
command.Parameters.AddWithValue("#invoice_id",last_invoice_id+1);
// I will add other parameters here (with the exact order in query)
command.ExecuteNonQuery();
}
catch (Exception ex){
attempts++;
if (attempts <= 3) // 3 attempts
{
System.Threading.Thread.Sleep(300); // 300 ms second delay
goto tryagain;
}
else
{
MessageBox.Show("Can not add invoice to database, " + ex.Message, "Unexpected error!"
, MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
for (int i = 0; i <= listInvoiceItems.Count-1; i++)
{
command = new OleDbCommand(#"INSERT INTO Invoices_Items
(invoice_id,quantity,product,price,amount,item_type)
VALUES(?,?,?,?,?,?)",myconnection);
// Now we use our stored last_invoice_id+1 as foreign key
command.Parameters.AddWithValue("#invoice_id",last_invoice_id+1);
// Add other Invoice Items parameters here (with the exact order in query)
command.ExecuteNonQuery();
}
I have a database with two tables; StudentID is the primary key on 'StudentList' table and StudentID is the foreign key on the 'JournalEntries' table.
On my website I have a search function so users can search for a student from the StudentList and the results are displayed in a datagrid. When the user selects a student from the list a journal entry box pops up. When they fill out the journal entry pop-up box and click the submit button I need the journal entry to be entered into the JournalEntries table tied to the student id that was selected from the datagrid.
protected void SearchGrid_SelectedIndexChanged(object sender, EventArgs e)
{
FNameLabel.Text = SearchGrid.SelectedRow.Cells[1].Text;
LNameLabel.Text = SearchGrid.SelectedRow.Cells[2].Text;
string constr = #"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=D:\Sites\Network2\nrsh\App_Data\myDB.mdb";
string cmdstr = "SELECT StudentID FROM StudentList WHERE = SearchGrid.SelectedRow.Cells[3].Text AND INSERT into JournalEntries (Topic, SubTopic, Summary, Date, Notes) values (#Topic, #SubTopic, #Summary, #Date, #Notes)";
OleDbConnection con = new OleDbConnection(constr);
OleDbCommand com = new OleDbCommand(cmdstr, con);
con.Open();
//The following fields are added from the journal entry form to the corresponding database fields
com.Parameters.AddWithValue("#Topic", ddlTopic.Text);
com.Parameters.AddWithValue("#SubTopic", txtSubTopic.Text);
com.Parameters.AddWithValue("#Date", txtDate.Text);
com.Parameters.AddWithValue("#Summary", txtSummary.Text);
com.Parameters.AddWithValue("#Notes", txtNotes.Text);
com.ExecuteNonQuery();
con.Close();
}
So that's my thought on the logic but it's probably completely wrong since I don't know much about sql. Any help would be great.
You cannot combine a SELECT and INSERT statement.
.......
string myValue = SearchGrid.SelectedRow.Cells[3].Text;
You don't have the value of SearchGrid.SelectedRow.Cells[3].Text in your string..you literally have "SearchGrid.SelectedRow.Cells[3].Text"...
string myValue = SearchGrid.SelectedRow.Cells[3].Text;
string cmdstr = "INSERT into JournalEntries (StudentID , Topic, SubTopic, Summary, Date, Notes) values (#StudentID , #Topic, #SubTopic, #Summary, #Date, #Notes)";
and the later
com.Parameters.AddWithValue("#StudentID", myValue);
com.Parameters.AddWithValue("#Topic", ddlTopic.Text);
com.Parameters.AddWithValue("#SubTopic", txtSubTopic.Text);
com.Parameters.AddWithValue("#Date", txtDate.Text);
com.Parameters.AddWithValue("#Summary", txtSummary.Text);
com.Parameters.AddWithValue("#Notes", txtNotes.Text);
I'm kinda guessing. You should give your table names and all the columns in your table and their datatypes (int, string, etc).
EDIT: REFACTOR.
You should create a class that accepts arguments. You should never have database code .... sitting where your GUI code is.
public class JournalEntriesManager
{
public static void InsertJournalEntry ( string studentID, string topic , string subTopic, DateTime DateOf , string summary , string notes )
{
// Your code here
}
}
That's like "Level 1" of "separation of concerns".
But in a nutshell, your GUI level code should COLLECT the information from the controls......and pass that info to BusinessLogic ("JournalEntriesManager" in this case).
Something like that.
You can't quite combine multiple statements with the AND statement, that is for combining multiple conditions together. Also, you can't just magically associate a row in one table to a row in another, instead, your JournalEntries table should have another column in it that contains the ID of the student that the entry is associated with. When you insert a new row into the JournalEntries table, you would include the student ID in that column and that is how your journal entries will be associated with a student.
Also, your queries can not include variable names like "SearchGrid.SelectedRow.Cells[3].Text", you would have to instead insert the value of that variable directly into the query text. Remember, you are sending this query to another server (your database server) and it has no idea what your variables are in your script.
I’m hoping somebody will be able to help with my SQLite database problem.
I’m receiving a ConstraintException when querying my SQLite database with C#. The full exception message is “Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.” I originally built this database using access which worked fine, but for various reasons I had to recreate it using SQLite.
To give a bit of background - this is a simple status scheduling program. Each Status has an associated Account and Schedule. I realise Statuses and Schedule is a 1:1 relationship and could be in the same table but to allow the program to develop further I have split them into two tables.
See below for a cut down version of my table script (this is enough to recreate the problem).
PRAGMA foreign_keys = ON;
CREATE TABLE Accounts
(ID INTEGER PRIMARY KEY AUTOINCREMENT,
Name char(100));
CREATE TABLE Statuses
(ID INTEGER PRIMARY KEY AUTOINCREMENT,
AccountId INTEGER REFERENCES Accounts(ID) ON DELETE CASCADE,
Text char(140));
CREATE TABLE Schedule
(ID INTEGER PRIMARY KEY REFERENCES Statuses(ID) ON DELETE CASCADE,
StartDate char(255),
Frequency INT);
I did not have any issues until I created two Statues and associated them to the same Account.
Accounts
ID Name
1 Fred Blogs
Statuses
ID AccountId Text
1 1 “Some text”
2 1 “Some more text”
Schedule
ID StartDate Frequency
1 16/02/2011 1
2 16/02/2011 1
The select statement I’m using which throws the exception is:
SELECT Statuses.Id, Statuses.Text, Accounts.Id, Accounts.Name, Schedule.StartDate, Schedule.Frequency
FROM [Statuses], [Accounts], [Schedule]
WHERE Statuses.AccountId = Accounts.Id AND Statuses.Id = Schedule.Id
If I run the same query, but remove the ‘Accounts.Id’ column the query works fine.
See below for the C# code I’m using but I don’t think this is the problem
public DataTable Query(string commandText)
{
SQLiteConnection sqliteCon = new SQLiteConnection(ConnectionString);
SQLiteCommand sqliteCom = new SQLiteCommand(commandText, sqliteCon);
DataTable sqliteResult = new DataTable("Query Result");
try
{
sqliteCon.Open();
sqliteResult.Load(sqliteCom.ExecuteReader());
}
catch (Exception)
{
throw;
}
finally
{
sqliteCon.Close();
}
return sqliteResult;
}
Any help will be appreciated. Thanks.
the error is occuring due to the ID columns in Statuses table and Schedule table. If they are not important delete the columns from the two tables.
I have found a way round this problem. If I select the AccountId from the Schedule table rather than the Accounts table there is no exception thrown. It seems I was unable to run a SELECT statement that contained two Unique primary key columns.
So instead of
SELECT Statuses.Id, Statuses.Text, Accounts.Id, Accounts.Name, Schedule.StartDate, Schedule.Frequency
FROM [Statuses], [Accounts], [Schedule]
WHERE Statuses.AccountId = Accounts.Id AND Statuses.Id = Schedule.Id
I run
SELECT Statuses.Id, Statuses.Text, Statuses.AccountId, Accounts.Name, Schedule.StartDate, Schedule.Frequency
FROM [Statuses], [Accounts], [Schedule]
WHERE Statuses.AccountId = Accounts.Id AND Statuses.Id = Schedule.Id
I fixed the issue by reading the schema only at first, then cleared the constraints of the datatable and then read again the data.
like this :
DataSet DS = new DataSet();
mytable = new DataTable();
DS.Tables.Add(mytable);
DS.EnforceConstraints = false;
SQLiteCommand command = DBconnection.CreateCommand();
command.CommandText = "select * from V_FullView";
SQLiteDataReader reader = command.ExecuteReader(CommandBehavior.SchemaOnly);
mytable.Load(reader);
mytable.Constraints.Clear();
reader = command.ExecuteReader();
mytable.Load(reader);
reader.Close();
my V_FullView is a view of 4 different tables merged. It seems that the constraints are the ones of the first merged table (name was unique on that one, but replicated a multiple of times in the view)