I'm imagining that this is a simple question, but I'm running into syntax issues I think.
I have a table that has an event ID as primary key(eventID), a device ID that of what triggered the event, and a timestamp of when the event triggered. I"m processing the mySQL(5.1) elements via C# and command line.
My dilemma is that I have to duplicate/import the database to another database and I am getting duplicate entries due to the eventID being the primary key and it being updated everytime a new record is added automatically. Changing that isn't an option. So what I want to do is only insert into the database if my current deviceID+timestamp combination doesn't already exist.
I've found a lot of query examples, but they either throw syntax issues or simply don't work as needed. In pseudo code this is what I'm looking for..
IF timestampToInsert EXISTS WHERE deviceIDtoInsert ALSO EXISTS ON SAME ROW
UPDATE ROW
ELSE
INSERT INTO myTABLE (deviceID, timeStamp) VALUES (deviceIDtoInsert, timestampToInsert)
It sounds like you want to do an "upsert".
In MySQL this is called "INSERT...ON DUPLICATE KEY UPDATE":
INSERT INTO myTABLE (deviceID, timeStamp)
VALUES (deviceIDtoInsert, timestampToInsert)
ON DUPLICATE KEY UPDATE ...
Note this will only work if you have a unique index on (deviceID,timestamp)
Related
I am using LINQ-to-SQL class. I am inserting a new row using LINQ method object.InsertOnSubmit().
I need to set same value which is generate by SQL Server (using Identity) for table primary key column.
Now I need the same value at the time of inserting new row into table. And set the same value for other column in the same table at the time of insert only.
As I cannot update as after inserting because table has UPDATE TRIGGER.
I tried the following
_db.EmpNews.InsertOnSubmit(_EmpNews);
...
_db.DisplaySeq = _EmpNews.ID;
...
_db.SubmitChanges();
Where ID is the auto-generated (Identity) column.
The first question really is: why would you need to store the same value in two separate columns in the same table? What do you need this for? Doesn't seem to make a lot of sense to me....
Since the value of the IDENTITY column is only available once the row has actually been inserted, there is no way to get that value and set it to another column before the row has indeed been saved to the database table.
That basically leaves three options to get that value and store it somewhere else:
you can write an AFTER INSERT trigger that just set the other column to the value that's just been inserted in the IDENTITY column
you could wrap the whole saving process into a stored procedure which you call from your C# code (instead of just saving the object) and you would do the INSERT of the row, then get the newly created IDENTITY value and update the row again with that new value. But that would cause an UPDATE to happen - which you seem to say is impossible for you because of an UPDATE trigger (not quite clear on why this should be a problem....)
you can write two lines of C# code to get the IDENTITY value after it's been inserted (and available in the ID property of your object) and then store the object a second time. But that, too, would cause an UPDATE to happen - which you seem to say is impossible for you because of an UPDATE trigger (not quite clear on why this should be a problem....)
So I guess your best option would be an INSERT trigger to do this.
Try something like this:
CREATE TRIGGER trInsertEmpNews
ON dbo.EmpNews AFTER INSERT
AS BEGIN
UPDATE dbo.EmpNews
SET DisplaySeq = i.ID
FROM INSERTED i
WHERE dbo.EmpNews.ID = i.ID
END
i'm trying to update my data in datagridview by going to sqldatasource properties "update queries" and writing the codes but its showing an error message
"Violation of PRIMARY KEY constraint 'PK_contact_master'. Cannot insert duplicate key in object 'dbo.admission_table'.
The statement has been terminated. "
plz tell me the exact code of editing the data in datagridview and update it..
Thanks,
Churchill
UPDATE:
Sql Code:
Update admission_table
set registration_id=#registration_id,
name_of_degree=#name_of_degree,
fees_paid=#fees_paid,
hostel=#hostel,
hostel_fees=#hostel_fees,
name_of_student=#name_of_student,
Date_of_birth=#Date_of_birth,
nationality=#nationality,
gender=#gender,
address=#address,
phone_no=#phone_no,
e_mail=#e_mail,
date=#date
Based on the sql query you provided it seems like your issue is that you don't have a where clause on your update query and you appear to be setting the primary key in the update.
This means you will update every record in the table with the same info and violate the PK.
To fix this I would first add a where clause. Once you are updating only the record you want you can most likely remove the registration_id from your set clause (assuming that's your pk).
My insert statement is:
INSERT INTO myTable (inst_id,user_id,app_id,type,accessed_on)
VALUES (3264,2580,'MyApp','Renew',Now);
...where all of the values are formatted correctly. The table has the above fields and one other, a long int auto-increment key field. The foreign keys are 'inst_id', 'user_id', and 'app_id'.
I am getting this error from Access:
...and the following error from VS 2005 when it errors out:
System.Data.OleDb.OleDbException: The changes you requested to the table
were not successful because they would
create duplicate values in the index,
primary key, or relationship. Change
the data in the field or fields that
contain duplicate data, remove the
index, or redefine the index to permit
duplicate entries and try again.
When making this insert query I can look into the database and see that the each of the foreign key values exist in their respective tables and have been for months (for the particular example I am using). These fields are also set so that I can have duplicates, so that is not the issue. Calls of this nature in other tables works great. I do not need to supply the auto-increment key value in the insert query, it adds it for me automatically (like it should).
The weird thing is that if I do this in my code:
try
{
//Execute the query here...
}
catch
{
//Execute the same query again
}
...or if I just try and execute this within Access twice, it works.
Has anyone encountered this before? Again, this type of insert works for other tables, all foreign keys are present in their respective tables, the primary key of this table is set as 'Auto-increment', and all fields (other than the primary key field of course) are set to allow duplicates.
Any ideas?
EDIT: Largest key before inserting: 343085. Largest key after inserting: 343086. The format is:
id: AutoNumber (Field Size=Long Interger, New Values=Increment, Indexed=Yes - No Duplicates)
inst_id: Number (Field Size=Long Interger, Required=Yes, Indexed=Yes - Duplicates OK)
user_id: Number (Field Size=Long Interger, Required=Yes, Indexed=Yes - Duplicates OK)
app_id: Text (Field Size=255, Required=Yes, Indexed=Yes - Duplicates OK)
type: Text (Field Size=50, Required=Yes, Indexed=No)
accessed_on: Date/Time (Default Value=Now(), Required=Yes, Indexed=No)
Going by some old memory here...
Try putting a timestamp field in your table.
I can't remember exactly why that works -- something to do with Access having difficulty identifying records / maybe some kind of locking or indexing quirk. I did some research on that several years ago when it happened to one of my tables.
The key violation the error refers to isn't a missing key in another table, it's a duplicate key in the same table. Sometimes, Access gets it's wires crossed and thinks that the key it's assigning to the new record is already assigned to another record in the table. I don't know what causes that to happen. But by putting a timestamp field in the table, it causes Access to think differently.
It's a frustrating fix, because I don't know why it works. And now I have an otherwise useless timestamp field in my table. But so be it.
MS-Access has been known to barf up spurious errors that have nothing to do with the problem they report. It wouldn't hurt to surround the column called "type" with brackets, [type].
http://office.microsoft.com/en-us/access-help/access-2007-reserved-words-and-symbols-HA010030643.aspx#_Toc272229038
Is the value Now changing between attempts so that there is now no longer a duplicate key error?
INSERT INTO myTable (inst_id,user_id,app_id,type,accessed_on)
VALUES (3264,2580,'MyApp','Renew',Now);
Can you just check this out with accessed_on datatype and Now datatype
Change the value type of DateTime to String while inserting that will be good.
Do let me know if this works for you.
Thanks
rAfee
I believe Jet/ACE will not understand the NOW() method.
And i worked with ACE version, the syntax could not work.
Need to find the other way for direct implementing the syntax.
I know long time ago I had a similuar issue. In my cases I was getting the same error but I didn't have any unique indexes in the table. I finally solved it by reparing and compacting the database.
I am building a hit counter. I have an article directory and tracking unique visitors. When a visitor comes i insert the article id and their IP address in the database. First I check to see if the ip exists for the article id, if the ip does not exist I make the insert. This is two queries -- is there a way to make this one query
Also, I am not using stored procedures I am using regular inline sql
Here are some options:
INSERT IGNORE INTO `yourTable`
SET `yourField` = 'yourValue',
`yourOtherField` = 'yourOtherValue';
from MySQL reference manual: "If you use the IGNORE keyword, errors that occur while executing the INSERT statement are treated as warnings instead. For example, without IGNORE, a row that duplicates an existing UNIQUE index or PRIMARY KEY value in the table causes a duplicate-key error and the statement is aborted.".) If the record doesn't yet exist, it will be created.
Another option would be:
INSERT INTO yourTable (yourfield,yourOtherField) VALUES ('yourValue','yourOtherValue')
ON DUPLICATE KEY UPDATE yourField = yourField;
Doesn't throw error or warning.
Yes, you create a UNIQUE constraint on the columns article_id and ip_address. When you attempt to INSERT a duplicate the INSERT will be refused with an error. Just answered the same question here for SQLite.
IF NOT EXISTS (SELECT * FROM MyTable where IPAddress...)
INSERT...
Not with SQL Server. With T-SQL you have to check for the existence of a row, then use either INSERT or UPDATE as appropriate.
Another option is to try UPDATE first, and then examine the row count to see if there was a record updated. If not, then INSERT. Given a 50/50 chance of a row being there, you have executed a single query 50% of the time.
MySQL has a extension called REPLACE that has the capability that you seek.
The only way I can think of is execute dynamic SQL using the SqlCommand object.
IF EXISTS(SELECT 1 FROM IPTable where IpAddr=<ipaddr>)
--Insert Statement
I agree with Larry about using uniqueness, but I would implement it like this:
IP_ADDRESS, pk
ARTICLE_ID, pk, fk
This ensures that a record is unique hit. Attempts to insert duplicates would get an error from the database.
I would really use procedures! :)
But either way, this will probably work:
Create a UNIQUE index for both the IP and article ID columns, the insert query will fail if they already exist, so technically it'll work! (tested on mysql)
try this (it's a real kludge, but it should work...):
Insert TableName ([column list])
Select Distinct #PK, #valueA, #ValueB, etc. -- list all values to be inserted
From TableName
Where Not Exists
(Select * From TableName
Where PK == #PK)
so I have an old database that I'm migrating to a new one. The new one has a slightly different but mostly-compatible schema. Additionally, I want to renumber all tables from zero.
Currently I have been using a tool I wrote that manually retrieves the old record, inserts it into the new database, and updates a v2 ID field in the old database to show its corresponding ID location in the new database.
for example, I'm selecting from MV5.Posts and inserting into MV6.Posts. Upon the insert, I retrieve the ID of the new row in MV6.Posts and update it in the old MV5.Posts.MV6ID field.
Is there a way to do this UPDATE via INSERT INTO SELECT FROM so I don't have to process every record manually? I'm using SQL Server 2005, dev edition.
The key with migration is to do several things:
First, do not do anything without a current backup.
Second, if the keys will be changing, you need to store both the old and new in the new structure at least temporarily (Permanently if the key field is exposed to the users because they may be searching by it to get old records).
Next you need to have a thorough understanding of the relationships to child tables. If you change the key field all related tables must change as well. This is where having both old and new key stored comes in handy. If you forget to change any of them, the data will no longer be correct and will be useless. So this is a critical step.
Pick out some test cases of particularly complex data making sure to include one or more test cases for each related table. Store the existing values in work tables.
To start the migration you insert into the new table using a select from the old table. Depending on the amount of records, you may want to loop through batches (not one record at a time) to improve performance. If the new key is an identity, you simply put the value of the old key in its field and let the database create the new keys.
Then do the same with the related tables. Then use the old key value in the table to update the foreign key fields with something like:
Update t2
set fkfield = newkey
from table2 t2
join table1 t1 on t1.oldkey = t2.fkfield
Test your migration by running the test cases and comparing the data with what you stored from before the migration. It is utterly critical to thoroughly test migration data or you can't be sure the data is consistent with the old structure. Migration is a very complex action; it pays to take your time and do it very methodically and thoroughly.
Probably the simplest way would be to add a column on MV6.Posts for oldId, then insert all the records from the old table into the new table. Last, update the old table matching on oldId in the new table with something like:
UPDATE mv5.posts
SET newid = n.id
FROM mv5.posts o, mv6.posts n
WHERE o.id = n.oldid
You could clean up and drop the oldId column afterwards if you wanted to.
The best you can do that I know is with the output clause. Assuming you have SQL 2005 or 2008.
USE AdventureWorks;
GO
DECLARE #MyTableVar table( ScrapReasonID smallint,
Name varchar(50),
ModifiedDate datetime);
INSERT Production.ScrapReason
OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
INTO #MyTableVar
VALUES (N'Operator error', GETDATE());
It still would require a second pass to update the original table; however, it might help make your logic simpler. Do you need to update the source table? You could just store the new id's in a third cross reference table.
Heh. I remember doing this in a migration.
Putting the old_id in the new table makes both the update easier -- you can just do an insert into newtable select ... from oldtable, -- and the subsequent "stitching" of records easier. In the "stitch" you'll either update child tables' foreign keys in the insert, by doing a subselect on the new parent (insert into newchild select ... (select id from new_parent where old_id = oldchild.fk) as fk, ... from oldchild) or you'll insert children and do a separate update to fix the foreign keys.
Doing it in one insert is faster; doing it in a separate step meas that your inserts aren't order dependent, and can be re-done if necessary.
After the migration, you can either drop the old_id columns, or, if you have a case where the legacy system exposed the ids and so users used the keys as data, you can keep them to allow use lookup based on the old_id.
Indeed, if you have the foreign keys correctly defined, you can use systables/information-schema to generate your insert statements.
Is there a way to do this UPDATE via INSERT INTO SELECT FROM so I don't have to process every record manually?
Since you wouldn't want to do it manually, but automatically, create a trigger on MV6.Posts so that UPDATE occurs on MV5.Posts automatically when you insert into MV6.Posts.
And your trigger might look something like,
create trigger trg_MV6Posts
on MV6.Posts
after insert
as
begin
set identity_insert MV5.Posts on
update MV5.Posts
set ID = I.ID
from inserted I
set identity_insert MV5.Posts off
end
AFAIK, you cannot update two different tables with a single sql statement
You can however use triggers to achieve what you want to do.
Make a column in MV6.Post.OldMV5Id
make a
insert into MV6.Post
select .. from MV5.Post
then make an update of MV5.Post.MV6ID