views:

73

answers:

6

I want to store a single row in a configuration table for my application. I would like to enforce that this table can contain only one row.

What is the simplest way to enforce the single row constraint ?

+3  A: 

You can implement an INSTEAD OF Trigger to enforce this type of business logic within the database.

The trigger can contain logic to check if a record already exists in the table and if so, ROLLBACK the Insert.

Now, taking a step back to look at the bigger picture, I wonder if perhaps there is an alternative and more suitable way for you to store this information, perhaps in a configuration file or environment variable for example?

John Sansom
+1 - I can see how the trigger would work, and maybe I will fall back on that approach, but I like Damien's simple constraint. There is an interesting discussion to be had on what type of configuration data belongs in the config file and what belongs in the DB. In this case I think the DB is the correct place. No doubt I will live to regret this... :-)
Martin
A: 
IF NOT EXISTS ( select * from table )
BEGIN
    ///Your insert statement
END
Sachin Shanbhag
A: 

You can write a trigger on the insert action on the table. Whenever someone tries to insert a new row in the table, fire away the logic of removing the latest row in the insert trigger code.

Karan
+4  A: 

You may want to rethink this strategy. In similar situations, I've often found it invaluable to leave the old configuration rows lying around for historical information.

To do that, you actually have an extra column creation_date_time (date/time of insertion or update) and an insert or insert/update trigger which will populate it correctly with the current date/time.

Then, in order to get your current configuration, you use something like:

select * from config_table order by creation_date_time desc fetch first row only

(depending on your DBMS flavour).

That way, you still get to maintain the history for recovery purposes (you can institute cleanup procedures if the table gets too big but this is unlikely) and you still get to work with the latest configuration.

paxdiablo
+1: I hear what you are saying, but I prefer to record the history of changes in separate audit tables.
Martin
+1: For sharing the interesting idea of implementing an audit trail.
John Sansom
+7  A: 

You make sure one of the columns can only contain one value, and then make that the primary key (or apply a uniqueness constraint)

CREATE TABLE T1(
    Lock char(1) not null,
    /* Other columns */,
    constraint PK_T1 PRIMARY KEY (Lock),
    constraint CK_T1_Locked CHECK (Lock='X')
)

I have a number of these tables in various databases, mostly for storing config. It's a lot nicer knowing that, if the config item should be an int, you'll only ever read an int from the DB.

Damien_The_Unbeliever
+1. This is the approach Celko uses for an auxiliary constants table in "SQL for Smarties"
Martin Smith
This is about as simple as it gets. Thanks.
Martin
+1: Interesting solution. I had not seen this before so thanks for sharing. Always the way, easy when you know how....
John Sansom
Here's a follow up question to think over. What is the primary key of this table? :)
dportas
@dportas - I believe it's natural key would be {}, but we're not allowed to implement that in SQL.
Damien_The_Unbeliever
Exactly so! By definition Lock cannot be a key because a key must be irreducible. But SQL has no syntax that allows for the empty set being a key. So in this case PRIMARY KEY != primary key.
dportas
@dportas - I'd be a fraud if I didn't admit to reading c.d.t and TTM, among other sources, so your question was a bit of a gimme.
Damien_The_Unbeliever
+1  A: 

I usually use Damien's approach, which has always worked great for me, but I also add one thing:

CREATE TABLE T1(
    Lock char(1) not null DEFAULT 'X',
    /* Other columns */,
    constraint PK_T1 PRIMARY KEY (Lock),
    constraint CK_T1_Locked CHECK (Lock='X')
)

Adding the "DEFAULT 'X'", you will never have to deal with the Lock column, and won't have to remember which was the lock value when loading the table for the first time.

ACB
+1 - nice tip, thanks.
Martin