tags:

views:

142

answers:

4

I need to build a primary key consisting of 3 sections.

  • The first section is 3 letters long and must be an a followed by two digits eg "a00"
  • The second section is a 3 digit unique identifier INCLUDING LEADING ZEROES, example "003"
  • The third section is the year section of the date, eg "2008"

This is all separated with dashes, so a complete key would look like "a00-014-2008"

My solution is to hold three separate columns with the data for each, unformatted, then add the clustered primary key constraint and format it when I need to display it in a view. Is this a good way of going about it? I think there might be a way to make the whole key on update using a trigger but I don't know how. Also how would I concatenate and display it in a view?

Though not a homework question, this will help me academically.

+5  A: 

My question is: do any of these three values have meaning by themselves? Or are they simply components of a primary key? If they have absolutely no other meaning then imho you are better off just creating a single column with the whole value.

Now "meaning" may be hard to qualify. It could mean that it's a particular customer code or something that is searched on or, well, lots of things.

Generally I try and avoid composite keys as they complicate joins and usually make your life difficult with ORMs (that typically view such practice - rightly or wrongly - as "legacy").

If those fields do have meaning then arguably they shouldn't be part of the primary key. I view such a practice as a mistake. I nearly always use auto number columns or sequences for primary key values (known as a "technical key" as opposed to a semantic key).

Given that the user supplies part of this and it needs to be formatted a particular way, I am assuming the key has a whole has a meaning, be it a product code, patient code, booking number or something like that. Would that be correct?

If so, given that and my almost complete preference for technical keys (opinions vary on this issue) I would consider not making this the primary key. Create an auto number field for that. Just make this as acolumn with a unique index that is varchar(12) or whatever.

cletus
+1. Nice answer
Mitch Wheat
Nice indeed, thanks ^_^ If I understand your meaning of meaning, then no, they are all for the purpose of uniquely identifying a record. How would I go about generating this? The first section has to be input by a user with the other two being programatically generated.
Tarks
Yes I apologise for not framing the question correctly, the key as a whole identifies an employee. I'd love to take Occam's razor to this and use an auto incrementing identity column or a primary key but the requirements specify this is needed to interface with a legacy system.
Tarks
+3  A: 
CREATE TABLE mytable (
      first TINYINT NOT NULL CHECK(first BETWEEN 0 AND 99),
      second INT NOT NULL CHECK (second BETWEEN 0 AND 999),
      third INT NOT NULL,
      CONSTRAINT pk_mytable_123 PRIMARY KEY (first, second, third)
      )
GO
CREATE VIEW v_mytable AS
SELECT  'a' + RIGHT('00' + CAST(first AS VARCHAR), 2) AS first,
        RIGHT('0000' + CAST(second AS VARCHAR), 4) AS second,
        third
FROM    mytable
GO

INSERT
INTO    mytable
VALUES  (1, 1, 2008)
GO

SELECT  *
FROM    v_mytable
GO

first  second  third
----   ----    ----
a01    0001    2008

This primary key will hold only INT values, all formatting will be done in the view.

Note that to achive best results in terms of performance, you better create computed columns instead of the view, and create an additional UNIQUE index in these columns:

CREATE TABLE mytable (
      _first TINYINT NOT NULL CHECK(_first BETWEEN 0 AND 99),
      _second INT NOT NULL CHECK (_second BETWEEN 0 AND 999),
      third INT NOT NULL,
      first AS 'a' + RIGHT('00' + CAST(_first AS VARCHAR), 2),
      second AS RIGHT('0000' + CAST(_second AS VARCHAR), 4)
      CONSTRAINT pk_mytable_123 PRIMARY KEY (_first, _second, third)
      )

CREATE UNIQUE INDEX ux_mytable_123 ON mytable (first, second, third)
Quassnoi
The second should be 3 characters long (001 instead of 0001) And maybe add the combination to the view, that seems to be what he's looking for? aka "a01-001-2008"
Andomar
Seems he want to join these values on something got from the outside world. In this case it's better to have 3 columns. Concatenating is easier than parsing.
Quassnoi
I'm getting errors when testing that second table, Unique is misspelled and then it complains of syntax errors, then it says "Computed column 'second' in table 'mytable2' is not allowed to be used in another computed-column definition."
Tarks
Corrected, try now
Quassnoi
I get "Computed Column 'first' in table 'mytable' is invalid for use in 'CHECK CONSTRAINT' because it is not persisted."
Tarks
Corrected, try now
Quassnoi
Seems like a good solution, as long as they don't decide next month that they now need some rows with the first part being "b" + a 2-digit number. You work with the requirements you're given though. :)
Tom H.
A: 

Primary keys traditionally have two purposes: to uniquely identify a row, and to allow other database tables to refer to it. Composite primary keys fulfill the first purpose, but make the second hard, because the other table has to refer to 3 columns. The same goes for ORM systems, or even updates from a web page.

A best practice solution is to make an identity column as primary key. This allows easy reference to the row, and is a scenario that all ORM layers can deal with. Then you add a "unique" index on the three columns that would make up the primary key. This way you have the best of both worlds.

Andomar
A: 

hmm so, composite keys are a "dead end"?

Ram Miranda