How to delete a row with primary key id? - sql-server

I have a SQL table user. It has 3 columns id(set as primary and Is Identity as Yes), name and password. When I enter data to the table the id became incremented. But on delete query only name and password will be deleted. I need to delete a particular row including the id.
For example:
id:1 name:abc password:123
id:2 name:wer password:234
id:3 name:lkj password:222
id:4 name:new password:999
I need to delete the third column ie, id:3 name:lkj password:222 . But after deleting this row, the table should be shown as below.
id:1 name:abc password:123
id:2 name:wer password:234
id:3 name:new password:999

From the additional information you have provided it shows you do not understand the IDENTITY data type. As others, including myself, have said numbers are not re-used.
You should also avoid changing primary keys just because a row was deleted.
It would seem you need a row number, don't use the key for this. Create a view using the ROW_NUMBER function, something like
SELECT ROW_NUMBER() OVER (Order by id) AS row_number, name, password, ...
FROM [Your_Table]

As #Tony said, once a number has been used, it isn't available anymore. A workaround for this problem is the following:
1. Don't use an Identity field at all. Use just an integer field set as primary key.
2. Declare a trigger which is triggered whenever a new row is inserted.
3. This trigger has to read the the ID of the last inserted row in the table and increment it by one and insert the result in the ID field.
So when you delete this row later, the ID is available again.

If you want to reuse the id later, that is an extremely poor idea. Don;t go down that path. The only ways to do that are either performance problems or are very subject to error when you have race conditions. There is a reason why udntities don't reuse values after all. The id should be meaningless anyway. There is usually no reason why it can't skip values except personal preference. But personal preference should not take precendence over performance and reliability. If you want to dothis because you hate the skipped values then don't. If you are getting this requirement from above, then push back. Tell them that the alternative are more time-consuming and less reliable and far more likely to cause data integrity problems.

Related

Either of 2 columns is always redundant -- is there a better solution?

Say, I want to create a form for a feedback. If a registered user submits a feedback, his email address is used automatically because he's authenticated. If an anonymous user does that, he has to enter his email manually. My table would look like this:
feedbacks(id, user_id, email, body)
As you can see, it has a redundant column: either user_id or email. And for those who's not familiar with the database structure it'll be confusing: why both email and user_id? can they both be null? or both have a value at the same time? in reality, only one of them must have a value, which isn't possibly to achieve on database level using constraints. Also, what if I by mistake insert values in both columns?
Thus, I wonder, is there any way to change its structure so that it's more wise and that issue described above has become resolved? Using a trigger isn't what I'm looking for.
In other words, the issue is "either of 2 columns is always redundant".
If you had several mutually exclusive columns, then you might have a good case for something called entity sub-typing. As it is, there is no good design reason for adding all of the extra overhead of this design pattern.
These are the basic options that you have:
Two mutually exclusive columns in one table - This is your current design. This is a good design because it lets you define a proper foreign key constraint on your user_id. You mention that it may be confusing for people that don't know the database well because the same kind of information might appear in one or the other place in the table. However, it's important to remember that even though both columns contain a string that happens to be in the form of an email address, to your system these things are semantically distinct. One is a foreign key to your user table. The other is a means of contacting (or identifying?) a non-member. You could avoid this apparent confusion in one of two ways: (a) give a more descriptive name to your email column, such as non_member_email or (b) create a view that coalesces user_id and email into a single column for displaying this information to people who would otherwise be confused.
Entity Subtyping - This approach has you create separate tables for logically separate groups of predicates (columns). These are joined together by a supertype table which gives a common primary key for all logical subtypes, as well as holding all other common predicates. You can google around to learn more about this design pattern. As I've already mentioned, this is overkill for your case because you only have one pair of mutually exclusive columns. If you think it's confusing to have this then having three tables (supertype, member subtype, non-member subtype) will really be confusing.
Column Overloading - This approach would have you combine both columns into a single one. This is feasible because you only need room in your table for one email address at a time. This is a terrible idea because it prevents you from creating a declarative referential constraint on user_id which is a very important tool for maintaining your data's referential integrity. It also conflates two semantically different pieces of information, which violates good database design principles.
The best choice is number 1. Don't worry about having two mutually exclusive columns or if you think you can't "comment" your way around the confusion you think this might cause with more descriptive column names, then use a view to hide the "complexity" of storing two things that look similar in two separate columns.
If one must be exclusively filled:
create table feedbacks (
id integer,
user_id text,
email text,
body text,
check ((user_id is null)::int + (email is null)::int = 1)
);
The cast from boolean to integer yields either 1 or 0, so the sum must be 1.
Remove the email field. If the user is registered, enter their user_id as you do now. If the user is not registered, search the user table for an anonymous entry with that email address. If exists, use that user_id. Otherwise, create an entry in the user table named 'Anonymous', storing the address and use the newly created user_id. There are two advantages:
You don't need mutually exclusive fields. As you have already noticed, these can be the cause of a lot of confusion and extra work to keep the data clean.
If an anonymous poster later registers, the existing "anonymous" user entry can be updated, thus preserving the user_id value and preserving all feedback (and any other activity you track for anonymous users) entered before registering. That is, if a user anonymously enters a few feedbacks then registers, the previous feedbacks remain associated with the now named user.
I might misunderstand the question, but why you say it is impossible to do with constraints?..
t=# CREATE TABLE feedbacks (
t(# id integer,
t(# user_id text CHECK (case when email is null then user_id is distinct from null else user_id is null end),
t(# email text CHECK (case when user_id is null then email is distinct from null else email is null end),
t(# body text
t(# );
CREATE TABLE
t=# insert into feedbacks select 1,null,null,'t';
ERROR: new row for relation "feedbacks" violates check constraint "feedbacks_check1"
DETAIL: Failing row contains (1, null, null, t).
t=# insert into feedbacks select 1,'t','t','t';
ERROR: new row for relation "feedbacks" violates check constraint "feedbacks_check1"
DETAIL: Failing row contains (1, t, t, t).
t=# insert into feedbacks select 1,'t',null,'t';
INSERT 0 1
t=# insert into feedbacks select 1,null,'t','t';
INSERT 0 1
t=# select * from feedbacks ;
id | user_id | email | body
----+---------+-------+------
1 | t | | t
1 | | t | t
(2 rows)

CakePHP, getting the id of a record from a db table

I know getting the id of a record from a db table in CakePHP is easy. I want to get the "future" id of a "future" record of a table, that is, I'll insert a record, but before inserting, I want to get its id, which will be generated by db after insertion is completed(the id is int, Auto Increment). Thanks.
Even the database itself doesn't know what ID it's going to use until the very moment after the record is saved.
You can't (in a multi-user system) ask in advance what the ID is going to be because 20 other records may have been inserted between the time you ask what the ID is going to be, and when you insert your record (with an ID that was used 20 records ago.) This is called a 'Race Condition'.
Here's what will happen:
You: DB - what's the next ID please?
DB: (Does a max() on the column) 21!
You: Great! I'll use that!
(meanwhile 20 other records get inserted by other users)
You: Hi DB, I'd like to insert this record using ID 21 like you told me!
DB: Oops - sorry - that ID has already been used :'-(
You don't NEED to know the record in advance. If you structure your save data correctly, and use CakePHP's saveAccociated() method, CakePHP will insert the correct ID as the foreign key value for all your related data.
The only way to have a predictable ID is to create it yourself. Remember - it MUST be non-null and unique (the definition of a primary key).
Save yourself many, many future primary key clashes and stick to the cake method :-)
One option is you can get the current max id from mysql and then just increment the value. If you have alot of operations going on this might cause some trouble with your site. But you could use:
$this->Model->query("SELECT MAX(id) as max FROM `your_table_name`");
This would get you the max id of that table currently then you can do a +1
Another option would be to get the ID after you save, then update your record with that ID. For example cakephp has a method for this.
$this->Model->getLastInsertID();
$this->Model->updateAll($fields, $conditions)
Reference updateAll: http://book.cakephp.org/2.0/en/models/saving-your-data.html#model-updateall-array-fields-array-conditions

What should I use as a primary key for this table?

I'm building a small forum component for a website where sub-forums have different admins and mods responsible for them, and users can be banned from individual sub-forums. The ban table I have looks like this:
_Bantable_
user_id
group_id
start_date
end_date
banned_by
comment
At first I was going to use the first four columns as the primary key, but now I'm wondering if it would matter if I use one at all, since no-one would be banned at the same exact time from the same forum, and regardless I'd still have to check if they were already banned and during what interval. Should I just not use a key here, and simply create an index on the user_id, and group_id and search through those when needed?
It wasn't 100% clear, but it sounds like you want temporary ban functionality on a per user basis for a particular groupId. If this is the case, you should make a composite primary key:
user_id,
group_id,
end_date
This will let you do
SELECT * FROM bantable WHERE user_id=$currentUserToCheck AND group_id=$currentGroupToCheck AND end_date < $currentDate
or something like that
Note: if you want your primary key to be coherent in terms of whatever database design principle you're adhering to, then you can just make the primary key the user_id (because it is indeed a unique identifier), and then make a composite index on the three columns that i specified above.
Be absolutely sure that any queries you run against this table that require individual indexes have those indexes correctly generated.
Do you need the historical record of past bans?
If not, just create a composite PK on {user_id, group_id}. Whatever data is currently in the _Bantable_ determines who is currently banned. When the ban expires, just delete the corresponding row (and consider whether you need the end_date at all1).
If you do need the historic record, put an active ban into your original table as before, but when the ban expires, don't just delete it - instead move it into a separate "history" table, which would have a surrogate PK2 independent from {user_id, group_id} (so a same user/group pair can be in multiple rows) and a trigger that prevents time overlaps (something like this).
1 If this is the date at which the ban is going to end, then you do need it. If this is the date the ban has ended, then you don't - the row will be gone by then.
2 Or alternatively, a PK on {user_id, group_id, start_date}.
Why dont you just take the user_id as primary key? I mean you don't even have to use auto_increment (which obviously would not make any sense in here).
Guessing that you'd request the user_id anyway on login this would probably provide the best performance to look if there is even an entry for banning matters.

Executing Sql Command only once

I have a Database DB with a table name population but with no Primary Key. Means it can have duplication of data. For example: I have 5 families (f1,f2,f3,f4,f5) with different members inside it (and members may have same name). So I can have exactly same type of record in more than 1 row. Now I want to edit just 1 member of the family, but it is editing all the duplicate records. What I want to do is, I just want to Update my Database once and only once. In other words, I want to use UPDATE command to execute just once. How to do it?
I am using Sql Server Express, VS2010, C# 4.0 (if this info matters).
I am pretty sure my problem may sound stupid to some people (probably many). But it is just a dummy of my problem. Any help or suggestion will be greatly appreciated. Thanks
I know it's not exactly what you're asking but seriously, the easiest option is to alter the database to have a primary key and use that. Perhaps an Identity key....
Without that, you could update just one record, but you have no guarantee of which record. This is why primary keys are such as fundamental concept. I suppose this doesn't really matter if they are all the same, so....
If you really want to proceed without a primary key, you need to use the TOP keyword as shown here: How do I update n rows in a table?
Set it to
UPDATE TOP 1 ....
Add an identity column, ID int with auto increment on. Then update using the id's.
CREATE TABLE dbo.Family
(
Id int NOT NULL IDENTITY (1, 1),
FamilyName varchar(50) NULL
)
update dbo.Family set FamilyName = 'xxx' where Id = y
In case you can't add an identity column for some reason:
UPDATE TOP ( 1 ) Families
SET Whatever = 'Your Value', ...
WHERE <Your where clause>
The real answer is: Fix your database design. Every record should have some unique identifier. Add an auto-increment field or something.
To directly answer your question, you can say "update top (1) ..." to only update one record. But without some unique identifier, how do you know which record to update? The program will essentially update a random record. Which takes me back to point 1.
Edit: Whoops, my original answer was for a different engine. Corrected above.

How to store old version of ID String in Database Design?

I am building a small database for a lab. We have some rules to make a ID String for every Item, so i do not want to store it in my database. The problem is that some times changes in data, for example the person response for that item changed, causes the chang of ID String. But i can not correct it for printed docs. How can i store the old version of that ID String.
I may simply do't change it but that will break the rules. Any suggestions?
To expand on Damir's point
A "Smart Key" is what you say when
We have some rules to make a ID String for every Item
You're taking the name of the item, maybe a category code and adding
person response for that item
So if I were responsible for Beakers that item ID might be
GLASSWARE-BEAKER-SPAGE
That 'code' becomes a 'Smart key' when you use it in your database as a Primary Key.
This is an anti-pattern. Like most anti-patterns it's seductive. People like the idea of just looking at the key and knowing what kind of thing it is, what it is called and who do I ask to get more. All that information on a report or shelf-label with just a few characters. But it's an anti-pattern for the reason you mentioned - it has meaning and meaning can be changed.
As Damir suggests, you can store this value in another column that we'd call an ALTERNATE KEY or CANDIDATE KEY... it's unique, it could be a PK but it's not. You'll want a unique constraint on the column but not a Primary Key constraint.
It is important to distinguish between a primary key which is supposed to uniquely identify a row in a table and some kind of a smart key that products in catalogs usually have.
For a primary key use auto-incrementing integer -- very few exceptions to this one.
Add columns for things that you are trying to represent in that smart key, like: Person, Project, Response etc.
Add a separate column for that key and treat it like any other field in the table -- this should keep people who are used to this kind of thinking happy.
Smart key is a misnomer here, from a db-design point, that key is rather dumb.
for example the person response for that item changed, causes the chang of ID String
Looks like the workflow in your lab is broken. IDs should never change. Try to bring this to attention of your superiors.

Resources