<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>Database Design</title>
        <link>http://weblogs.sqlteam.com/jeffs/category/243.aspx</link>
        <description>Database design and modeling.</description>
        <language>en-US</language>
        <copyright>Jeff Smith</copyright>
        <managingEditor>smith_jeffreyt@yahoo.com</managingEditor>
        <generator>Subtext Version 1.9.4.0</generator>
        <item>
            <title>An INT primary key .... yet not an Identity?</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2008/02/21/60523.aspx</link>
            <description>Ah, this is &lt;span style="font-style: italic;"&gt;not &lt;/span&gt;an anti-identity rant, don't worry!&lt;br /&gt;
&lt;br /&gt;
Though, in a round-a-bout sort of way, it is yet another argument against always blindly using them -- but not in the way you might expect.&lt;br /&gt;
&lt;br /&gt;
There is a simple rule I'd like to propose, let me know what you think:&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-style: italic;"&gt;"If your client code, SQL code, or configuration files reference the primary key column of a table to determine any application logic, that primary key column should not be an identity."&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Now, I am not saying that primary key column can't be a meaningless integer.  I am just saying it should not be an &lt;span style="font-style: italic;"&gt;auto-generated meaningless integer.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Working with an inherited web application (in "classic" ASP .... yuck), there were lots of tables like this:&lt;br /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;groupID, groupName&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1, Administrator&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;2, User&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;3, Finance User&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;5, Account Manager&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;8, ReadOnly&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
and there was &lt;span style="font-style: italic;"&gt;lots &lt;/span&gt;of code written like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;if groupID = 1 then &lt;span style="font-style: italic;"&gt;show delete button&lt;/span&gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;if groupID =3 or groupID=5 and groupID != 8 then &lt;span style="font-style: italic;"&gt;show the create new project button&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
... repeated everywhere, throughout the application and in the SQL code.   Yet, the groupID column was an identity.   I discussed a similar issue &lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2006/02/10/9002.aspx"&gt;here&lt;/a&gt;, but this is a slightly different approach.   In this case, let us assume that we really want to -- or need to -- embed that "groupID" value everywhere in our code.  And we want that table to have an integer primary key to keep things short and simple and precise in our database code.  That's all fine, it happens, and it certainly is common.&lt;br /&gt;
&lt;br /&gt;
But why does that groupID need to be an identity?&lt;br /&gt;
&lt;br /&gt;
For static, non-changing system tables, why assign an identity primary key? Why not just make it an integer?  And once a year or so when someone adds and entry to this table (usually manually, behind the scenes with an INSERT command or opening the table directly) what is so bad about having them manually "figure out" the next ID to use and manually insert it?&lt;br /&gt;
&lt;br /&gt;
The database will always have that primary key constraint on the column -- we don't gain any integrity by using an identity.  We just gain ... well, what exactly do we gain when the table is static?&lt;br /&gt;
&lt;br /&gt;
The advantage of &lt;span style="font-style: italic;"&gt;not&lt;/span&gt; using an identity is this: if we wish to confer meaning on these ID values, we have complete control over them.  Moving from one system to the next means we can just copy them over and we don't need to worry about setting IDENTITY INSERT ON and things like that.   We don't have to worry about gaps in the sequence or re-seeding the tables.  We can guarantee that we have complete control over these values, and they never will be created anywhere unless we &lt;span style="font-style: italic;"&gt;explicitly create them.  &lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
If we do use an identity, that's great the next "ID" will pop up magically, but what good does that really do for us in this scenario?  I understand that when an order is generated, or a customer is added, or for things like that, an IDENTITY is the way to go.  But for static tables, I really honestly don't bother with an identity.  Just put an INT primary key on there and you are good to go.   &lt;br /&gt;
&lt;br /&gt;
The reason I bring this up is as the result of a mini-debate with another developer.  If a system table such as "Status" will only ever have 3 values, and we wish to assign each of those values an integer "ID" as a primary key, why bother with an identity?  Why not just use a standard, non-auto-generating integer column as the primary key?&lt;br /&gt;
&lt;br /&gt;
Do the pros of an identity&lt;span style="font-style: italic;"&gt; in this situation&lt;/span&gt; outweigh the cons?&lt;br /&gt;
&lt;br /&gt;
Then again, I am a bit of a control freak, I admit ... But I think that key values in your data tables that your applications and systems rely on are a pretty good thing to have control over.&lt;br /&gt;
&lt;br /&gt;
(Another minor point oft-overlooked:  Don't forget about considering the use of tinyint or smallint data types for these columns as well. )&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60523.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2008/02/21/60523.aspx</guid>
            <pubDate>Thu, 21 Feb 2008 17:08:46 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60523.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2008/02/21/60523.aspx#feedback</comments>
            <slash:comments>12</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60523.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60523.aspx</trackback:ping>
        </item>
        <item>
            <title>Implementing Table Inheritance with SQL Server</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2008/02/21/60522.aspx</link>
            <description>I have a new article up at SQLTeam:&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.sqlteam.com/article/implementing-table-inheritance-in-sql-server" target="_blank"&gt;Implementing Table Inheritance with Sql Server&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
It discusses the situation where you have multiple entities that are distinct, yet they have many attributes or relations in common.   There is an easy way to simplify your database design and your code if you use the concept of a "base table" for that common data, which is very similar to the concept of &lt;span style="font-style: italic;"&gt;Inheritance&lt;/span&gt; in Object-Oriented programming.&lt;br /&gt;
&lt;br /&gt;
I recently had to do this for a client that tracks Contributions to their foundation; there is a base set of data that all Contributions have, such as who donated, how they paid, the date a tax letter was sent, etc. But for certain contribution types we need additional information, such as if they bought an Auction Item, sponsored an Event, and so on. Thus, we set up a "base table" of Contributions and sub-tables for the different types, and set up a constraint to ensure that the right subtable is used depending on the type.  &lt;br /&gt;
&lt;br /&gt;
It sounds complicated and like it may require fancy triggers or at the very least CHECK constraints, but it is very easy to model in T-SQL -- especially in SQL Server 2005+.  The end result is that you have a less redundant database design and much less code to write to maintain that data.  &lt;br /&gt;
&lt;br /&gt;
Check it out if it sounds interesting, or helpful, or if none of this makes any sense and you're wondering what the heck I'm talking about.&lt;br /&gt;
&lt;br /&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60522.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2008/02/21/60522.aspx</guid>
            <pubDate>Thu, 21 Feb 2008 16:05:35 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60522.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2008/02/21/60522.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60522.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60522.aspx</trackback:ping>
        </item>
        <item>
            <title>Interesting Database Modeling Dilemma</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2008/01/07/database-modeling-dilemma.aspx</link>
            <description>Let's say you have a database that contains Companies, Products and Stores.   Products and Stores are unique to each company -- i.e., they are not "shared" across companies. &lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;create table Companies&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;&lt;/span&gt;&lt;span style="font-family: Courier New;"&gt;    CompanyID int identity primary key,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    Name varchar(100)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;create table Products&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    ProductID int identity primary key,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    CompanyID int references Companies(CompanyID) not null,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    Name varchar(100)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;create table Stores&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    StoreID int identity primary key,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    CompanyID int references Companies(CompanyID) not null,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    Name varchar(100)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;/div&gt;
&lt;br /&gt;
OK, looks very simple and standard, right?  Now, suppose we wish to create a table that lets us relate products to the stores that sell them:&lt;br /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;create table StoreProducts&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    StoreID int references Stores(StoreID),&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    ProductID int references Products(ProductID),&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    primary key (StoreID, ProductID)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;/div&gt;
&lt;br /&gt;
All is well and good in the world -- except that we now have a very flawed data model that does not constrain at all against entering potentially &lt;span style="font-weight: bold;"&gt;meaningless data&lt;/span&gt;!&lt;br /&gt;
&lt;br /&gt;
The problem? &lt;span style="font-weight: bold;"&gt;We can easily relate Stores for company X with products for Company Y. &lt;/span&gt;None of our constraints disallow this from happening.  Yet, it is a simple data model and this is a simple situation and it was very easy to overlook.  If we have any data of that sort in our database, it is effectively garbage and we should not be allowing it.&lt;br /&gt;
&lt;br /&gt;
So, the question is: what is the most effective way to handle this?  How we can ensure that only Stores and Products for the same company get related?  &lt;br /&gt;
&lt;br /&gt;
This seems to be a case where composite primary keys might be required.  Using composite primary keys for the Products and Stores table that includes the CompanyID column as well (making those tables more like "child" tables of Companies), we can obtain our goal like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;create table Products&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    CompanyID int references Companies(CompanyID) not null,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;&lt;/span&gt;&lt;span style="font-family: Courier New;"&gt;    ProductID int identity,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    Name varchar(100),&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    &lt;span style="font-weight: bold;"&gt;primary key (CompanyID, ProductID)&lt;/span&gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;create table Stores&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    CompanyID int references Companies(CompanyID) not null,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    StoreID int identity,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    Name varchar(100),&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New; font-weight: bold;"&gt;    primary key (CompanyID, StoreID)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;create table StoreProducts&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    CompanyID int,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    StoreID int,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    ProductID int,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New; font-weight: bold;"&gt;    foreign key (CompanyID, StoreID) references Stores (CompanyID, StoreID),&lt;/span&gt;&lt;br style="font-family: Courier New; font-weight: bold;" /&gt;
&lt;span style="font-family: Courier New; font-weight: bold;"&gt;    foreign key (CompanyID, ProductID) references Products (CompanyID, ProductID),&lt;/span&gt;&lt;br style="font-family: Courier New; font-weight: bold;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    primary key (CompanyID, StoreID, ProductID)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
In the above model, we have solved the problem -- only stores and products for the same company can be related.  Yet, this doesn't seem very intuitive and doesn't seem ideal.  &lt;br /&gt;
&lt;br /&gt;
We could also leave the PK of Stores and Products as the single identity columns and add additional unique constraints to these tables to use in the foreign key constraints, but would the design still be normalized?  The CompanyID column in our StoreProducts table would be a redundant attribute that is already stored in other related tables.  Storing redundant data as part of a primary key certainly doesn't violate the principle of normalization since that is how we relate two tables, but storing redundant non-PK attributes certainly seems to.  Then again, the unique constraint would simply be an alternate primary key so I suppose that would be fine.  &lt;br /&gt;
&lt;br /&gt;
The "unique constraint" version of the model looks like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;create table Products&lt;br /&gt;
(&lt;br /&gt;
    ProductID int identity primary key,&lt;br /&gt;
    CompanyID int references Companies(CompanyID) not null,&lt;br /&gt;
    Name varchar(100),&lt;br /&gt;
    &lt;span style="font-weight: bold;"&gt;constraint Products_altpk unique (CompanyID, ProductID)&lt;/span&gt;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
create table Stores&lt;br /&gt;
(&lt;br /&gt;
    StoreID int identity primary key,&lt;br /&gt;
    CompanyID int references Companies(CompanyID) not null,&lt;br /&gt;
    Name varchar(100),&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;    constraint stores_altpk unique (CompanyID, StoreID)&lt;/span&gt;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
create table StoreProducts&lt;br /&gt;
(&lt;br /&gt;
    CompanyID int,&lt;br /&gt;
    StoreID int,&lt;br /&gt;
    ProductID int,&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;    foreign key (StoreID, CompanyID) references Stores (StoreID, CompanyID),&lt;/span&gt;&lt;br style="font-weight: bold;" /&gt;
&lt;span style="font-weight: bold;"&gt;    foreign key (ProductID, CompanyID) references Products (ProductID, &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: Courier New;"&gt;&lt;span style="font-weight: bold;"&gt;CompanyID&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: Courier New;"&gt;&lt;span style="font-weight: bold;"&gt;),&lt;/span&gt;&lt;br style="font-weight: bold;" /&gt;
    primary key (StoreID, ProductID)&lt;br /&gt;
)&lt;/span&gt;&lt;span style="font-family: Courier New;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
So, be aware of situations like this when designing your data models -- things are not always as simple as they seem.  The two techniques shown above will help you to avoid making the modeling error described here and will keep your data accurate and consistent, without the need for triggers or relying on application code to validate data.  It seems funny to take a perfectly unique identity and make that &lt;span style="font-style: italic;"&gt;part&lt;/span&gt; of a primary key or a unique constraint, since it is unique on its own, but as you can see here it is often a very useful technique.&lt;br /&gt;
&lt;br /&gt;
When choosing a unique constraint or composite primary key, I think the main question is this: Do all (or most) of the the tables related to that entity need both columns for other relations and/or constraints? If so, then use a composite primary key, since you will always be relating on both of those columns anyway.  However, if it is rare that you would need to relate back to those entities on both columns, then I would go with a unique constraint.&lt;br /&gt;
&lt;br /&gt;
Does anyone have other (better) ideas out there for handling situations like this?  This is a great example of how data modeling is truly an art and not a science.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-style: italic;"&gt;see also:&lt;br /&gt;
&lt;/span&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a title="View Entry" href="../../../../jeffs/archive/2007/08/23/composite_primary_keys.aspx"&gt;Composite Primary Keys&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl06_HyperLink1" title="View Entry" href="../../../../jeffs/archive/2007/07/03/60248.aspx"&gt;Data Types -- The Easiest Part of Database Design&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a title="View Entry" href="../../../../jeffs/archive/2007/06/19/60238.aspx"&gt;SQL Data Modeling: Entities versus Attributes&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl10_HyperLink1" title="View Entry" href="../../../../jeffs/archive/2007/06/05/60223.aspx"&gt;Don't Let Output Dictate your Database Design&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl06_HyperLink1" title="View Entry" href="../../../../jeffs/archive/2006/02/10/9002.aspx"&gt;Data belongs in your tables -- not in your code&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl04_HyperLink1" title="View Entry" href="../../../../jeffs/archive/2007/08/15/60287.aspx"&gt;The problem isn't the poor database model; It's that external code is bound to the schema&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a title="View Entry" href="../../../../jeffs/archive/2007/03/28/60145.aspx"&gt;Dear DBA ....&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60449.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2008/01/07/database-modeling-dilemma.aspx</guid>
            <pubDate>Mon, 07 Jan 2008 15:52:26 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60449.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2008/01/07/database-modeling-dilemma.aspx#feedback</comments>
            <slash:comments>13</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60449.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60449.aspx</trackback:ping>
        </item>
        <item>
            <title>Working with Date and/or Time values in SQL Server: Don't Format, Don't Convert -- just use DATETIME</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/08/29/SQL-Dates-and-Times.aspx</link>
            <description>&lt;span style="font-weight: bold;"&gt;The Importance of Data Types&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Imagine that SQL Server only provided two data types:  the MONEY data type to store numeric values, and VARCHAR to store text. &lt;br /&gt;
&lt;br /&gt;
If you are designing a database in this scenario and you need to store or return integer values, which data type -- MONEY or VARCHAR -- would you use?&lt;br /&gt;
&lt;br /&gt;
Suppose I were to argue that MONEY is too complicated, and a waste of space, since all MONEY values always have 4 digits after the decimal which we don't need and it might get confusing.  Therefore, we should use VARCHAR, which is much simpler.  After all, if we use MONEY, every time we execute a SELECT, our integer data will be returned with 4 decimal places like "45.0000", which is certainly not what we want and doesn’t &lt;span style="font-style: italic;"&gt;look &lt;/span&gt;like an integer; but if we use VARCHAR we will get "45" which looks much better and is really what we want to see.  While eventually we will notice that we cannot add these VARCHAR numbers together, or sort them, or compare them, or do any kind of math with them, we can always temporarily convert those values to MONEY if we need to do these things, right?   And as for ensuring that we only store valid numbers in our VARCHAR columns, we can handle that with some complicated CHECK expressions that parses the string to ensure that it stores only valid digits.  We also need to make sure that everyone is aware of the rules for the format of integer data in our VARCHAR columns, to avoid problems as well: after all, we may wish to store values like 34934 as "34,942" so that it looks just right when the values are returned and is easier to work with.  &lt;br /&gt;
&lt;br /&gt;
Now, if I make this argument to you, what would you say?  Would you think it's a good idea?&lt;br /&gt;
&lt;br /&gt;
I think we can all agree that a much better approach would be to use MONEY. Now we can add, sort, compare, do math, and all kinds of things on our values which are stored as numeric data, not text.  We can add a quick, simple CHECK constraint to ensure that our MONEY values have nothing stored after the decimal (e.g., &lt;span style="font-family: Courier New;"&gt;CHECK round(value,0) = value&lt;/span&gt;), and we simply let our front end format those numbers without any decimal places.  In this scenario, it's probably fair to say that no reasonable programmer would argue that VARCHARs are better for working with integers than a true, numeric data type like MONEY. &lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;Manipulate and Return Data -- not Strings&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
If we agree to use the MONEY data type, wouldn't it make sense to keep those values as MONEY throughout our T-SQL code, and only return MONEY values to the clients?  We wouldn't want to try to convert our MONEY values to VARCHAR in our database code just so that things "look good" and we "don't see" that pesky little ".0000" after each value, right?  It means nothing to us, it doesn’t affect our data, so we simply store and work with and return MONEY in &lt;span style="font-style: italic;"&gt;all &lt;/span&gt;of our database code and we don't worry about formatting or how things "look" or the extra decimal places that we aren't using.  This keeps our code short, clear, easy to read since we are not converting things back and forth between VARCHAR and MONEY over and over to make things "look good" in one spot but to make them “work correctly” in another.&lt;br /&gt;
&lt;br /&gt;
Along those same lines, suppose we have a MONEY value like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt; 1846.4069&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
... and we need to return that value as an integer.  What should we return, a VARCHAR value or a MONEY value?  The VARCHAR value of "1846" will &lt;span style="font-style: italic;"&gt;look &lt;/span&gt;nice, but again: we cannot sort, compare or do anything with it -- it is just a picture of data, not actual data.  If we return a MONEY value of 1846.0000, we can and should ignore the decimal portion since it does not affect anything and enjoy the benefit of returning an actual numeric value that both the database and the client can sort, compare, calculate, and so on.&lt;br /&gt;
&lt;br /&gt;
If you don't agree with any of that, stop reading now and let me know in the comments.  Otherwise, let's continue on ...&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;Another Obvious Example&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
What about if we want to store only values that are decimals, such as .0234 or .963?  These values will never have any digits before the decimal, but will always have one to four digits after the decimal (we only need 4 digits of precision).  That is, we are storing values from -.9999 to .9999 only.   With only MONEY and VARCHAR available, what data type should we use to store and work with these values?&lt;br /&gt;
&lt;br /&gt;
Once again, suppose I argue that VARCHAR is the way to go.  After all, if we use MONEY, every value will be preceded by "0.", which is not what we want and again a waste of space.  We don't need the integer portion, and having it returned and seeing it everywhere will be confusing.  If we use VARCHAR it will always look perfect, and we again can use CHECK constraints that parse the string to ensure we have valid data.  Things still don’t sort or compare or calculate, but we can CONVERT back and forth as needed. &lt;br /&gt;
&lt;br /&gt;
Yet once again, I would hope that you will agree that the suggestion to use VARCHAR is not a good one.  We should use a numeric data type, and therefore MONEY is the best choice.  It handles our data perfectly with the accuracy we need, we can do math, sort, and compare.  We know that it will be valid and accurate, and a simple CHECK constraint ensures that we only have values between -.9999 and .9999 as opposed to using string parsing to determine this.  And, again, even though in the T-SQL world all of our money values have an integer portion of “0” attached to them, it should make sense that we should not worry about this since our data is accurate and correct, it doesn't affect calculations, and the client can output these decimals without the preceding “0” very easily.  &lt;br /&gt;
&lt;br /&gt;
This also affects doing some math on a value like 139.592 to return only the decimal portion; for all of the reasons stated, we should all agree that the value to return is a MONEY value of 0.5920 and &lt;span style="font-style: italic;"&gt;not&lt;/span&gt; a VARCHAR value of ".5920".&lt;br /&gt;
&lt;br /&gt;
Finally, if we always store and return MONEY for&lt;span style="font-style: italic;"&gt; both&lt;/span&gt; our integer values and our decimal values, we have another huge benefit:  we can do math on both of those values &lt;span style="font-style: italic;"&gt;together &lt;/span&gt;and get accurate, consistent results.  No conversions, no string manipulation or parsing or concatenation, no worrying about how things are formatted or stored or how they look; we can do simple, efficient and accurate math on all of our data with standard mathematical operations and it just works perfectly and intuitively.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;Getting to the Point (Finally!)&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Are we all agreed on the above?  Good.  So, then, what’s my point?&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-style: italic;"&gt;Shouldn't we follow the exact same logic and reasoning when &lt;/span&gt;&lt;span style="font-style: italic;"&gt;storing &lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;span style="font-weight: bold;"&gt;date &lt;/span&gt;and &lt;span style="font-weight: bold;"&gt;time &lt;/span&gt;data?&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;
&lt;/span&gt;The exact same scenario happens every day, only programmers are deciding how to store or return dates without times, or times without dates.  Yet, very often we see beginners choosing to store their values as VARCHARs and/or return them and manipulate them as VARCHARs, instead of using the easiest, most obvious and appropriate data type: DATETIME.  &lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;
Working with Date-Only Data&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
If you need to store just a date, use a DATETIME.  Don’t worry about the “extra” time that is stored, just enforce that it is always midnight and it won’t affect anything – just like forcing a decimal to be “.000” and ignoring it!  It is the &lt;span style="font-style: italic;"&gt;exact &lt;/span&gt;same logic.  And, by that same token, &lt;span style="font-style: italic;"&gt;don’t worry about that time being there and feel you need to convert everything to VARCHAR to make it “look” right. &lt;/span&gt; Just use data in the proper type throughout your SQL code, ignore the time portion, and return the DATETIME value – in the correct type – to your clients.  Don’t try to “help” them by converting those nice, accurate, and clean DATETIME values to a string to “hide” the time part – just return the value, just as you would not try to “hide” a decimal portion of “.000” in a numeric by converting it to a string.&lt;br /&gt;
&lt;br /&gt;
Luckily, many programmers do indeed use DateTime when all they want to store is dates, but of course many do obsess about “hiding” that time portion.  Don’t do it.  Leave your data in the proper type, enforce a time of only midnight with a simple check constraint (e.g., &lt;span style="font-family: Courier New;"&gt;CHECK dateAdd(dd,datediff(dd,0,yourdate),0) = yourdate&lt;/span&gt;) and now you can compare, sort, do math, and everything else you ever need on those values, and your client can do the same.  Just as you would use a MONEY data type to store numeric data, if you had to, as opposed to a VARCHAR.  It’s easier, shorter, and more efficient – it just makes sense. &lt;br /&gt;
&lt;br /&gt;
The same concept applies if you have a DATETIME value like "5/6/2007 5:00 PM" and you'd like to return just the date portion:  Should you return a VARCHAR or a DATETIME?  For all of the reasons stated, it should be clear that you simply return a DATETIME value a midnight -- "5/6/2007 12:00AM" -- knowing that the time portion is now "zero" and even though it is there and we see it, it does not affect any calculations and can easily be excluded when the client presents the data.&lt;br /&gt;
&lt;br /&gt;
To "round" a DATETIME so that the time at midnight is returned:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select dateadd(dd,0, datediff(dd,0, &lt;span style="font-style: italic;"&gt;datetimeval&lt;/span&gt;)) as date_at_midnight&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;Working with Time-Only Data&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Now, what about storing only a Time?  Here’s where people &lt;span style="font-style: italic;"&gt;really &lt;/span&gt;get confused, but, again, &lt;span style="font-style: italic;"&gt;it is exactly the same as storing a value between -.9999 and .9999 in either MONEY or a VARCHAR&lt;/span&gt;.   We agreed to use MONEY, and simply accept the fact that our integer portion of “0” is &lt;span style="font-style: italic;"&gt;always &lt;/span&gt;there, but it doesn’t affect anything; we can simply ignore it and let our client worry about not displaying it.  Remember, when storing a true decimal value, we had no choice – that zero was always there, whether we displayed it or not, right?  Well, DATETIME values have the &lt;span style="font-style: italic;"&gt;exact &lt;/span&gt;same concept!  The decimal portion of a DATETIME is the time component, and even though we just want to store time values, a DATETIME works perfectly for us.  We simply ensure that we store a 0 value as the date portion and we &lt;span style="font-style: italic;"&gt;ignore it&lt;/span&gt;!  &lt;br /&gt;
&lt;br /&gt;
For DATETIME data, a date of “0” that doesn’t affect any calculations is “1/1/1900”, just as a time of “0” that doesn’t affect any calculations is “12:00:00 AM”.  Thus, “1/1/1900 12:00:00AM” is the equivalent to a decimal value of 0.0 -- adding or subtracting that value to other values will not have any effect. &lt;br /&gt;
&lt;br /&gt;
In fact, take a look at this:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select cast(0.0 as datetime) as ZeroDateTime&lt;br /&gt;
&lt;br /&gt;
ZeroDateTime&lt;br /&gt;
-----------------------&lt;br /&gt;
1900-01-01 00:00:00.000&lt;br /&gt;
&lt;br /&gt;
(1 row(s) affected)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
select getdate() as Now, getdate() + '1/1/1900 12:00:00 AM' as NowPlusZeroDateTime&lt;br /&gt;
                        &lt;br /&gt;
Now                     NowPlusZeroDateTime&lt;br /&gt;
----------------------- -----------------------&lt;br /&gt;
2007-08-30 20:55:48.513 2007-08-30 20:55:48.513&lt;br /&gt;
&lt;br /&gt;
(1 row(s) affected)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;
Notice that the numeric value of 0.0 is converted nicely to '1/1/1900 12:00:00 AM', and that adding '1/1/1900 12:00:00 AM' to a DATETIME value has no effect.&lt;br /&gt;
&lt;br /&gt;
So, if we want to store &lt;span style="font-style: italic;"&gt;only &lt;/span&gt;a time, without a date, we just:&lt;br /&gt;
&lt;ul&gt;
    &lt;li&gt;Use a DATETIME data type&lt;/li&gt;
    &lt;li&gt;Ensure that the date value of that time is 0 (that is, "1/1/1900") with a check constraint (e.g., &lt;span style="font-family: Courier New;"&gt;CHECK datediff(dd,0,TransTime) = 0&lt;/span&gt;)&lt;/li&gt;
    &lt;li&gt;Ignore the date in our SQL code even though we might “see it” here and there&lt;/li&gt;
    &lt;li&gt;Keep our data in the correct data type throughout our code without worrying how it “looks” and trying to “hide” the date part&lt;/li&gt;
    &lt;li&gt;Return that DATETIME value to our client and let it worry about hiding the “1/1/1900”, just as we let the client worry about hiding the preceding “0.” in a decimal value such as 0.2394.&lt;/li&gt;
&lt;/ul&gt;
Once again, let's consider what to do if we have a DATETIME value with such as "6/1/2007 5:00 PM" and we'd like to just return the time portion: Do we return a VARCHAR or a DATETIME?  By now, the answer should be clear:  we return data in the correct type, DATETIME, and we simply use the "0" date of 1/1/1900 by returning "1/1/1900 5:00 PM" knowing that the date portion will not affect the time value just as a an integer portion of 0 will not affect a decimal value.&lt;br /&gt;
&lt;br /&gt;
To return just the time portion of a DATETIME (i.e., at the base date of 1/1/1900):&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;select &lt;span style="font-style: italic;"&gt;datetimeval &lt;/span&gt;- dateadd(dd,0, datediff(dd,0, &lt;span style="font-style: italic;"&gt;datetimeval&lt;/span&gt;)) as time_at_base_date&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
Finally, just as in our previous MONEY example,  if we exclusively work with dates and times using the correct DATETIME data type throughout our schema and our SQL code, we can simply add values together to combine a date and a time using simple math:&lt;br /&gt;
&lt;br /&gt;
  &lt;span style="font-family: Courier New;"&gt;    select &lt;span style="font-style: italic;"&gt;somedate &lt;/span&gt;+ &lt;span style="font-style: italic;"&gt;sometime &lt;/span&gt;as &lt;span style="font-style: italic;"&gt;somedatetime&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
No converting, no string manipulations or parsing, no worrying about AM or PM or time formats or anything.  If we keep our data in the correct types, and constraint it properly, everything works as it should – quickly, accurately, and intuitively.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The next time you are working with dates and times, please remember: how would you handle things if you were working with integers and decimals?  The same logic and reasoning applies.  Be smart, let SQL do the work for you and use the right data types for the job, even if things don't always "look" right.  It's not about how good your data &lt;span style="font-style: italic;"&gt;looks&lt;/span&gt;, it's about how accurate it actually &lt;span style="font-style: italic;"&gt;is&lt;/span&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-style: italic;"&gt;see also:&lt;br /&gt;
&lt;/span&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/10/15/time-spans-durations-sql-server.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl08_HyperLink1"&gt; Working with Time Spans and Durations in SQL Server&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/09/10/group-by-month-sql.aspx" title="View Entry"&gt;Group by Month (and other time periods)&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/08/29/SQL-Dates-and-Times.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl08_HyperLink1"&gt;Working with Date and/or Time values in SQL Server: Don't Format, Don't Convert -- just use DATETIME&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/07/03/60248.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl10_HyperLink1"&gt;Data Types -- The Easiest Part of Database Design&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/04/13/format-date-sql-server.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl06_HyperLink1"&gt;How to format a Date or DateTime in SQL Server&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2004/12/02/2954.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl06_HyperLink1"&gt;Breaking apart the DateTime datatype -- Separating Dates from Times in your Tables&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/10/31/sql-server-2005-date-time-only-data-types.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl04_HyperLink1"&gt;Date Only and Time Only data types in SQL Server 2005 (without the CLR)&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/01/02/56079.aspx" title="View Entry"&gt;Essential SQL Server Date, Time and DateTime Functions&lt;/a&gt; 				 				&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60309.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/08/29/SQL-Dates-and-Times.aspx</guid>
            <pubDate>Wed, 29 Aug 2007 14:04:02 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60309.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/08/29/SQL-Dates-and-Times.aspx#feedback</comments>
            <slash:comments>18</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60309.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60309.aspx</trackback:ping>
        </item>
        <item>
            <title>Composite Primary Keys</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/08/23/composite_primary_keys.aspx</link>
            <description>Ah … primary keys … such a topic!  When discussing what columns to define as a primary key in your data models, two large points always tend to surface:&lt;br /&gt;
&lt;ol&gt;
    &lt;li&gt;&lt;a target="_blank" href="http://en.wikipedia.org/wiki/Surrogate_key"&gt;Surrogate Keys&lt;/a&gt; versus Natural Keys&lt;/li&gt;
    &lt;li&gt;&lt;a target="_blank" href="http://www.datamodel.org/NormalizationRules.html"&gt;Normalization&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
These can be very complicated and sometimes polarizing things to debate.   As I often try to do, I will attempt to approach this topic from a slightly different perspective.&lt;br /&gt;
&lt;br /&gt;
Let's start things off with what I feel is a good interview question:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-style: italic;"&gt;How would you define what a primary key of a table is?&lt;br /&gt;
&lt;/span&gt;&lt;br style="font-style: italic;" /&gt;
&lt;span style="font-style: italic;"&gt;a.    An auto-generated numeric or GUID column in the table that uniquely identifies each row&lt;/span&gt;&lt;br style="font-style: italic;" /&gt;
&lt;span style="font-style: italic;"&gt;b.    A non-nullable column in the table that uniquely identifies each row&lt;/span&gt;&lt;br style="font-style: italic;" /&gt;
&lt;span style="font-style: italic;"&gt;c.    None of the above&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
I suspect that many people will answer (a), and quite a few will answer (b).  If you answer (c), though, you are correct!  Why?  Because a primary key is &lt;span style="font-style: italic;"&gt;not &lt;/span&gt;a single column, it is &lt;span style="font-style: italic;"&gt;a set of columns&lt;/span&gt;.  Many people who have designed large, complicated systems are simply &lt;span style="font-style: italic;"&gt;not &lt;/span&gt;aware of this.&lt;br /&gt;
&lt;br /&gt;
I once worked with a consultant who kept claiming that importing data into his system was complicated, because his database used “primary keys”.  It was very confusing (yet humorous) trying to discuss things with him because he kept confusing primary keys with identity columns.  They are &lt;span style="font-style: italic;"&gt;not &lt;/span&gt;the same!  An identity column may be a type of primary key, but a primary key &lt;span style="font-style: italic;"&gt;is not an identity column; &lt;/span&gt;it is a &lt;span style="font-style: italic;"&gt;set of columns&lt;/span&gt; that &lt;span style="font-style: italic;"&gt;you &lt;/span&gt;define that determine what makes the data in your table unique.  It defines your data. It may be an identity column, it may be a varchar column or a datetime column or an integer column, or it may be a combination of multiple columns.&lt;br /&gt;
&lt;br /&gt;
When you define more than one column as your primary key on a table, it is called a &lt;span style="font-style: italic;"&gt;composite primary key.&lt;/span&gt;  And many experienced and otherwise talented database programmers have &lt;span style="font-style: italic;"&gt;never&lt;/span&gt; used them and may not even be aware of them. Yet, composite primary keys are very important when designing a good, solid data model with integrity.&lt;br /&gt;
&lt;br /&gt;
This will be greatly oversimplifying things, but for this discussion let's categorize the tables in a database into these two types:&lt;br /&gt;
&lt;ul&gt;
    &lt;li&gt;Tables that &lt;span style="font-style: italic;"&gt;define &lt;/span&gt;entities&lt;/li&gt;
    &lt;li&gt;Tables that &lt;span style="font-style: italic;"&gt;relate &lt;/span&gt;entities&lt;/li&gt;
&lt;/ul&gt;
Tables that &lt;span style="font-style: italic;"&gt;define &lt;/span&gt;entities are tables that define customers, or sales people, or even sales transactions.  The primary key of these tables is not what I am here to discuss.   You can use GUID columns, identity columns, long descriptive text columns, or whatever it is you feel comfortable to use as primary keys on tables that define entities.  It’s all fine by me, whatever floats your boat as they say.  There are lots of discussions and ideas about the best way to determine what the best primary key of these tables should be, and pros and cons of all of the various approaches, but overall, that is not really what I am addressing.  &lt;br /&gt;
&lt;br /&gt;
Tables that &lt;span style="font-style: italic;"&gt;relate &lt;/span&gt;entities, however, are a different story.&lt;br /&gt;
&lt;br /&gt;
Suppose we have a system that tracks customers, and allows you to assign multiple products to multiple customers to indicate what they are eligible to order.  This is called a &lt;span style="font-style: italic;"&gt;many-to-many&lt;/span&gt; or &lt;span style="font-style: italic;"&gt;N:N&lt;/span&gt; relation between Customers and Products.  We already have a table of Products, and a table of Customers.  The primary key of the Products table is ProductID, and the Customers table is CustomerID.  Whether or not these “ID” columns are natural or surrogate, identity or GUID, numerical or text or codes, is irrelevant at this point.&lt;br /&gt;
&lt;br /&gt;
What is relevant and important, and what I am here to discuss, is how we define our CustomerProducts table.  This table relates customers to products, so the purpose of the table is to relate two entities that have already been defined in our database.  Let’s also add a simple “OrderLimit” column which indicates how many of that product they are allowed to order.  (This is just a simple example, any attribute will do). How should we define this table?&lt;br /&gt;
&lt;br /&gt;
For some reason, a very common answer is that we simply create a table with 4 columns: One that stores the CustomerID, one that stores the ProductID we are relating it to, the Order Limit, and of course the primary key column which is an identity:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;Create table CustomerProducts&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New; font-weight: bold;"&gt;    Customer_ProductID int identity primary key,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    CustomerID int references Customers(CustomerID) not null,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    ProductID int references Products(ProductID) not null,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    OrderLimit int not null&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
This is what I see in perhaps most of the databases that I’ve worked with over the years.  The reason for designing a table in this manner?  Honestly, I don’t know! I can only surmise that it is because of the lack of understanding what a primary key of a table really is, and that it can be something other than an identity and that it can be comprised of more than just a single column.  As I mentioned, it seems that many database architects are simply not aware of this fact.&lt;br /&gt;
&lt;br /&gt;
So then, what is the problem here?  The primary issue is data integrity.  This table allows me to enter the following data:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;&lt;span style="text-decoration: underline;"&gt;CustomerProductID&lt;/span&gt;    &lt;span style="text-decoration: underline;"&gt;CustomerID&lt;/span&gt;    &lt;span style="text-decoration: underline;"&gt;ProductID&lt;/span&gt;    &lt;span style="text-decoration: underline;"&gt;OrderLimit&lt;/span&gt;&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;1                    1             100          25&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;2                    1             100          30&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
In the above data, what is the order limit for customerID #1, productID #100?  Is it 25 or 30?  There is no way to conclusively know for sure.  Nothing in the database constrains this table so that we only have exactly one row per CustomerID/ProductID combination. Remember, our primary key is just an identity, which does not constrain anything.  &lt;br /&gt;
&lt;br /&gt;
Most database designs like this just assume (hope?) that the data will be always be OK and there will be no duplicates.  The UI will handle this, of course!  But even if you think that only one single form on one single application &lt;span style="font-style: italic;"&gt;ever &lt;/span&gt;updates this table, you have to remember that data will &lt;span style="font-style: italic;"&gt;always&lt;/span&gt; get in and out of your system in different ways.  What happens if you upgrade your system and have to move the data over?  What if you need certain transactions restored from a back up?  What if you ever need to do a batch import to save valuable data entry time?  Or to convert data from a new system that you are absorbing or integrating?&lt;br /&gt;
&lt;br /&gt;
If you ever write a report or an application off of a system and simply &lt;span style="font-style: italic;"&gt;assume &lt;/span&gt;that the data will be constrained a certain way, but the database itself does not guarantee that, you are either a) greatly over-engineering what should be a simple SQL statement to deal with the possibility of bad data or b) ignoring the possibility of bad data completely and setting yourself up for issues down the road.  It's possible to constrain data properly, it's efficient, it's easy to do, and it simply &lt;span style="font-style: italic;"&gt;must &lt;/span&gt;be done or you should not really be working with a database in the first place -- you are forgoing a very important advantage it provides.&lt;br /&gt;
&lt;br /&gt;
So, to handle that issue with this table design, we need create a unique constraint on our CustomerID/ProductID columns:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;create unique index cust_products_unique on CustomerProducts (CustomerID, ProductID)&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;br /&gt;
Now, we are guaranteed that there will only be exactly one row per combination of CustomerID and ProductID.  That handles that problem, our data now has integrity, so we seem to be all set, right?&lt;br /&gt;
&lt;br /&gt;
Well, let’s remember the definition of what a primary key really is.  It is the &lt;span style="font-style: italic;"&gt;set of columns&lt;/span&gt; in a table that uniquely identify each row of data.  Also, for a table to be normalized, all non-primary key columns in a table should be fully dependent on the primary key of that table.&lt;br /&gt;
&lt;br /&gt;
Consider instead the following design:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;Create table CustomerProducts&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;(&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    CustomerID int references Customers(CustomerID) not null,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    ProductID int references Products(ProductID) not null,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;    OrderLimit int not null,&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New; font-weight: bold;"&gt;    Primary key (CustomerID, ProductID)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;span style="font-family: Courier New;"&gt;)&lt;/span&gt;&lt;br style="font-family: Courier New;" /&gt;
&lt;/div&gt;
&lt;br /&gt;
Notice here that we have eliminated the identity column, and have instead defined a composite (multi-column) primary key as the combination of the CustomerID and ProductID columns.  Therefore, we do not have to create an additional unique constraint.  We also do not need an additional identity column that really serves no purpose.  We have not only simplified our data model physically, but we’ve also made it more logically sound and the primary key of this table accurately explains what it is this table is modeling – the relationship of a CustomerID to a ProductID.&lt;br /&gt;
&lt;br /&gt;
Going back to normalization, we also know that our OrderLimit column should be dependent on our primary key columns.  Logically, our OrderLimit is determined based on the combination of a CustomerID and a ProductID, so physically this table design makes sense and is fully normalized.  If our primary key is just a meaningless auto-generated identity column, it doesn’t make logical sense since our OrderLimit is not dependent on that.&lt;br /&gt;
&lt;br /&gt;
Some people argue that having more than one column in a primary key “complicates things” or “makes things less efficient” rather than always using identity columns.  This is simply not the case.   We’ve already established that you &lt;span style="font-style: italic;"&gt;must &lt;/span&gt;add additional unique constraints to your data to have integrity, so instead of just:&lt;br /&gt;
&lt;ol&gt;
    &lt;li&gt;A single indexed composite primary key that uniquely constrains our data&lt;/li&gt;
&lt;/ol&gt;
we instead need:&lt;br /&gt;
&lt;ol&gt;
    &lt;li&gt;An additional identity column&lt;/li&gt;
    &lt;li&gt;A primary key index on that identity column&lt;/li&gt;
    &lt;li&gt;An additional unique constraint on the columns that logically define the data&lt;br /&gt;
    &lt;/li&gt;
&lt;/ol&gt;
So we are actually &lt;span style="font-style: italic;"&gt;adding &lt;/span&gt;complexity and overhead to our design, not simplifying!  And we are requiring more memory and resources to store and manipulate data in our table.&lt;br /&gt;
&lt;br /&gt;
In addition, let's remember that a data model can be a complicated thing.  We have all kinds of tables that have primary keys defined that let us identify what they are modeling, and we have relations and constraints and data types and the rest.  Ideally, you should be able to look at a table's primary key and understand what it is all about, and how it relates to other tables, and not need to basically ignore the primary key of a table and instead investigate unique constraints on that table to &lt;span style="font-style: italic;"&gt;really&lt;/span&gt; determine what is going on!  It simply makes no sense and adds unnecessary confusion and complication to your schema that is so easily avoided.&lt;br /&gt;
&lt;br /&gt;
Some people will claim that being able to quickly label and identify the relation of a Product to a Customer with a single integer value makes things easier, but again we are over-complicating things.  If we only know we are editing CustomerProductID #452 in our user interface, what does that tell us?  Nothing!  We need to select from the CustomerProducts table every time just to get the CustomerID and the ProductID that we are dealing with in order to display labels or descriptions or to get any related data from those tables.  If, instead, we know that we are editing CustomerID #1 and productID #6 because we are using a true, natural primary key of our table, we don’t need to select from that table at all to get those two very important attributes.&lt;br /&gt;
&lt;br /&gt;
There are lots of complexities and many ways to model things, and there are many complicated situations that I did not discuss here.  I am really only scratching the surface.  But my overall point is to at least be aware of composite primary keys, and the fact that a primary key is not always a single auto-generated column.   There are pros and cons to many different approaches, from both a logical design and physical performance perspective, but please consider carefully the idea of making your primary keys count for something and don’t automatically assume that just tacking on identity columns to all of your tables will give you the best possible database design.&lt;br /&gt;
&lt;br /&gt;
And, remember -- when it comes to &lt;span style="font-style: italic;"&gt;defining&lt;/span&gt; your entities, I understand that using an identity or GUID or whatever you like instead of real-world data has advantages.  It is when we &lt;span style="font-style: italic;"&gt;relate &lt;/span&gt;entities that we should consider using those existing primary key columns from our entity tables (however you had defined them) to construct an intelligent and logical and &lt;span style="font-style: italic;"&gt;accurate&lt;/span&gt; primary key for our entity relation table to avoid the need to create extra, additional identity columns and unique constraints.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-style: italic;"&gt;see also:&lt;br /&gt;
&lt;/span&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/08/15/60287.aspx" title="View Entry"&gt;The problem isn't the poor database model; It's that external code is bound to the schema&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/07/24/60266.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl04_HyperLink1"&gt;Distinguishing data from code&lt;/a&gt; 				 				&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/07/03/60248.aspx" title="View Entry"&gt;Data Types -- The Easiest Part of Database Design&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/06/19/60238.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl08_HyperLink1"&gt;SQL Data Modeling: Entities versus Attributes&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/06/05/60223.aspx" title="View Entry"&gt;Don't Let Output Dictate your Database Design&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2007/04/24/60186.aspx" title="View Entry" id="ctl00_pageContent_Editor_Results_rprSelectionList_ctl10_HyperLink1"&gt;Custom Auto-Generated Sequences in SQL Server&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2006/02/10/9002.aspx" title="View Entry"&gt;Data belongs in your tables -- not in your code&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="../../../../jeffs/archive/2004/10/07/2190.aspx" title="View Entry"&gt;Delete Duplicates And Resolve Foreign Key References in SQL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60306.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/08/23/composite_primary_keys.aspx</guid>
            <pubDate>Thu, 23 Aug 2007 14:07:20 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60306.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/08/23/composite_primary_keys.aspx#feedback</comments>
            <slash:comments>51</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60306.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60306.aspx</trackback:ping>
        </item>
        <item>
            <title>The problem isn't the poor database model; It's that external code is bound to the schema</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/08/15/60287.aspx</link>
            <description>Dealing with poorly designed databases is a simple and common fact of life for programmers.  It happens, sometimes due to lack of experience or education, or sometimes because business requirements were never analyzed properly or they changed.   It's hard to avoid poor database designs, but it takes only a simple concept to make fixing those designs much easier.  &lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2007/08/15/60287.aspx"&gt;read more...&lt;/a&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60287.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/08/15/60287.aspx</guid>
            <pubDate>Wed, 15 Aug 2007 13:34:26 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60287.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/08/15/60287.aspx#feedback</comments>
            <slash:comments>7</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60287.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60287.aspx</trackback:ping>
        </item>
        <item>
            <title>Distinguishing data from code</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/07/24/60266.aspx</link>
            <description>What is data, and what is code?  How do we define the difference, and decide what goes where?  It is great to say "keep data out of your code", but what if that data is integral to the application itself?  Isn't it therefore code, and not data?  &lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2007/07/24/60266.aspx"&gt;read more...&lt;/a&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60266.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/07/24/60266.aspx</guid>
            <pubDate>Tue, 24 Jul 2007 13:02:43 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60266.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/07/24/60266.aspx#feedback</comments>
            <slash:comments>18</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60266.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60266.aspx</trackback:ping>
        </item>
        <item>
            <title>Data Types -- The Easiest Part of Database Design</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/07/03/60248.aspx</link>
            <description>I see it time and time again in forums -- "dates" that don't sort properly, "numbers" that don't add correctly, "boolean" data with 10 different values, and so on ... Since we are rarely provided any DDL to review, it often takes many posts going back and forth until we finally realize: "wait ... you aren't using a datetime data type to store these dates?!"  &lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2007/07/03/60248.aspx"&gt;read more...&lt;/a&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60248.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/07/03/60248.aspx</guid>
            <pubDate>Tue, 03 Jul 2007 14:13:12 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60248.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/07/03/60248.aspx#feedback</comments>
            <slash:comments>8</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60248.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60248.aspx</trackback:ping>
        </item>
        <item>
            <title>Retrieving Identity Values When Inserting Multiple Rows</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/07/02/60246.aspx</link>
            <description>You're INSERTing multiple rows from an un-normalized import table.  Each row is assigned an identity primary key.  You know you can use scope_identity() to retrieve one identity at a time, but how do you retrieve a whole set of them? Are cursors the only answer?  As usual, it depends on having logical specifications and a good design. &lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2007/07/02/60246.aspx"&gt;read more..&lt;/a&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60246.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/07/02/60246.aspx</guid>
            <pubDate>Mon, 02 Jul 2007 16:31:17 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60246.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/07/02/60246.aspx#feedback</comments>
            <slash:comments>6</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60246.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60246.aspx</trackback:ping>
        </item>
        <item>
            <title>Passing an Array or Table Parameter to a Stored Procedure</title>
            <link>http://weblogs.sqlteam.com/jeffs/archive/2007/06/26/60240.aspx</link>
            <description>SQL is a set-based language, and often we wish to pass sets of data as a parameter to a stored procedure. For example, you might wish to pass a set of Customers to an invoice generating stored procedure, or a set of employees for which you’d like to calculate a particular bonus.  SQL Server already has everything you need to do this, and you don't need CSV or XML strings. &lt;a href="http://weblogs.sqlteam.com/jeffs/archive/2007/06/26/60240.aspx"&gt;read more...&lt;/a&gt;&lt;img src="http://weblogs.sqlteam.com/jeffs/aggbug/60240.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Jeff Smith</dc:creator>
            <guid>http://weblogs.sqlteam.com/jeffs/archive/2007/06/26/60240.aspx</guid>
            <pubDate>Tue, 26 Jun 2007 13:36:11 GMT</pubDate>
            <wfw:comment>http://weblogs.sqlteam.com/jeffs/comments/60240.aspx</wfw:comment>
            <comments>http://weblogs.sqlteam.com/jeffs/archive/2007/06/26/60240.aspx#feedback</comments>
            <slash:comments>24</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/jeffs/comments/commentRss/60240.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/jeffs/services/trackbacks/60240.aspx</trackback:ping>
        </item>
    </channel>
</rss>