Unique, Non-Required Column in SQL Server 2008 - sql-server-2008

Using SQL Server 2008, I have a requirement that email addresses in my user table must be unique, but email addresses are not required in my app. I've tried to make email addresses required, but I just cannot get the customer to budge on this one. What is the best method to create this constraint? If I add a constraint, what does the constraint look like? If I add a before insert trigger, what does that look like?
This application will be running on a multi-server web farm, and there are multiple points of entry. An application-level lock() { } is not a great option. I'm doing a select and verifying that the email doesn't exist from code right before performing the insert operation to give immediate feedback to the user. However, I would really like a database-level solution here. Just in case.
I'm using an ORM (NHibernate with AutoMapping), so I'd rather not insert or update records with a stored procedure.

Use an unique filtered index:
create table Foo (
Id int not null identity(1,1) primary key
, Name varchar(256) null
, Address varchar(max) null
, Email varchar(256) null);
create index ndxFooEmail unique on Foo(Email)
where Email is not null;
This is a sure-shot 100% bullet proof way to guarantee uniqueness of an optional value. The uniqueness will be enforced in the database server, your ORM/DAL does not need to worry with it, simply handle the error if the unique constraint is violated rather than try to duplicate the constraint in the ORM/DAL (is not really possible to do it correctly under concurrency).
See Filtered Index Design Guidelines for more details about SQL Server 2008 filtered indexes.

Related

Getting id generated in a trigger for further requests

I have a table with two columns:
caseId, referring to a foreign table column
caseEventId, int, unique for a given caseId, which I want to auto-increment for the same caseId.
I know that the auto-increment option based on another column is not available in mySql with InnoDb:
MySQL Auto Increment Based on Foreign Key
MySQL second auto increment field based on foreign key
So I generate caseEventId into a trigger. My table:
CREATE TABLE IF NOT EXISTS mydb.caseEvent (
`caseId` CHAR(20) NOT NULL,
`caseEventId` INT NOT NULL DEFAULT 0,
PRIMARY KEY (`caseId`, `caseEventId`),
# Foreign key definition, not important here.
ENGINE = InnoDB;
And my trigger:
CREATE DEFINER=`root`#`%` TRIGGER `mydb`.`caseEvent_BEFORE_INSERT` BEFORE INSERT ON `caseEvent` FOR EACH ROW
BEGIN
SELECT COALESCE((SELECT MAX(caseEventId) + 1 FROM caseEvent WHERE caseId = NEW.caseId),0)
INTO #newCaseEventId;
SET NEW.`caseEventId` = #newCaseEventId;
END
With this, I get my caseEventId which auto-increments.
However I need to re-use this new caseEventId in further calls within my INSERT transaction, so I place this id into #newCaseEventId within the trigger, and use it in following instructions:
START TRANSACTION;
INSERT INTO mydb.caseEvent (caseId) VALUES ('fziNw6muQ20VGYwYPW1b');
SELECT #newCaseEventId;
# Do stuff based on #newCaseEventId
COMMIT;
This seems to work just fine but... what about concurrency, using connection pools etc...?
Is this #newCaseEventId variable going to be shared with all clients using the same connection, can I run into problems when my client server launches two concurrent transactions? This is using mysql under nodejs.
Is this safe, or is there a safer way to go about this? Thanks.
Edit 2020/09/24
FYI I have dropped this approach altogether. I was trying to use the db in a way it isn't meant to be used.
Basically I have dropped caseEventId, and any index which is supposed to increment nicely based on a given column value.
I rely instead on properly written queries on the read side, when I retrieve data, to recreate my caseEventId field...
That is no problem, the user defined variables a per client.
That means every user has its own use defined varoables
User-defined variables are session specific. A user variable defined by one client cannot be seen or used by other clients. (Exception: A user with access to the Performance Schema user_variables_by_thread table can see all user variables for all sessions.) All variables for a given client session are automatically freed when that client exits.
see manul

Error: Duplicate entry '' for key 'email'

I have seen this error with people running php scripts before but this is happending to me in phpmyadmin ??
Error
SQL query:
UPDATE `cl56-goldeng`.`users` SET `email` = '' WHERE `users`.`id` =118
MySQL said: Documentation
#1062 - Duplicate entry '' for key 'email'
It works fine if I give the field another value, but if I clear the field and press enter I get the above error.
The table itself looks like this :
On your table cl56-goldeng.users, the field email was specified on creation to not allow more than 1 of the same value to be allowed into it. This is done using the UNIQUE identifier on table creation in MySQL. You can see more on the UNIQUE identifier at this link.
You have 2 options that you could go about doing.
First would be to remove the unique constraint on the email field. This entirely depends on your logic in your code, but seeing as emails should almost always be unique, this is not suggested.
You can drop a unique key by running the command:
alter table [table-name] drop index [unique-key-index-name];
Second, would be to use NULL instead of an empty string. My assumption is that you are setting an empty string when the users email does not exist. In this scenario, it would be better to use NULL, and then check for that when retrieving data from the database.
You can insert a NULL value by using the NULL identifier in your MySQL statement, like such:
INSERT INTO users (firstName,lastName,email)
VALUES ('Bob','Ross',NULL);
And then check for a NULL value in whatever language you are accessing this data from.
You have a unique constraint on your email field. Either rethink your logic or drop the unique constraint.
Thats because you may have declare the email as unique key, and once you enter one row of empty email, it wont except another empty email

Mysql: Possible to force updating of a second column after updating the first?

I have a Mysql database that stores login data. The passwords and salts are saved as sha512 hashes. Now, should the value in the password column be changed, I would like to implement a condition that the salt MUST be changed, or the mysql command is invalid.
CREATE TABLE loginData(
id int UNSIGNED SERIAL DEFAULT VALUE,
email varchar(64) NOT NULL,
password binary(64) NOT NULL,
salt binary(64) NOT NULL,
PRIMARY KEY(id))
ENGINE=InnoDB;
Now, I was thinking of something like the integrity constraints of foreign keys, but obviously I should not connect the password and salt column as foreign keys. Is there any way to prevent updating only the password column - so a new salt HAS to be given - on the Mysql side? Preventing it only on the side of the accessing code feels incomplete.
One way you can possibly do it is to not actually update your login records for password changes, but to insert new records. You would need a schema change to add a tinyint fieldname named active or similar to store a flag indicating which is active login.
You could then add unique indexes on email/salt and email/password in order to force uniqueness on those combinations, meaning you could never have the same email with the same salt entered and also you could never enter the same email/password combination. Any inserts with same email/salt or email/password would fail. If you don;t need password uniqueness (you can obviously just not add the email/password unique index).
When you lookup the login to actually perform the credential check you would just have to add WHERE active = 1 to your query filter.
You would probably also want to wrap the operation of inserting the new salt & password record and updating the old row to active = 0 within a transaction so that either the entire transaction succeeds or fails, thus preventing cases where users get stuck without a login.
Unless you have multiple systems accessing the database, I wouldn't say preventing it only on the accessing code is incomplete. You can prevent admins from manually updating the data by not giving them the appropriate write rights on the table.
But if you must enforce this in MySQL, you could consider adding a trigger (code which is run when after updating a record), but in case the salt comes from your application, this is probably not feasible. Then the best option is to only provide access to the table through a stored procedure (code residing in the database), which enforces the integrity of the table.
See http://dev.mysql.com/doc/refman/5.6/en/stored-programs-views.html

violation of primary key constraint .Cannot insert duplicate key in object using ADO

we are working on a users apllication using Access2003(VBA) as software language and SQL Server 2005 as database.
We are using ADO method and we encounter a problem.
when users create new record in a ADO Screen and they want to save the record after implementing it they receive this error :
error -2147217873 violation of primary key constraint 'PK_ '.Cannot insert duplicate key in object 'Pk_...'
Any help will be appreciated
Thanks in advance
The problem occures since you can't have two primary keys with the same value.
If you are using Ints as primary key, remember to put auto-increment on it.
If you are using GUID as primary key, you might forget to set the guid to sometheing else than the default empty guid, and there by trying to insert and empty guid twice.
Are you trying to insert a new record with the primary key field having a value that is already in the database. The primary key field must always contain unique values.
Check witch columnt is your PrimaryKey. If you are trying to insert value that already exist then you are getting that error.
you should create your PK value either from your code or on the SQL side. On the SQL side, when creating your database, you have to indicate that default value for "myPrimaryKey" field is uniqueIdentifier, while from code, you could have something like
myRecordset.fields("myPrimaryKey") = stGuidGen()
(check here for the stGuidGen function)
There are some pros and cons to each method. By implementing the SQL method, you do not have to care about generating PKs anymore. By doing it through code, you can store the newly generated value without having to requery the database, and reuse it immediatly in your code, and this can be very useful.
get the property of your primary key column and set the identity property to YES

ms-access could not delete

ms-access is connecting to a local mysql database
the following code returns an error:
Public Function run_sql(strSql As String)
On Error GoTo lblError
CurrentDb.Execute strSql, dbFailOnError
lblExit:
Exit Function
lblError:
MsgBox Err.Number & ": " & Err.Description
Resume lblExit
End Function
strSql = "DELETE FROM tblUsersSubjects WHERE user_id=2007;" - i ran this statement it works perfectly, but access is giving me this error: 3086: Could not delete from specified tables
what is the cause of this error?
table structure is:
CREATE TABLE `tbluserssubjects` (
`user_id` int(11) NOT NULL,
`subject_id` int(11) NOT NULL,
`other` varchar(50) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
please note that i AM able perform the needed delete operation my using the shell, instead of access
From within Access can you open your linked table, tblUsersSubjects, in datasheet view and edit or delete in datasheet view? If not, Access may be treating the connection to your MySql table as read-only. Try deleting the link (in Access; not the actual table in MySql). Then re-link the table in Access and make sure to tell Access which field (or combination of fields) to use as a primary key. If Access isn't aware of a linked table's primary key, the link will be read-only.
After off-line discussions with Alex, I want to add to this answer:
Access originally didn't recognize what to
use as a primary key, so your linked table was read-only from the Access side. I'll guess that was because your CREATE TABLE statement didn't
include a primary key constraint. But I don't actually know the
details of how Access automagically identifies the primary key when linking to an
external table. Perhaps, in the absence of an explicitly defined
primary key, it might look for a field with Not Null and Unique
constraints. But the CREATE TABLE statement didn't include any unique constraints on your MySql
table either.
So when Access is not able to automagically guess the external table's primary key, you must tell it which field (or fields) to use as the primary key ... unless you want the linked table to be read-only from Access.
Is the table in Access or MySql? If it's in MySql it's likely that you don't have the proper permissions to edit table data. Check your connection string that points to the MySql table and make sure that whoever you're connecting as has delete permissions on that table.
Also - does this table have any foreign key relationships to other tables? Perhaps you are trying to delete a record that would cause a violation to some other table's primary key.
Maybe its a case-sensitive issue?
You typed: "tbluserssubjects" for the table structure, but in the query you typed "tblUsersSubjects" (capital U and S)