Generate ids for a database based on certain information - c#

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.

Related

How to keep ID from increasing and use first available unused ID instead?

When I delete an Item from my table I want that when adding next Item in that table that item should use the first available unused ID. How can i achieve this? When I deleted all of the Items and created new ones this happened:
In this case it would be much better that Item Id 21 was 1.
I would recommend against modifying (what looks like) a primary key column. As an example of side effects: if other entities are referencing the primary column, this will fail, or break the relations. Also, you potentially need to renumber the whole table for every delete that is executed.
If you want a dynamic auto-incremented number, you can use row_number() in a view:
create view myview as
select
row_number() over(order by item_id) item_id,
title,
description
from mytable
You can then query the view instead of the table, which gives you an always up-to-date increment number.
You mean you want to rearrange the Autoincerment ID back to 1? I believe this will solve it Reorder / reset auto increment primary key

How to generate an integer unique id in a multi-user application without duplication in C#/SqlServer?

Scenario
I want to generate a unique integer key (not a database primary key) by extracting max() and incrementing it by one. Then I want to use that integer key for insert/update operations in one or more tables. I prefer to do this in C# code but if there's no other option then I could go for SQL batch statements or inside a stored procedure etc as well.
Question
Since multiple users can be doing this at the same time, how do I ensure that no two users get the same max()?
Sample pseudocode
Let's say there are two tables - Employee (Columns: EmpId, BatchId, Name) and MiscData (Columns: EmpId, BatchId).
Below is the C# inspired pseudocode that shows one implementation of this scenario -
void DoOperation(int empId, string[] names)
{
int maxBatchId = repository.GetMaxBatchId(); //GetMaxBatchId() basically executes select max(BatchId) from Employee
maxBatchId++;
foreach(string name in names)
command.ExecuteNonQuery("insert into Employee values (" + maxBatchId + ", '" + name + "')");
command.ExecuteNonQuery("insert into MiscData select EmpId, " + maxBatchId + " where EmpId = " + empId);
}
The method DoOperation above can be doing whatever database operations based on the value of maxBatchId + 1.
If more than one users run DoOperation(...) at the same time, they're likely to get exactly same maxBatchId. How do I ensure that only a single instance of this method can run at one time?
You can use Sequence in SQL Server
CREATE SEQUENCE testseq
START WITH 1
INCREMENT BY 1 ;
SELECT NEXT VALUE FOR testseq
I cannot use sequence in SQL server because I cannot have gaps in the numbers due to regulatory rules.
This is an old post but while I was reading this to find an answer I thought of a different way that might actually work and posting it here to help others.
If you create a new column in the table and set the identity insert to true and 1,1 when you save the record it will be unique.
BUT you may not be able to modify the database table as it may affect other areas...
So what you can do is create a new table with three fields: ID, Username, CurrentDateTime.
The ID field is incrementing(1,1)
When you want a unique ID simply add a record to that table with the current date and time and the username which will generate you a unique ID and you can
Select Top 1 ID where UserName = XXX order by DateTime Desc
That will give you that users last entry in this table which you can use as your unique integer key
Pros:
Unique identifier that will never duplicate in a multi-user
environment
If you have records already created you can insert them
into this table after the fact and start using this method.
Cons: An extra table
The extra table will take almost no space in your database and any old systems won't be affected by this new table. New systems might complain that the table should not exist and of course this needs to be tested.

Getting the Average in ROWS c#

i have a sql server database with table. These are
1stAP_TB, 2ndAP_TB, 3rdAP_TB, 4thAP_TB, 1steng_TB, 2ndeng_TB, 3rdeng_TB,
4theng_TB
all in them are in row. The numbers will be solve individually on specific column. Now, i need to know how am i going to get the average of 1stAP_TB, 2ndAP_TB, 3rdAP_TB and 4thAP_TB while there are in rows.
Also, there are multiple data that will be save inside the database. I am using C# programming language.
Try below method
create table aveexample
(a1stAP_TB int,
a2ndAP_TB int,
a3rdAP_TB int,
a4thAP_TB int,
a1steng_TB int,
a2ndeng_TB int,
a3rdeng_TB int,
a4theng_TB int
)
Sample data
insert into aveexample values(1,2,3,4,5,6,7,8)
insert into aveexample values(11,22,33,44,55,66,77,78)
insert into aveexample values(2,3,1,4,10,10,45,5)
Method 1
select *, (select AVG(totaldata)
from (values(a1stAP_TB),
(a2ndAP_TB),(a3rdAP_TB),(a4thAP_TB),(a1steng_TB),
(a2ndeng_TB),(a3rdeng_TB),(a4theng_TB)) total(totaldata))as average
from aveexample
Method 2
select ((a1stAP_TB)+
(a2ndAP_TB)+(a3rdAP_TB)+(a4thAP_TB)+(a1steng_TB)+
(a2ndeng_TB)+(a3rdeng_TB)+(a4theng_TB))/8 as Average
from aveexample
It is difficult to give concrete advice given the very limited description in the question, but from the description and comments so far, it seems to me like the database needs to be redesigned to better fit your requirements. First, you have no ID field, so there is no way to differentiate one row from the next. Then, what you are left with is a series of repeated values. The clue here is that you have "1st", "2nd", "3rd" in the column names. That's probably a sign that those columns need to be moved into rows of a related table. It may not instantly seem to be the best approach, but this is called "First Normal Form" and is a typical best practice with SQL databases. See also Database Normalization Basics.
It seems to me that what you have here is some entity (which you haven't mentioned in your question) that has a number of values associated with it. The 'entity' here should be given a unique ID and then all of the values for that entity stored with its ID.
You might have a table with the following columns:
CREATE TABLE MyItems (
ID int NOT NULL,
Sequence int NOT NULL,
Value int NOT NULL,
CONSTRAINT PK_MyValues_ID_Sequence PRIMARY KEY
(ID,Sequence)
)
Note: ID + sequence forms the unique primary key for the table and makes every row unique. This also lets you keep track of what order the items were added in. This may or may not be important to you but every table should probably have a unique primary key.
Your data table would then look something like this (the example represents two different entities, the first having 4 values and the second having 3 values):
It's difficult to show a sensible example without knowing more about the application and what it does... but with this table design you have a basis from which to add values one at a time, as you said you needed, and a way to query them back. You can use grouping to produce things like totals and averages, or you can do that in code by iterating over the results of a query or in a LINQ statement.
You can then compute the average for an entity of a given ID using a LINQ query along the lines of:
var average = MyItems.Where(p=>p.ID == 1).Average(q=>q.Value);
As an example of the flexibility of this sort of approach, you could just as easily compute the average of every second value entered across the entire database:
var averageOfSecondItems = MyItems.Where(p => p.Sequence == 2).Average(q => q.Value);
The example I've shown deals with one type of value. In your question it appears that you might have two different types of value. There are several ways you could handle that - for example you could add another column to the table if the values are always entered in pairs, or you could create a second table to hold the separate values. Again, it's hard to make a recommendation based on the limited information given.
If putting your data into First Normal Form seems like a lot of work, then your application might be a better fit for a document database ("NoSQL" database), but that is really a different question. In the question, a SQL database was specified so I've concentrated on that.

Order rows with Entity Framework

I'm using EF in order to insert and retrieve info from DB,
there is any way to insert new row but at the specified position,
Like i have 10 rows with IDs ranging from 0 to 9 and new row i'm inserting will be on the position 4?
I'm using ASP.NET MVC 5 and LINQ.
Thank you.
The simple answer is no. Order has no meaning unless it's explicit in a database system. Sure in most cases I can insert into a table and pull from this exact table and get the exact order as it was inserted, but this is undefined...and the only guarantee is to use an ORDER BY clause.
If you are talking about changing an auto number property, this is also not possible, the database does not go back and fill in gaps with id numbers. If numbering is critical and important to you don't set the auto-increment property.
Your ID and order position are different things.
For ID you use an autonumeric and you shouldnt mess with that.
For order you use another column and run a trigger when a new row is insert update all the rows
So when the new row is inserted with order_id = 4 all the rows get update
something like
UPDATE table
set order_id = order_id +1
when order_id >= 4
So, I would do so quickly:
I would plan the database to not auto increment primary key and saving would so that the id is attributed according to the specific location. Obviously put an IF to verify that it is available, and if I would start a review cycle to the cascade of subsequent ID or positioning the value traded in the end.
for example
MyTable table = myDb.MyTable.Find(id); //position
if (table==null)
{ table.id=position; table.Field=value; myDb.SaveChanges() }
else
{
var temp = table.id;
var max = table.count(x=> x.id).value;
table.id=max+1;myDb.SaveChanges();
table.id=id; table.Field=value; myDb.SaveChanges();
}
sorry if translate is no good! ;-)

How to update autoincremented id when delete row in table?

I am creating application that uses MYSQL database in C#. I want to delete row and update autoincremented value of id in table. For example, I have table with two columns: id and station, and table is station list. Something like this
id station
1 pt1
2 pt2
3 pt3
If i delete second row, after deleting the table looks something like this:
id station
1 pt1
3 pt3
Is there any way that I update id of table, for this example that id in third row instead value 3 have value 2?
Thanks in advance!
An autoincrement column, by definition, should not be changed manually.
What happen if some other tables use this ID (3) as foreign key to refer to that record in this table? That table should be changed accordingly.
(Think about it, in your example is simple, but what happen if you delete ID = 2 in a table where the max(ID) is 100000? How many updates in the main table and in the referring tables?)
And in the end there is no real problem if you have gaps in your numbering.
I suggest you don't do anything special when a row is deleted. Yes you will have gaps in the ids, but why do you care? It is just an id.
If you change the value of id_station, you would also need to update the value in all tables that have an id_station field. It causes more unnecessary UPDATES.
The only way to change the value of the id column in other rows is with an UPDATE statement. There is no builtin mechanism to accomplish what you want.
I concur with the other answers here; normally, we do not change the value of an id column in other rows when a row is deleted. Normally, that id column is a primary key, and ideally, that primary key value is immutable (it is assigned once and it doesn't change.) If it does change, then any references to it will also need to change. (The ON UPDATE CASCADE for a foreign key will propagate the change to a child table, for storage engines like InnoDB that support foreign keys, but not with MyISAM.
Basically, changing an id value causes way more problems than it solves.
There is no "automatic" mechanism that changes the value of a column in other rows when a row is deleted.
With that said, there are times in the development cycle where I have had "static" data, and I wanted control over the id values, and I have made changes to id values. But this
is an administrative exercise, not a function performed by an application.

Categories

Resources