Click here to monitor SSC
Av rating:
Total votes: 29
Total comments: 16


Joe Celko
The DIS-Information Principle, Part II
01 September 2010

Database design simply involves populating a schema with tables that model sets of entities and relationships.  A table will contain Columns that model  an entity's attributes and contain scalar values. What could go wrong? Plenty, unfortunately, when these simple principles are misunderstood or flouted,  and Joe continues to itemise bad design practices that can cause subsequent grief for the application developers.

We've covered the a series of bad practices in database design that come from the habit of 'splitting'  tables and columns. This  is only one family of RDBMS design errors. There are plenty of other disasters awaiting the data modeler. You can always fix bad  queries by replacing them with good ones, but DDL design errors effect everything and the best query in the world cannot save you.

If I can touch it, it is probably an entity.
If I have to describe it with a verb of being,
 it is probably a relationship.
If I measure it on a scale, it is probably an
attribute.

The principles behind the design of relational databases  sound pretty simple, neat and clean; but apparently the task is harder than it looks. Beginners in any field will tend to make the same kind of errors in their data models and eventually the errors get a name. There is “attribute splitting”, “column overloading” and “EAV” (Entity-Attribute-value) to name a few Data Definition Language (DDL) errors. But the one thing that they have in common is confusing entities, attributes and values and modeling them wrongly.

Misplaced Columns

Putting a column in the wrong table sounds almost absurd, but it is common. The most extreme example of which I heard was on an interview question which asked for a skeleton of the classic Sybase /SQL Server Bookstore schema. The failed candidate put the price of the book as an attribute of the Buyer. Hey, he pays it, doesn't he?

Nope, the price of a book is clearly an attribute of the book. Duh. It might be modified by the buyer because he has some special status (a buyer attribute), but that is another issue.

I will guess that this is most often from having a 1:1 relationship that gets embedded into a one or both tables. If you have a table of husbands (husband_id as its key), then each guy must have a wife. That is what makes him a husband, right? So we add a wife column to the table. Likewise, if you have a table of wives (wife_id as its key), then each gal must have a husband. That is what makes her a wife, right? So we add a husband column to the table. Now there is a cycle where the two tables reference each others key.

The problem is a failure to see that a marriage is a relationship and needs its own table. The (husband_id, wife_id) pair is a natural key and they reference the two tables involved. Because a marriage has other attributes (wedding dates, license number, presiding official, etc.), this is easy to see. But if the relationship has no other attributes, it simply gets put in the wrong place.

Inconsistent Data Element Modeling

This nightmare is having something mutate from a value, entity or attribute in the same schema to something else.

A recent posting on a newsgroup had two tables that look like this. Well, since the original poster never bothered to give DDL and thought we could understand his narrative and personal programming language. He also did not know that movies are identified by the ISAN (International Standard Audiovisual Number), the way that a VIN identifies a vehicle. You can Google (http://www.isan.org/). But one example is ISAN 0000-3BAB-9352-0000-G-0000-0000-Q. Yes, it is weird, long and ugly but it is now required by law in many countries and therefore in common usage in that industry.

His first table was the release dates for five particular movies, thus:

CREATE TABLE MovieReleaseDates –- no key, multiple rows
(movie1 DATE NOT NULL,
 movie2 DATE NOT NULL,
 movie3 DATE NOT NULL,
 movie4 DATE NOT NULL,
 movie5 DATE NOT NULL);

Does the idea that a movie title is an attribute of a date seem weird to you? Me too. The second table is also strange. Here is a guess at the DDL he never posted, based on vague sample data.

CREATE TABLE MovieReleaseLocation –- no key, multiple rows
(city_name VARCHAR(25) NOT NULL,
 movie_title VARCHAR(25) NOT NULL,
 release_date DATE,
 PRIMARY KEY (city_name, movie_title, release_date));

Did you notice that a movie title has changed from an attribute to a value taken from the domain {'movies1', 'movies2', 'movies3', 'movies4', 'movies5'}? Does that make sense? Nope! The title has to an entity, attribute or value everywhere in the data model.

His challenge was to find out which movies are released on which dates and in which cities. He insisted that he needs both tables because the release dates in the first table must match to locations in the second table in some way. The schema should have been something like this:

CREATE TABLE Movies –- Entities with an ISO identifier
(isan CHAR (35) NOT NULL PRIMARY KEY
 CHECK (isan LIKE..), –- regular expression?
 movie_title VARCHAR(255) NOT NULL,
 etc);

CREATE TABLE TheaticalReleases
(isan CHAR(35) NOT NULL NOT NULL
  REFERENCES Movies(isan),
 city_name VARCHAR(35) NOT NULL,
 state_code CHAR(2) NOT NULL, –- USPS codes
 release_date DATE NOT NULL, –- UTC?
 PRIMARY KEY (isan, city_name, state_code, release_date),
 etc);

You do not just throw a movie out the door to no place in particular on Tuesday. You might have cities bidding for it or unknown premiere dates, so you make so you make the future time/space attributes NULL-able in the worst case. And that would change my guess at the key for that table. Without better specs I can only guess.

What he showed was something like a bad calendar or spreadsheet printout. In the actual posting, he was concatenating movie titles with a date in a cell in a spreadsheet!

Schema Splitting

The extreme case is putting data into multiple databases. Before we had federated databases, this was done out of necessity most of the time. It was not always physically or practically possible to put all of the enterprise data into one centralized database. A federated database is similar to a partitioned database in that it has the power to present a unified logical view of the schema from a disjoint physical system.

In a federated database, the system maintains the relationships among the databases and (we hope) keeps the data consistent (i.e., every DB is on UTC, uses the same set of measures, the same data element names, etc.) so that the data belongs to one central data model and not a bunch of local data models that do not match.

EAV (Entity-Attribute-Value) Tables

Entity-Attribute-Value models have the user doing meta-data in the database. He produces things that belong in the schema information tables, but without any data integrity. The excuse for it is that you can make a database "on the fly" when you have not done any research and do not care about data integrity.

This is an actual example from an old newsgroup posting, with a little clean up. The table names are very generic and describe meta-data. The first table is simply EAV, and it contains the name of a column (attribute) and the possible values that are allowed in that column.

CREATE TABLE EAV -- no key declared

(key_col VARCHAR (10), -- what does null mean?

  attrib_value VARCHAR (50)); -- allow nulls

Since we wanted to allow NULLs, the attribute value column has to be NULL-able. But the key_col column has to be repeated and cannot be a key. We also don't know anything about data types because we have no idea what any particular attribute might be until insertion time. Hey, we can cast VARCHAR(n) to any data type we need, so everything -- dates, numeric values, etc.,-- becomes a string. I am violating an EAV design rule by only making that column 50 charters wide; since you might want to store a huge string, you should use the longest possible string for everything. Lets load this table.

INSERT INTO EAV

VALUES ('LOCATION', 'Bedroom'),

        ('LOCATION', 'Dining Room'),

        ('LOCATION', 'Bathroom'),

        ('LOCATION', 'courtyard'),

        ('EVENT', 'verbal aggression'),

        ('EVENT', 'peer'),

        ('EVENT', 'bad behavior'),

        ('EVENT', 'other');

Now we discover that this database has to do with domestic violence. Finding out what your database does after you create it is not a good design principle. But do not worry, if you want to put a snake farm management system into this table!

Now we need some data for this thing. Not particular, specific data, but vague generic data which does into a second table called EAV_Data. There is no such thing as a generic key that identifies all things in creation. That is a belief from Kabbalah numerological mysticism, in which God puts a number on everything in Creation. We have the equally mystical IDENTITY table property instead, so EAV tends to use it whenever it needs a key.

CREATE TABLE EAV_Data --no constraints, defaults or DRI

(id INTEGER IDENTITY (1,1) NOT NULL PRIMARY KEY, --vague names

  bts_id INTEGER NULL,

  key_col VARCHAR (10),

  attrib_value VARCHAR (50));


INSERT INTO EAV_Data

VALUES (1, 'LOCATION', 'Bedroom'),

        (1, 'EVENT', 'other'),

        (1, 'EVENT', 'bad behavior'),

        (2, 'LOCATION', 'Bedroom'),

        (2, 'EVENT', 'other'),

        (2, 'EVENT', 'verbal aggression'),

        (3, 'LOCATION', 'courtyard'),

        (3, 'EVENT', 'other'),

        (3, 'EVENT', 'peer');

The query we want is a simple count of the events by location. Here is the sample data in a grid:

Bedroom verbal aggression 1

Bedroom peer 0

Bedroom bad behavior 0

Bedroom other 2

Dining Room verbal aggression 0

Dining Room peer 0

Dining Room bad behavior 0

Dining Room other 0

Bathroom verbal aggression 0

Bathroom peer 0

Bathroom bad behavior 0

Bathroom other 0

courtyard verbal aggression 0

courtyard peer 1

courtyard bad behavior 0

courtyard other 1

Since this a lot of zeros, another query that drops the zeros out of the results:

Location Event count

Bedroom verbal aggression 1

Bedroom other 2

courtyard peer 1

courtyard other 1

Here is an answer From: Thomas Coleman

SELECT Locations.locationvalue, Events.eventvalue,

       (SELECT COUNT(*)

          FROM (SELECT LocationData.locationvalue, EventData.eventvalue

                  FROM (SELECT TD1.bts_id, TD1.value AS locationvalue

                          FROM eav_data AS TD1

                         WHERE TD1.key = 'location') AS LocationData

               INNER JOIN

               (SELECT TD2.bts_id, TD2.value AS eventvalue

              FROM eav_data AS TD2

              WHERE TD2.key = 'event'

            ) AS EventData

            ON LocationData.bts_id = EventData.bts_id

      ) AS CollatedEventData

    WHERE CollatedEventData.locationvalue = Locations.locationvalue

      AND CollatedEventData.eventvalue = Events.eventvalue 

FROM (SELECT T1.value AS locationvalue

      FROM EAV AS T1

      WHERE T1.key = 'location') AS Locations,

   (SELECT T2.value AS eventvalue

      FROM EAV AS T2

     WHERE T2.key = 'event') AS Events

ORDER BY Locations.locationvalue, Events.eventvalue ,

SELECT Locations.locationvalue, Events.eventvalue

       (SELECT COUNT(*)

          FROM (SELECT LocationData.locationvalue, EventData.eventvalue

                  FROM (SELECT TD1.bts_id, TD1.value AS locationvalue

                          FROM eav_data AS TD1

                         WHERE TD1.key = 'location') AS LocationData

              INNER JOIN

              (SELECT TD2.bts_id, TD2.value AS eventvalue

                 FROM eav_data AS TD2

                WHERE TD2.key = 'event') AS EventData

              ON LocationData.bts_id = EventData.bts_id)

              AS CollatedEventData

    WHERE CollatedEventData.locationvalue = Locations.locationvalue

      AND CollatedEventData.eventvalue = Events.eventvalue)

FROM (SELECT T1.value AS locationvalue

        FROM EAV AS T1

      WHERE T1.key = 'location') AS Locations,

    (SELECT T2.value AS eventvalue

       FROM EAV AS T2

       WHERE T2.key = 'event') AS Events;

This has subquery expressions nested inside each other to do the simplest task because each base table in a proper design has to be built on the fly, over and over. Her is the same query in a proper schema with a table for Locations and one for Events.

SELECT L.locationvalue, E.eventvalue, COUNT(*)

  FROM Locations AS L, Events AS E

 WHERE L.btd_id = E.btd_id

 GROUP BY L.locationvalue, E.eventvalue;

The column names are seriously painful. Don't use reserved words like "key" and "value" for column names. It means that the developer *has* surround the column name with double quotes for everything. And they are too vague to be data element names anyway!

     "To be is to be something
in particular; to be nothing
in particular is to be nothing."
 --Law of Identity

All data integrity is destroyed. Any typo becomes a new attribute or entity. Entities are found missing attributes, so all the reports are wrong.

Try to write a single CHECK() constraint that works for all the attributes of those 30+ entities your users created because you were too dumb or too lazy to do your job. It can be done! You need a case expression almost 70 WHEN clauses for a simple invoice and order system when I tried it as an exercise.

Try to write a single DEFAULT clause for 30+ entities crammed into one column. Impossible!

Try to set up DRI actions among the entities. If you thought the WHEN clauses in the single CASE expression were unmaintainable, wait until you see the "TRIGGERs from Hell" -- Too bad that they might not fit into older SQL Server which had some size limits. Now maintain it.

For those who are interested, there are a few of links to articles that I found on the net:

A really good horror story about this kind of disaster is here.

Conclusions

It is not that hard to design a good schema. It is mostly common sense and simple questions about the nature of the things in your universe of discourse. If I can touch it, it is probably an entity. If I have to describe it with a verb of being, it is probably a relationship. If I measure it on a scale, it is probably an attribute. Those simple questions will cover 80-85% of your real-world design situations. After that, you have to think about things a little more.



This article has been viewed 6016 times.
Joe Celko

Author profile: Joe Celko

Joe Celko is one of the most widely read of all writers about SQL, and was the winner of the DBMS Magazine Reader's Choice Award four consecutive years. He is an independent consultant living in Austin, TX. He has taught SQL in the US, UK, the Nordic countries, South America and Africa.
He served 10 years on ANSI/ISO SQL Standards Committee and contributed to the SQL-89 and SQL-92 Standards.
He has written over 800 columns in the computer trade and academic press, mostly dealing with data and databases. He is the author of eight books on SQL for Morgan-Kaufmann, including the best selling SQL FOR SMARTIES.
Joe is a well-known figure on Newsgroups and Forums, and he is famous for his his dry wit. He is also interested in Science Fiction.

Search for other articles by Joe Celko

Rate this article:   Avg rating: from a total of 29 votes.


Poor

OK

Good

Great

Must read
 
Have Your Say
Do you have an opinion on this article? Then add your comment below:
You must be logged in to post to this forum

Click here to log in.


Subject: 666
Posted by: BuggyFunBunny (view profile)
Posted on: Friday, September 03, 2010 at 7:51 AM
Message: Such a wonderfully sharp tongue. I sometimes get upbraided for being uber-Pascal, but there come some times when the Emperor must be revealed as without raiment.

I will admit to having created, under duress (my bosses were still thinking in COBOL COPYBOOK ways), a One True Lookup Table. The reason this was demanded was that the "business analysts" (allegedly the Subject Matter Experts) couldn't state what the data should be. They would make it up on the fly.

Subject: Your using bad practice on your INSERTs!
Posted by: Tony Rogerson (not signed in)
Posted on: Saturday, September 04, 2010 at 11:15 PM
Message: For an article about best practice design I'm shocked to see you are not naming columns on the INSERT and relying on the physical order they were added to the table. Also your example using the IDENTITY property doesn't even work because of it!

INSERT INTO EAV_Data
VALUES ('LOCATION', 'Bedroom'),
('EVENT', 'peer');

Never ever ever ever write SQL like this - its about as bad as it gets and can lead to values being put in the wrong columns in the table.

INSERT INTO EAV_Data ( key_col, attrib_value )
VALUES (1, 'LOCATION', 'Bedroom'),
(3, 'EVENT', 'peer');


Also, your example....

CREATE TABLE EAV_Data --no constraints, defaults or DRI

(id INTEGER IDENTITY (1,1) NOT NULL PRIMARY KEY, --vague names
bts_id INTEGER NULL,
key_col VARCHAR (10),
attrib_value VARCHAR (50));

This does not work because you've haven't named columns (did you test any of this Joe?).

INSERT INTO EAV_Data

VALUES (1, 'LOCATION', 'Bedroom'),
(1, 'EVENT', 'other');


To correct the article....

INSERT INTO EAV_Data ( bts_id,
key_col,
attrib_value )

VALUES (1, 'LOCATION', 'Bedroom'),
(1, 'EVENT', 'other');


One further point, the magical IDENTITY property is fine and conforms to the latest ratified ISO SQL 2008 for use as a surrogate key - most people do that and understand that so your tirade on the general use of IDENTITY is very miss placed.

All in all, good points and yes mistakes like that do get made.

Subject: Re: Your (sic) using bad practice on your INSERTs!
Posted by: SQLServerThoughtPolice (not signed in)
Posted on: Tuesday, September 07, 2010 at 11:33 AM
Message: Tony;

There seems to be a misunderstanding here. Joe says quite clearly in the article that this code is directly quoted from a Newsgroup and is not his own. He writes 'This is an actual example from an old newsgroup posting, with a little clean up.'

It would certainly be a surprise to see Joe advocating practices that are shown in the EAV example.

Subject: One True Lookup Table
Posted by: Celko (view profile)
Posted on: Tuesday, September 07, 2010 at 2:38 PM
Message: >> I will admit to having created, under duress (my bosses were still thinking in COBOL COPYBOOK ways), a One True Lookup Table. <<

I had a client with a One True Lookup Table where most of the encoding schemes were numeric. An update got screwed up and the wrong encodings got assigned to some of the encoding.

The actual incident was not funny, so when I disguised it in a book as a table with Dewey Decimal and ICD (International Classification of Disease) getting crossed up (both have the format "###.###"). Lok up 259.0 in both encoding was something to do with churches pratices in Dewey and improper sexual development in ICD,

It is good for a laugh in a book, but not in a report.

>> The reason this was demanded was that the "business analysts" (allegedly the Subject Matter Experts) couldn't state what the data should be. They would make it up on the fly. <<

Would you go to an "expert" surgeon who told you he make it up on the fly? Remeber Dr. Nick Rivera on THE SIMPSON'S?





Subject: EAV sucks
Posted by: Anonymous (not signed in)
Posted on: Tuesday, September 07, 2010 at 10:48 PM
Message: nice analysis of the hell that is EAV: http://weblogs.sqlteam.com/davidm/articles/12117.aspx

Subject: Then what should we do
Posted by: Anonymous (not signed in)
Posted on: Wednesday, September 08, 2010 at 2:08 PM
Message: Lots of criticisms in part I and II, but I don't see alternative solutions.

Subject: What you should do
Posted by: BuggyFunBunny (view profile)
Posted on: Wednesday, September 08, 2010 at 7:12 PM
Message: This is a classic. Nearly as snarky as Joe.

http://weblogs.sqlteam.com/davidm/articles/12117.aspx

And, yes, in the comment stream are a few who just don't get data and complain, just as some have here. Oh well. Just remember: It's not nice to fool Mother Nature.

The Prime Directive: data has structure, by definition; if there's no structure, it's not data but merely noise. The younger generation's insistence that their various Byte Heaps are improvements on the relational model/database I attribute to rampant math illiteracy. xml, which started this mess, is a variation on SGML, which is the product of LAWYERS, for Codd's sake.

Subject: If only! If only!
Posted by: Tony Rogerson (not signed in)
Posted on: Thursday, September 09, 2010 at 12:35 AM
Message: Hi SQLServerThoughtPolice,

If only that were the case, alas, most examples in Joe's books and in answers he gives on forums follow the reliance on column postition and number of columns on the INSERT - the bad practice we all know is bad, in fact funnily enough I had it at my client yesterday - my boss had made a copy of a table using INTO and then tried INSERT SELECT * which is basically what Joe is doing, unfortunetly the table structure was different - we only knew it was a problem because we tried to put a varchar value into a datetime column - imagine if the table had the same number of columns and compatible data types - we'd not know!

Tony.


Subject: Rather a blanket condemnation of EAV
Posted by: Sean Fowler (view profile)
Posted on: Thursday, September 09, 2010 at 11:30 AM
Message: I agree that in the examples shown a proper schema is needed, and this is also the case for most database modelling.

However EAV has its place in other areas. Trust me, we've had an EAV system working for 1.5 years and it's a great success.

It's only one part of the system, the vast majority of the database uses conventional modelling. However conventional modelling wasn't appropriate here.

The system needs to allow the storage and retrieval of many small pieces of data (e.g. text); there's no need to report on those pieces of data. What needs to be stored expands on a daily basis, and changing the database structure to accomodate this was unfeasible and unnecessary.

I won't go into details about what we use it for, trade secrets and all that (it's not taxonomy btw). However I can say that given the choice I'd do it again the same way.

I'm speaking from a position of many years' experience of database modelling and of implementing successful EAV models. Knowing when they're the right choice is key; they're certainly not suitable for compensating for fuzzy requirements.

Subject: Standards
Posted by: Dave Poole (not signed in)
Posted on: Friday, September 10, 2010 at 9:03 AM
Message: Joe mentions ISAN. What would be really useful is a short crib-sheet that lists data standards agencies such as IATA, IANA, ISO, ABI, TCU etc.

Where an agency such as ISO exists, the standards that are relevant to data such as ISO 5218, 3166 etc.

Half the battle is finding the standards in the first place the other half is enforcing them!

Subject: Standards
Posted by: Celko (view profile)
Posted on: Tuesday, September 14, 2010 at 11:09 AM
Message: >> What would be really useful is a short crib-sheet that lists data standards agencies such as IATA, IANA, ISO, ABI, TCU etc.<<

Dave, don't you have a copy of my book "Data, Measurements and Standards in SQL" ISBN-13: 978-0123747228?

http://www.amazon.com/Measurements-Standards-Kaufmann-Management-Systems/dp/0123747228/ref=sr_1_1?s=books&ie=UTF8&qid=1284483706&sr=1-1

I even listed the Potrzebie Systems of Weights and Measures by Donald Knuth!

Subject: Text bases
Posted by: Celko (view profile)
Posted on: Tuesday, September 14, 2010 at 11:17 AM
Message: >> The system needs to allow the storage and retrieval of many small pieces of data (e.g. text); there's no need to report on those pieces of data <<

I am not an SQL-only guy. When i have a text problem, I use a "text base" (Document retrieval systems; in my case, it was a labor law library that the client wanted to put into DB2 before I got there.

I stopped working for the prison system before we got fingerprint systems and I have just touched GIS and the 2D and 3D systems that are designed for specialized data and their queries.

Right now I am trying to replace an EAV at a client who has had it up for 5+ years. It is about to fail because they are successful. They just expanded into the UK, Germany and EU, and Australia. The thing will not grow or maintain data integrity. It is hard to run a dot-com when your response time is constantly getting worse.



Subject: Marriage
Posted by: Geoff (view profile)
Posted on: Thursday, September 16, 2010 at 1:53 PM
Message: >The problem is a failure to see that a marriage is a relationship and needs its own table.

Joe,

I've heard some insist that relationship (join) tables should only be used for many-many situations. Polygamy aside, what is your take on that piece of dogma? What about alternatives, Husband referencing Wife directly? Or Spouse with recursive relationship (better for same-sex marriage)?

Subject: Marriage, again
Posted by: BuggyFunBunny (view profile)
Posted on: Thursday, September 16, 2010 at 2:16 PM
Message: The join table accounts, if nothing else, for serial polygamy, rather common in these days. The rest of Joe's statement:

Because a marriage has other attributes (wedding dates, license number, presiding official, etc.), this is easy to see.


Neither issue can be solved without the relation table.

I'll let Joe add a snarky bon mot, if he's so moved.

Subject: woops
Posted by: Geoff (view profile)
Posted on: Thursday, September 16, 2010 at 2:33 PM
Message: Sorry about the double posting. IE did that.

Subject: Using an ISAN would be a huge mistake
Posted by: Seven24 (view profile)
Posted on: Wednesday, January 05, 2011 at 12:34 AM
Message: Movies are not even remotely close to using ISAN numbers universally nor even mostly identified by an ISAN number. The vast majority of movies produced in the US do not have an ISAN number. I happen to know quite a bit about ISAN and currently it is a failure in the US and only used by a few European countries. Movies and derivative works are probably one of the most complicated items to provide a unique identifier. There is rumor of a group right now that is trying to rehash the idea of a universal identifier that the studios will actually use specifically because ISAN is seen as a failure.

Would you like to try your schema again given that movies do not have a unique identifier and can have identical names? Expand your schema to include many types of media like television shows, television movies, clips, audio tracks and add to that the lack of universal organization (or even universal recognition of the terms in some cases) and you have a right ole mess. Of all the problems you attempted to claim were simple to solve, I can tell you that managing media is one of the most complicated.

 










Phil Factor
Automated Script-generation with Powershell and SMO
 In the first of a series of articles on automating the process of building, modifying and copying SQL Server... Read more...



 View the blog
What's the Point of Using VARCHAR(n) Anymore?
 The arrival of the (MAX) data types in SQL Server 2005 were one of the most popular feature for the... Read more...

SQL Source Control: The Development Story
 Often, there is a huge difference between software being easy to use, and easy to develop. When your... Read more...

How to Import Data from HTML pages
 It turns out that there are plenty of ways to get data into SQL Server from websites, whether the data... Read more...

SQL Scripts Manager: An Appreciation
 SQL Scripts Manager is Simple-Talk's present to its readers. William Brewer was an enthusiastic... Read more...

Hosted Team Foundation Server 2010 Review
 Team Foundation Server (TFS) has expanded its remit to support the whole software development process,... Read more...

Beginning SQL Server 2005 Reporting Services Part 1
 Steve Joubert begins an in-depth tour of SQL Server 2005 Reporting Services with a step-by-step guide... Read more...

Ten Common Database Design Mistakes
 Database design and implementation is the cornerstone of any data centric project (read 99.9% of... Read more...

Reading and Writing Files in SQL Server using T-SQL
 SQL Server provides several "standard" techniques by which to read and write to files but, just... Read more...

Beginning SQL Server 2005 Reporting Services Part 2
 Continuing his in-depth tour of SQL Server 2005 Reporting Services, Steve Joubert demonstrates the most... Read more...

Creating CSV Files Using BCP and Stored Procedures
 Nigel Rivett demonstrates some core techniques for extracting SQL Server data into CSV files, focussing... Read more...

Over 400,000 Microsoft professionals subscribe to the Simple-Talk technical journal. Join today, it's fast, simple, free and secure.

Join Simple Talk