tags:

views:

588

answers:

6

We have a database (SQL Server 2005) which we would like to get under source control. As part of that we are going to have a version table to store the current version number of the database. Is there a way to limit that table to only holding one row? Or is storing the version number in a table a bad idea?

Ended up using this approach:

CREATE TABLE [dbo].[DatabaseVersion]
    (
     [MajorVersionNumber] [int]  NOT NULL,
     [MinorVersionNumber] [int]  NOT NULL,
     [RevisionNumber] [int]  NOT NULL
    )
GO

Insert DataBaseVersion (MajorVersionNumber,  MinorVersionNumber,  RevisionNumber) values (0, 0, 0)
GO

CREATE TRIGGER DataBaseVersion_Prevent_Delete
ON DataBaseVersion INSTEAD OF DELETE
AS
BEGIN
    RAISERROR ('DatabaseVersion must always have one Row. (source = INSTEAD OF DELETE)', 16, 1) 
END
GO

CREATE TRIGGER DataBaseVersion_Prevent_Insert
ON DataBaseVersion INSTEAD OF INSERT
AS
BEGIN
    RAISERROR ('DatabaseVersion must always have one Row. (source = INSTEAD OF INSERT)', 16, 1) 
END
GO
+5  A: 

Use a trigger.

Otávio Décio
Trigger was my first thought too. On Insert see if the entry exists and just fail out, or ideally perform an update instead using a stored proc.
Adam
I actually ended up using this approach. Maybe you could change your answer to have a little more detail though? Would be helpful.
Ej
+1  A: 

Not at all. You can simply add another, ascending column to that table (date, id, whatever), and then order the query by that other column descendingly and limit the result to 1 row:

SELECT v.version FROM version v ORDER by v.date DESC LIMIT 1;

This way you even get a history of when each version was reached.

Edit:

The above sql query wouldn't work on SQL Server since it doesn't support the LIMIT statement. One would have to circumvent that deficiency, possibly as described in this "All Things SQL Server" blog entry.

Ole
LIMIT is not SQL Server
Matt Rogish
I was not aware of that. Thanks.
Ole
SELECT TOP 1 v.version FROM version v ORDER by v.date DESC
recursive
+5  A: 

Generalize the table to hold "settings" and make it a key/value pair

CREATE TABLE Settings (Key nvarchar(max), Value nvarchar(max))

Then make a unique index on Key.

CREATE UNIQUE INDEX SettingsIDX ON Settings (Key)

That will create a table with unique key value pairs, one of which can be Version.

INSERT INTO Settings (Key, Value) VALUES ('Version','1');
WOPR
I've done this myself, but it's not my first choice: 1) nvarchar(max) seems a little large for the key. 2) The value is not typed.
Joel Coehoorn
The Setting table is typically quite small so the size isn't really an issue. I use text fields for version numbers because it allows things like "1.0.0.4"... and I've never needed to multiply version numbers...
WOPR
A: 

By creating the one allowable original row as part of the database initialization script, and (also in that script) removing Insert permissions to that table for all logins (Only Updates will be allowed)

You might also want to disallow deletes as well...

Charles Bretana
I don't like this solution as it depends on effective permissions management for the correct functioning of the logic.The table should enforce it.
WOPR
out of curiousity, why?
Charles Bretana
My reasoning is that if the table enforces it, it's common for all users, even SA etc. If an admin adds a user and mucks up the permissions, it will still work.Your approach would be better if some users were allowed to add dupicates, but not others (imho).
WOPR
Also if your deploying this database to another server, then you have to remember to setup the user accounts properly. (likely to fail). A 'settings' table like Kieran suggests is way more flexible and can open up more effective resource usage. 1 table with 1 row, might as well XML file it.
Adam
I guess if you're not familiar with this technology then it will be strange for you... I personally use permissions a great deal, and find them intuitive and quite appropriate in certain scenarios - like this. And I don't apply them to users, but to application logins... and these are scripted.
Charles Bretana
+1  A: 

Based on your comments to other responses, it seems that:

  1. You don't want users to just modify the value.
  2. You only ever want one value returned.
  3. The value is static, and scripted.

So, might I suggest that you script a function that returns the static value? Since you'll have to script an update to the version number anyway, you'll simply drop and recreate the function in your script when you update the database.

This has the advantage of being usable from a view or a procedure, and since a function's return value is read-only, it can't be modified (without modifying the function).

EDIT: You also wouldn't have to worry about convoluted solutions for keeping a table constrained to one row.

Just a suggestion.

Mike Hofer
This is a good solution.
WOPR
Yes I agree, also a good solution. Though I think either the table limited to one row or a function are equally good. Perhaps semantically though I prefer the table as a version number feels like a piece of data rather than functionality, (but thats only a small afterthought).
Ej
A: 

Keeping a version number for the database makes total sense. However I prefer to have a Version table that can contain multiple rows with fields for the version number, the time the update occured and the user that performed the upgrade.

That way you know which upgrade scripts have been run and can easily see if they have been run out of sequence.

When you want to read the current version number you can just read the most recent record.

If you only store one record you have know way of knowing if a script has been missed out. If you want to be really clever you can put checks in you upgrade scripts so they won't run unless the previous version of the database is correct.

Martynnw