So I have a table of Employees that has the fields EmployeeId (GUID), EmployeeNumber (string), and IsActive (bit) among others. I would like the SQL Server to enforce a rule where any number of records can have the same employee number, but only one record of a given employee number may have the IsActive bit set at a time.
I'm trying to determine the most efficient or effective way to have the SQL server do this, but so far I've only come up with the idea of using a Trigger. Considering the trigger, I was thinking I would probably need to use a cursor to iterate each of the rows in the inserted table and check each row individually. And this has me worrying about performance.
I've considered using a constraint, but clearly I can't use a UNIQUE constraint because I'd only be allowed two records. Is there a better way to handle this rather than a trigger?
The links below explain how to enforce conditional unique constraints based on bit/boolean fields
SQL Server
- conditional unique constraint
Oracle
- Conditional unique constraint in oracle db
Postgresql
- PostgreSQL: Conditional unique constraint
MySQL
- Doesn't seem to be possible
A (not too elegant) workaround for this would be to have a numeric field {activity_level} so {EmployeeNumber, activity_level} is unique. Then you should define MAX_INTEGER, or 0, or MIN_INTEGER or whatever value you want as the active-flag (employees with this value are active, all other are not). I know it is not very clean, but it could do the trick if you don't find anything better...
Related
I want to enforce a business rule on my database table to ensure that a row can't be inserted if the table already contains rows meeting a certain criteria.
Was wanting to use a CHECK constraint but suspect this may have to be done via a trigger.
Is there a way to do this via a CHECK constraint? OR is there another way to do this at the database level without using a trigger?
Depending on your specific criteria (which you haven't shared yet), you may be able to do a unique filtered index.
This is normally faster than functions or other workarounds.
General format would be:
CREATE UNIQUE NONCLUSTERED INDEX ix_IndexName ON MyTable (FieldstoIndex)
WHERE <filter to only include certain rows>
I use SQL Server 2008, and I have a table with a column of type varchar(X) which I want to have unique values.
What is the best way to achieve that? Should I use unique constraint and catch an exception, or should I pre-check before inserting a new value?
One issue, the application is used by many users so I guess that pre-checking might result in race condition, in case that two users will insert the same values.
Thanks
Race condition is an excellent point to be aware of.
Why not do both? - pre-check so you can give good feedback to the user, but definitely have the unique constraint as your ultimate safeguard.
Let the DB do the work for you. Create the unique constraint.
If it's a requirement that the values be unique --- then a constraint is the only guaranteed way to achieve that. reliable so-called pre-checking will require a level of locking that will make that part of your system essentially single user.
Use a constraint (UNIQUE or PRIMARY KEY). That way the key is enforced for every application. You could perform additional checks and handling in a store procedure if you need to - either before or after the insert.
I am a PHP developer with little Oracle experience who is tasked to work with an Oracle database.
The first thing I have noticed is that the tables don't seem to have an auto number index as I am used to seeing in MySQL. Instead they seem to create an index out of two fields.
For example I noticed that one of the indexes is a combination of a Date Field and foreign key ID field. The Date field seems to store the entire date and timestamp so the combination is fairly unique.
If the index name was PLAYER_TABLE_IDX how would I go about using this index in my PHP code?
I want to reference a unique record by this index (rather than using two AND clauses in the WHERE portion of my SQL query)
Any advice Oracle/PHP gurus?
I want to reference a unique record by this index (rather than using two AND clauses in the WHERE portion of my SQL query)
There's no way around that you have to use reference all the columns in a composite primary key to get a unique row.
You can't use an index directly in a SQL query.
In Oracle, you use the hint syntax to suggestion an index that should be used, but the only means of hoping to use an index is by specifying the column(s) associated with it in the SELECT, JOIN, WHERE and ORDER BY clauses.
The first thing I have noticed is that the tables don't seem to have an auto number index as I am used to seeing in MySQL.
Oracle (and PostgreSQL) have what are called "sequences". They're separate objects from the table, but are used for functionality similar to MySQL's auto_increment. Unlike MySQL's auto_increment, you can have more than one sequence used per table (they're never associated), and can control each one individually.
Instead they seem to create an index out of two fields.
That's what the table design was, nothing specifically Oracle about it.
But I think it's time to address that an index has different meaning in a database than how you are using the term. An index is an additional step to make SELECTing data out of a table faster (but makes INSERT/UPDATE/DELETE slower because of maintaining them).
What you're talking about is actually called a primary key, and in this example it'd be called a composite key because it involves more than one column. One of the columns, either the DATE (consider it DATETIME) or the foreign key, can have duplicates in this case. But because of the key being based on both columns, it's the combination of the two values that makes them the key to a unique record in the table.
http://use-the-index-luke.com/ is my Web-Book that explains how to use indexes in Oracle.
It's an overkill to your question, however, it is probably worth reading if you want to understand how things work.
I was just reading How to avoid a database race condition when manually incrementing PK of new row.
There was a lot of good suggestions like having a separate table to get the PK values.
So I wonder if a query like this:
INSERT INTO Party VALUES(
(SELECT MAX(id)+1 FROM
(SELECT id FROM Party) as x),
'A-XXXXXXXX-X','Joseph')
could avoid race conditions?
Is the whole statement guaranteed to be atomic? Isn't in mysql? postgresql?
The best way to avoid race conditions while creating primary keys in a relational database is to allow the database to generate the primary keys.
It would work on tables which use table-level locking (MyISAM), but on Innodb etc, it could deadlock or produce duplicate keys, I think, depending on the isolation level in use.
In any case doing this is an extremely bad idea as it won't work well in the general case, but might appear to work during low-concurrency testing. It's a recipe for trouble.
You'd be better off using another table and incrementing a value in there; that's more likely to be race-free / deadlock-free.
No, you still have a problem, as, if two queries try to increment at the same time there may be a situation where the inner select is done, then another query is processed.
Your best bet, if you want a guarantee, if you don't want the database doing it, is to have a unique key on there.
In the event that there is an error in inserting, then try your query again, and once the primary key is unique it will work.
In this case, your best bet is to first insert only the id and any other non-null columns, and then do an update to set the nullable columns to whatever is correct.
I'm a little rusty with my triggers and what not and am trying to figure out this problem for a class:
In a database TEST, tables do not have the option of the IDENTITY feature. In other words, when we insert a row into the table “Users”, we would like the primary key “UserID” to auto-increment. Please suggest a workaround to implement this feature without such a built-in functionality.
(Hint: You may still use functions, stored procedures, sequences, triggers, etc)
Use an Int column for the table Primary Key called ID.
You can then use an instead of Insert Trigger, to populate/calculate the value to be inserted for ID.
The trigger will determine what the maximum existing ID is for the table in question (using select MAX ID from TableA) and then increment it by 1 for each record to be inserted.
If there are no records in the table then the ID value is 1.
You use a sequence, and it's very common with Oracle, which does not (or did not once, it may have changed) have identity columns. Since this is homework I'll let you figure out the rest from here.