sql - duplicates - c#

I'm putting data from website (json) to sql base.
In db i have these rows.
ID | PostId | Name | Message
Id is auto-increment primary key.
PostId also has a unique values.
Name and Message are nothing special.
When I run my script / click on the button in form / ... , the program saves all the values into database (lets say there are 25).
Next time I'm going to press the button there will be added 25 more records (all duplicates), and so on...
Is there a way that the program can check through 'PostIds' if the value already exists before adding it to the db?
Thanks

Another way is to use merge statement, this can also update the duplicate rows if you like and is easier than useing an if statement

if not exists(select * from table where PostId =#PostId)
Begin
//add
End

You have many option
Simple one is that you ask Your data base about that PostId
SELECT count(PostId) FROM Table where PostId = #PostId;

Related

how to insert same LAST_INSERT_ID() in one table to create multiple records;

I am programming a website, with ASP.NET, C#, as well as using MYSQL.
I need to be able to record two rows with same child_id;
My problem is with this one statement, it inserts one row and skips the last.
//data.ChldrenRecord.Service contain two records
// babysit, and tutor
foreach (string s in data.ChildrenRecord.Services)
{
query += (" INSERT INTO ServiceChildren SET service='" + s + "', child_id=LAST_INSERT_ID();");
}
so table should look something like this
id service child_id
1 babysit 1
2 tutor 1
I use Last_INSERT_ID() because child_id is a foreign key. I create a record in another table whose primary key is child_id. Afterwards, I use LAST_INSERT_ID() to reference that one record primary key child_id so that i may use it in my ServiceChildren table.
as it stands my table looks:
id service child_id
1 babysit 1
I think i am on the right track now. if i log directly into the database, this statement works:
SET #last_id = LAST_INSERT_ID();
//then insert statements
INSERT INTO ServiceChildren(service, child_id) VALUES('babysit', #last_id);
INSERT INTO ServiceChildren(service, child_id) VALUES('tutor', #last_id);
BUT IN MY C#, ASP.NET CODE THE LINE
SET #last_id = LAST_INSERT_ID();
does not do anything, even populate tables with a prior insert statement.
OK, I found out my problem. I needed to place Allow User Variables=True in the connection string to be allowed to create and use #last_id.

How to synchronize custom ID column with table's primary key column

Primarily, sorry for being too descriptive.
I am storing patient's info in sql db by creating a custom ID field "PatientID" and I have a primary key field "ID". PatientID has a pattern "PID-1" or "PID-2" so on and so forth. I want to synchronize both IDs. Like if table's ID for "John" is 4 then its patientID should also be "PID-4". For this, I have done some coding like if no record exist then start saving patientID from "PID-1" and then for all next record first find the max id of patient from ID field and increment it by 1 and concatenate it with "PID" + (tableID+1).
ID PatientID
1 PID-1
2 PID-2
3 PID-3
4 PID-4
Now, for an instance, while adding more record an exception is thrown although record is not saved but ID gets incremented. And here comes the problem. Suppose, some bug comes and record for ID 5 could not be saved in the db, after fixing that bug when program runs correctly it put the ID 6 rather than 5. And for the patientID it puts "PID-5" due to MAX query. From here both IDs start being distinct. Same problem for deleting, if I am deleting last record from above table i.e, 4 and PID-4, the next record's ID would be 5 while PatientID would be "PID-4". This was the whole problematic picture of handling both IDs from my side. Any alternate solution or any modification in my idea or any better idea then mine would be highly appreciated.
In SQL Server you could create a computed column for this purpose:
ALTER TABLE Patient DROP COLUMN PatientID;
GO
ALTER TABLE Patient ADD COLUMN PatientID AS ('PID-'+CAST(ID AS VARCHAR(15));
For more info regarding computed columns, please have a look here.
Note: I assumed that your table's name is Patient. You have to change this correspondingly if this is not the name of your table.

Generate ids for a database based on certain information

I need a way to generate ids for a database based on certain information. Depending on the conference the user is registering for, the id will differ. The id will be 4 digits of the event identifier concatenated with 5 sequential digits. For example:
Event A: 1000
Event B: 2000
Event C: 3000
An id for event A could be 100012345, and the next number for this id would be 100012346. An id for event B could be 200012345. Etc.
So how can I grab the last id for a certain event?
How can I autogenerate the next number for this?
Use uniqueidentifier type for IDs with newid() default value , not int. This will create automatically new id of type guid.
If the problem is to take last created ID.Create two new columns in your table UpdateDate and CreateDate. When you are inserting a record
CreateDate = DateTime.Now;
On update
UpdateDate = DateTime.Now;
If you want to take last create item you will fetch data from database with this query:
Select * from [TableName] Order By CreateDate Desc
I suggest you split the event and id as two separate columns in the DB and make them both primary key.
Then, should you need to add another key, first check what event you need (for example 1000) then check on DB what's the max id for that event. This should answer your first question.
As for your second question, once you have the max id for the event, you can just add +1.
Or even better, you could define id as auto-increment, but I'm not sure it'll work on a single part of a complex primary key.
Hope this helps! :)
If you insist on combining the two int values as a string then you would have to search. Since you are using strings you will need to make sure your sequence number is zero padded e.g 200000001 being the first id for event B. Given this then the query
Select top 1 ID from [TableName] Where ID like '2000%' Order By ID Desc
should get you the largest ID and you will have to break it apart/convert to int and increment it. Of course you will then need some collision handling code when you attempt to create the record unless you are single thread/process when changing the db.
You might want to consider breaking these two concepts apart. You could use individual int fields to prevent doing string searches and instead combine the two int values when you need to present them as a combined identifier. Then you r SQL is
Select Top 1 SequenceId from [TableName] Where EventId=2000 Order By SequenceId Desc
Also if you truly want auto incremented sequence identifiers then you would have to move to a table per event with an auto incremented PK on each table as primary keys are the only auto incremented fields in SQL Server.
In my opinion, a trigger would be a good bet. You could create an sql trigger which would fire before the insert, checking which event the user is registering for, and generating the corresponding Id.

Get MAX id number from database table after deleting last record

I want to get a new row id for "products", for this I use MAX SQL command as follwing (the command is in insert new record button click event):
SqlCommand cmd = new SqlCommand("Select ISNULL(MAX(id)+1,0) from products", SqlCon);
the issue is when there are rows with IDs 10,11,12 (12 is MAX) and i delete id 12 record , i gets MAX+1 id 12 when the new id row is 13 ("id" field is PK with identity increment 1).
can i do it with other way?
example:
id prodect
-- -------
1 dog
2 cat
3 mouse
4 elefant
when i deletes row 4 i get MAX(id)+1 = 4 and i want to get 5 since this is the next row id.
I suspect the actual question is How can I find the ID of the row I just inserted so I can use it as a foreign key in related tables or in an image file name?
SQL Server since 2005 provides the OUTPUT clause in INSERT, UPDATE, DELETE statements that returns the values of the columns just inserted or modified. In the case of the insert statement, the syntax is:
insert into Products (Product)
OUTPUT inserted.ID
VALUES ('xxx')
This is a better option than the IDENT_CURRENT or SCOPE_IDENTITY values because it returns the values using a single statement and there is no ambiguity about what is returned:
IDENT_CURRENT may return a different value if multiple users are writing to the table outside a transaction
SCOPE_IDENTITY returns the last ID generated in a transaction, no matter the table
You can return more than one column:
insert into Products (Product)
OUTPUT inserted.ID, inserted.Product
VALUES ('xxx')
You can execute this statement with ExecuteScalar, if you return only one column or ExecuteReader, if you want to return more columns.
In the case of UPDATE or DELETE statements, the deleted table contains the deleted values and inserted contains the new values
Note ORMs like Entity Framework use such statements already to retrieve auto-generated IDs and update saved objects. In this case one only needs to read the ID property of the saved objects.
I will take a stab at what I think you are after. :)
If you include SELECT SCOPE_IDENTITY(); in your SQL you will get the ID you need:
INSERT INTO products (
* your fields *
)
VALUES (
* your values *
);
SELECT SCOPE_IDENTITY();
And then in your code you can have:
var Id = Convert.ToInt32(cmd.ExecuteScalar());
This will give you the id of the record you have inserted.
One possible solution could be that you don't delete the rows. You can add a flag and make it inactive/deleted. That way your row numbers will always be preserved and your code will give you the max Id.
I think the OP tries to tackle the wrong problem...
When you insert a new product into the products table, you should try to retrieve the new id directly with the scope_identity function as such (SQLServer!):
string sql = "insert into products(name) values('Yellow Cup'); SELECT SCOPE_IDENTITY();";
var sqlCommand = new SqlCommand(sql, conn);
var id = cSqlServer.ExecuteScalar();
Definitely MAX is not what anybody would use in this case. Closest solution would be to get recently used identity value and then increment it by 1 (in your case) or by seed value, whatever it is.
select ident_current('products') + 1
Caution - although this solves your purpose for now, beware that 'ident_current' will return you the identity value set by other sessions as well. In simple words, if there is some request/trigger/execution that causes id to be incremented even before your button click finishes then you you will get inserted_id and not deleted one.

3 records with same ID but change different columns using SqlBulkCopy

I am doing a conversion with SqlBulkCopy. I currently have an IList collection of classes which basically i can do a conversion to a DataTable for use with SqlBulkCopy.
Problem is that I can have 3 records with the same ID.
Let me explain .. here are 3 records
ID Name Address
1 Scott London
1 Mark London
1 Manchester
Basically i need to insert them sequentially .. hence i insert record 1 if it doesn't exist, then the next record if it exists i need to update the record rather than insert a new 1 (notice the id is still 1) so in the case of the second record i replace both columns Name And Address on ID 1.
Finally on the 3rd record you notice that Name doesn't exist but its ID 1 and has an address of manchester so i need to update the record but NOT CHANGING Name but updating Manchester.. hence the 3rd record would make the id1 =
ID Name Address
1 Mark Manchester
Any ideas how i can do this? i am at a loss.
Thanks.
EDIT
Ok a little update. I will manage and merge my records before using SQLbulkCopy. Is it possible to get a list of what succeeded and what failed... or is it a case of ALL or nothing? I presume there is no other alternative to SQLbulkCopy but to do updates?
it would be ideal to be able to Insert everything and the ones that failed are inserted into a temp table ... hence i only need to worry about correcting the ones in my failed table as the others i know are all OK
Since you need to process that data into a DataTable anyway (unless you are writing a custom IDataReader), you should merge the records before giving them to SqlBulkCopy; for example (in pseudo code):
/* create empty data-table */
foreach(row in list) {
var row = /* try to get exsiting row from data-table based on id */
if(row == null) { row = /* create and append row to data-table */ }
else { merge non-trivial properties into existing row */
}
then pass the DataTable to SqlBulkCopy once you have the desired data.
Re the edit; in that scenario, I would upload to a staging table (just a regular table that has a schema like the uploaded data, but typically no foreign keys etc), then use regular TSQL to move the data into the transactional tables. In addition to full TSQL support this also allows better logging of operations. In particular, perhaps look at the OUTPUT clause of INSERT which can help complex bulk operations.
You can't do updates with bulk copy (bulk insert), only insert. Hence the name.
You need to fix the data before you insert them. If this means you have updates to pre-existing rows, you can't insert those as that will generate the key conflict.
You can either bulk insert into a temporary table, and run the appropriate insert or update statements, only insert the new rows and issue update statements for the rest, or delete the pre-existing rows after fetching them and fixing the data before reinserting.
But there's no way to persuade bulk copy to update an existing row.

Categories

Resources