Prevent non-primary key column to have duplicates - database

I read in this site that it is recommended use an auto-number ID rather than username for primary keys because it will not change. However, how do I prevent the database to have only unique usernames. I am using Access.

In Access, open the table in Design View and click on the username field. In the "Field Properties" pane at the bottom, select Yes (No Duplicates) for the Indexed property. That will prevent duplicate username values from being entered.

Set unique constraint on username column (some main table for user).
You always can validate before inserting (for prompting user) or on trigger before insert.

I take it you've already made the table, so run this query:
ALTER TABLE users
ADD UNIQUE(username)
Change table name and column name in the query to match your table and column name, obviously.
Here's the reference: http://www.w3schools.com/sql/sql_unique.asp

Related

How to default a column value from another table?

Imagine I have two tables named Account and AccountStatus. In the Account table I got my account data including the accountStatusID by a Foreign Key referencing AccountStatus Primary Key.
In the AccountStatus table I insert all my possible user status (E.g. Account Non-Activated, Account Activated, Account Banned, etc).
Now my problem is when I insert an Account, I want my default value from AccountStatus to be "Account Non-Activated" which have some ID. I can't figure out how I can make this happen without hardcoding, like an Insert Trigger getting Select ID From AccountStatus WHERE AccountStatusTitle = "Account Non-Activated" and set the field (accountStatusID) from Account table.
The simplest option here would be to hard-code the ID using a default constraint. If however you really want to avoid this then I would recommend the following:
a) Add an 'IsDefault' column to your AccountStatus table
b) Add a default constraint to the AccountStatusId field on the Account Table which calls a function which will return the id of the AccountStatus where the IsDefault column is set to true.
Hope this helps.

Resetting the primary key to 1

I have a script for microsoft sql server database which has hundreds of tables and tables contains data as well. This is the database of a web application.what I want to do is to delete the previous records and reset the primary key to 1 or 0.
I have tried
`DBCC CHECKIDENT ('dbo.tbl',RESEED,0); `
but it does not work for me as in most of the tables the primary key is not identity.
I can not truncate the table as its primary key is being used as FK in many other tables.
I have also tried to add the identity specification in the primary key of the table and run the checkident query and then changing it back to non-identity spec, but after adding the record again it starts from where it left.
Making changes in the code is not an option for me.
please help.
According with your question I am not sure about the main objective, Why? If you need truncate a lot of tables and change their structures to have an Identity property why you can't disabled the FK? . In the past I have used an standard process for rebuild a table and migrate all the information, this represent a group of steps, I would try to help you but you should follow the next steps.
Steps:
1) Disable FK for alter the structure of your tables. You can get the solution for this task in the next link:
Temporarily disable all foreign key constraints
2) Alter the table with the new property Identity, this is a classic process of ALTER TABLE xxxxxx.
3) Execute the syntax that previously posted :
DBCC CHECKIDENT ('dbo.tbl',RESEED,0);
Try to follow this path and if you have any problem only ask us.
You can not truncate table that have relation. You shoud remove relation firstly.
My understanding of this question:
You have a database with tables that you want to empty and next have them use primary key values starting at 0 or 1.
Some of these tables use an identity value and you already have a solution for those (you know you can find out which columns have an identity by using the sys.columns view? Look for the is_identity column).
Some tables do not use an identity but get their pk values from an unknown source, which we can't modify.
The only solution I see, is creating an after insert trigger (or modifying) on those tables that subtracts from the new pk value.
E.g.: your "hidden generator" will generate a next value 5254, but you want the next pk value to become one:
CREATE TRIGGER trg_sometable_ai
ON sometable
AFTER INSERT
AS
BEGIN
UPDATE st
SET st.pk_col = st.pk_col - 5253
FROM sometable AS st
INNER JOIN INSERTED AS i
ON i.pk_col = th.pk_col
END
You'll have to determine the next value and thus the "subtract value" for each table.
If the code also inserts child records into tables with a foreign key to this table, and uses the previously generated value, you have to modify those triggers as well...
This is a "last resort" solution and something I would recommend against in any scenario that has other options. Manipulating primary key values is generally not a good idea.

SET IDENTITY_INSERT ON/OFF needed on application server, but ALTER permission seems dangerous. Suggestion?

We are building a multi-user web app where they need an unique postId for post they create. Each post has (userId, postId) as the compound primary key.
Right now, postId is an identity value, but because of the need to support some operations that require postId to be inserted as is (no re-numbering), we decide to use SET IDENTITY_INSERT ON/OFF.
However, our DBA told us that such operation is not meant be used by the application server because the ALTER permission requirement:
Permissions
User must own the table or have ALTER permission on the table.
https://msdn.microsoft.com/en-ca/library/ms188059.aspx
If the application server got hacked, with ALTER permission it seems rather risky. Our DBA suggests us to not use identity value at all, and locally generate an unique postId per user.
Can SET IDENTITY_INSERT ON be left on globally?
If it can't be left on globally, does avoiding identity value and use local generation of postId (per user) with max(postId)+1 per user make sense? We much prefer to use identity value if possible because we are worried about possible deadlocks and performance issues associated with custom postId generation.
Starting with SQL Server 2012 you can use sequences like in Oracle. You may be better off with those. First, create the sequence:
CREATE SEQUENCE mySeq AS LONG START WITH 1 INCREMENT BY 1;
GO
Then have the table's primary key default to the next sequence value (instead of being an IDENTITY value):
CREATE TABLE myTable (
myPK LONG PRIMARY KEY DEFAULT (NEXT VALUE FOR mySeq),
myWhatever...
);
If you don't specify a PK value with an INSERT you'll get a unique, generated sequence value. It's basically the same behavior as an IDENTITY. But if you want to specify a PK value you can, as long as you don't violate the primary key's uniqueness - but again, that's the same behavior as an IDENTITY with SET IDENTITY INSERT ON.
It sounds like you need to evaluate your database design if this is possible. A post should be a fixed entity and an identity column as a single primary key should be sufficient. In your comment you mentioned that you might want to copy posts from one user to another user. If you want to split the post so that user1 and user2 can independently control their own versions of the post, then it's just a matter of copying all the post attributes into a new record (which creates a new identity key) and then updating the new records user attribute from User1 to User2. But if you want the users to share the same post... then you should do that with a relationship from user to post to avoid the need to maintain duplicate data in your post table. In other words, if you want to assign user1 and user2 to an identical version of the post, then create a relationship table with two fields (Post ID, User ID). This way you can simply add a user to the post by inserting a new record into the relationship table.
Example: Post 1 is owned by user 1. Post 2 is owned by user 1 and 2.
Post Table - Key (Post ID)
(Post ID=1, PostText="This post is important!")
(Post ID=2, PostText="This post is also important!")
Users - Key (User ID)
(User ID=1, Name="Bob")
(User ID=2, Name="George")
Post Users - Key (Post ID, User ID)
(Post ID=1, User ID=1)
(Post ID=2, User ID=1)
(Post ID=2, User ID=2)
This concerns me a little:
"...the need to support some operations that require postId to be inserted as is (no re-numbering)..."
I assume this sort of operation is the exception, and not the norm? I can also only assume that you're inserting the same post with the same Post ID into the same table without deleting the original? It's still not clear WHY you want to do this.
I really don't see why you'd need to worry about changing the Post ID if you're assigning posts to another user. Nothing else changes except the values in the User ID column by the sounds of it. Unless you mean you can have two or more posts with the same Post ID and the same User ID. If so, why?
To answer your questions:
No, IDENTITY_INSERT cannot be set globally. It is a per object, per session setting.
Using MAX(PostID) + 1 doesn't make sense. Is there a reason why IDENTITY(1, 1) doesn't work for the PostID column? You can re-seed if necessary.
Don't use application-generated UUIDs as key values. They make queries so much slower. At worst, use NEWSEQUENTIALID() in SQL Server if you absolutely want to use a UUID. UUIDs unnecessarily bloat tables and indexes, and with the exception of NEWSEQUENTIALID, are query performance killers.
What you could do is have a Primary key column simply called ID, and then a surrogate key called Post ID if that needs to be non-unique. That way, when you copy a post, the copy of the original gets a new ID, but still retains the original Post ID, but with no need to worry about doing anything unnecessary to the PK.
However, without any changes to the application or the DB, what I would suggest is using a stored procedure executed as the owner of the stored proc (which also owns the Posts table) to set IDENTITY_INSERT to ON only when absolutely necessary. Here is an example I've just written:
create procedure dbo.sp_CopyPost
(
#PostID INT
,#UserID INT
)
with execute as owner
as
begin
set nocount on;
set identity_insert dbo.Posts on;
begin tran
insert into dbo.Posts
(
PostID
,UserID
--Whatever other columns
)
values
(
#PostID
,#UserID
--Whatever other values
)
commit tran
set identity_insert dbo.Posts off;
select ##IDENTITY
end
That will do what you want, based on the current wording of your question, and the comments you've made.
If you need to essentially "plug the gaps" in your identity column, you will find Microsoft-recommended queries to do so in section B here:
https://msdn.microsoft.com/en-us/library/ms186775.aspx

use tablockx for insert non duplicable data outside a primary key

In SQL Server I have a table with the following data: first name, last name, birthplace, etc, etc.
The table has an identity ID column (the primary key of the table). In the interface of my application, the user can modify this data until they hit a button named "Close Record", when this happens I have to generate a Closed_Record_ID with syntax year + consecutive_number. For all the records in my table, the order they entered the database (given by the identity ID), may not be the same in wich they were closed, so I have to generate a new consecutive number.
How should I use the Tablockx hint, or what should I do to avoid duplicate consecutive numbers in the Closed_Record_ID column?

Make a varchar(50) column unique

I have a column (which represents an e-mail) in a SQL Server database with varchar(50) as data type and I would like to make it unique (do not allow the same two e-mail addresses). I cannot find a way to make such column unique in SQL Server Management Studio.
How to do that?
In T-SQL it would be
ALTER TABLE MyTable WITH CHECK
ADD CONSTRAINT UQ_MyTable_Email UNIQUE (EmailAddress)
Or as an explicit index
CREATE UNIQUE INDEX IXU_Email ON MyTable (EmailAddress)
Edit: I can't see how to create a constraint in the SSMS GUI: other answers show how to manage indexes. I do only use SQL though, never the GUI for this kind of work
In the Object Explorer under the table right-click the Indexes folder and choose New Index....
In the window that appears enter Index name:, tick the Unique checkbox and add your email field from the Add... button then click OK.
Try this:
ALTER TABLE [dbo].[TableName] ADD CONSTRAINT UNQ__TableName__ColumnName UNIQUE ([ColumnName])
From this:
http://msdn.microsoft.com/en-us/library/ms191166.aspx

Resources