Click here to Skip to main content
15,892,298 members
Articles / Programming Languages / SQL

Writing Server Indifferent SQL

Rate me:
Please Sign up or sign in to vote.
3.06/5 (8 votes)
2 Feb 2009CPOL6 min read 29.5K   15   11
An article on how to write SQL that runs against all(?) data bases

Introduction

In many (if not in most) cases, development projects have an advanced knowledge of the type of data server they are about to interact with. When building an isolated application for a specific customer, the customer's server is given (or decided upon) for the specific project. When developing a web-based application or service, the backing storage is an integral part of the system design. Services enjoy the boundary-less world of XML and even most off-the-shelf applications are designed for a specific database. Nevertheless, sometimes you need to write an application that produces SQL queries that may be run against an unspecified server. This article briefly describes (some of) what you might want to know when encountering such a situation.

Standards

ANSI-92

SQL has a standard formal definition described by the American National Standards Institute (ANSI). In more than one area, you might come across a standard by these guys. The standard is usually named ANSI something. In the case of SQL, the ANSI standard is ANSI-92, named after its publishing year (replaced ANSI-89). ANSI has since published quite a few new versions of the standard (check SQL in Wikipedia), but the industry moved forward at a greater pace.

Dialects

All commercial database vendors need SQL extensions. This is in part a result of the nature of business vs. standards and in part a result of the definition of SQL as a declarative language rather than a programming language. So they came up with their specific versions of SQL (dialects). Microsoft uses T-SQL (Transact SQL), Oracle has PL/SQL (Procedural language SQL), IBM (DB2) has SQL/PL (well...) and My-SQL uses SQL-PSM (Persistent Store Model).

Common Denominator

Obviously, you would like your SQL to use the "lowest common denominator" of these popular databases in order to be "server indifferent." As far as I was able to determine, all the above mentioned databases support ANSI-92. Therefore, just get your copy of ANSI-92 and make sure to use only what is in it.

Tips

Well, getting a copy of ANSI-92 might be important but looking for everything in it would probably be a bit impractical. The following sections contain some of the things I learned during my experience – use at your own risk...

Piece of Advice

Double check your need for server indifference. The database only gives you so much and finding an alternative implementation for your needs is tricky in most cases and impossible in many. You might want to consider the business logic driving you in that direction and think things over. In my case, I was developing a product to be used with a third party system. The third party system allowed only direct database access by SQL (no stored procedures and no user function) and supported two flavors of database – Microsoft SQL server and IBM DB2. After doing some remarkable SQL acrobatics (and writing most of this article) I went to the bosses and asked them to check our target audience distribution of databases. It turned out less that 0.1% of them were using DB2. They were happy to let me off the hook.

General Stuff

Look for irregular data types. You usually have what you need but I think nvarchar() is not supported and varchar is (this is a bit funny: the 'N' in nvarchar comes from ANSI because these fields support the ANSI standard for characters covering quite a few languages). Do not use column names longer than 16 characters. The function "Convert" is included in ANSI-92. So are "MAX," "MIN" and "AVG." Search the ANSI-92 document for "reserved word."

Stored Procedures

Generally, it is not advised to have strings in your code, let alone SQL. The common way of pushing your SQL out is using stored procedures which are predefined SQL queries stored in the DB. These queries also perform better as they can be cached by the server. This might seem as irrelevant as you can use ANSI-92 compliant SQL in or out of a stored procedure. The thing is, ANSI-92 has no notion of stored procedures. It seems to me that since all databases now support stored procedures (including My-SQL since 1995 version) it would be wise to use them, but I have read (cannot say when and where) that stored procedures are not recommended in this case so I am quoting to be safe. Make your own checks.

Date Format

The date format compatible with all data bases is: YYYYMMDD. Thanks to the reader 'los' and to Tony Rogerson.

Validating ANSI-92 Compliance with Ms-SQL SQL Server

If you happen to be using SQL-Server Management studio, you can make sure your SQL is ANSI-92 compliant. Add the following statement at the head of your query:

SQL
SET FIPS_FLAGGER 'full'

You would get a message every time your SQL violates ANSI-92. Note the standard SQL Server validates not ANSI-92 but rather FIPS 127-2. To the best of my knowledge, they are the same in all relevant aspects. On MSDN, they say "This is based on the ISO standard."

Getting to the Top

The last thing I have come across is this: the first problem you are about to encounter once you have adopted the ANSI-92 SQL approach is selecting a specific number of records from a table. How do I know that? Well, it happened in my development team (twice), and while I was searching the net for issues related to specific SQL dialects, I found more answers to this question than I would care to remember (each dialect has a completely different approach here. I find this example very educating when discussing this problem). I came up with a way to select the first record (equivalent to T-SQL - TOP 1) and it is explained here:

Suppose you want the oldest customer in your DB. T-SQL would spell:

SQL
SELECT TOP 1 CustID 
FROM Customers 
ORDER BY BirthDate ASC

Now, since we cannot use TOP, we have to define a WHERE clause that eliminates all but one row. Here is how it is done:

SQL
SELECT CustID 
FROM Customers 
    WHERE (BirthDate =(SELECT MIN(BirthDate) 
    FROM Customers))

Note that the WHERE should be defined so that it yields only one record. If you have two elderlies with the same birth date you might find yourself in somewhat of a tight spot. In such a case, please consider which one you really want. When you get that right, polish your inner select. If you have exhausted your options and still cannot be sure you get only one record use DISTINCT (included in ANSI-92). This scenario is common when selecting only one child of a parent record (for instance, selecting the last price set for the item). In such cases you have three nested queries and you have to make absolutely sure you get only one result or else your query will fail, and worse, it might pass sometimes and fail at other times.

As to selecting more than one record from the top of a result set, I have a few things to say:

  • If you find yourself needing this, you are in violation of the Zero-One-Infinity rule. Check again if you really need it.
  • It may be achieved using this technique: use a union between queries, each selecting one row. Each query should be formulated roughly like the one mentioned earlier but the WHERE clause should remove records already chosen (this is achieved by nastily nesting the previous queries). This is such a bad query that I will not even give an example.

Disclaimer

I am not a DBA, nor am I an SQL expert. I just fell into this hole and I am shouting from the deep darkness for the benefit of another innocent passer-by. I would be happy to receive any kind of extensions for this either by e-mail or replies.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer Ziv systems, Israel
Israel Israel
Starting with Apple IIe BASICA, and working my way through Pascal, Power Builder, Visual basic (and the light office VBA) C, C++, I am now a full stack developer and development manager. Mostly with MS technologies on the server side and javascript(typescript) frameworks on the client side.

Comments and Discussions

 
GeneralWhy not... Pin
Colin Angus Mackay3-Feb-09 4:39
Colin Angus Mackay3-Feb-09 4:39 
AnswerRe: Why not... Pin
Asher Barak4-Feb-09 10:21
professionalAsher Barak4-Feb-09 10:21 
GeneralRe: Why not... Pin
Colin Angus Mackay4-Feb-09 21:43
Colin Angus Mackay4-Feb-09 21:43 
AnswerRe: Why not... Pin
Asher Barak7-Feb-09 9:23
professionalAsher Barak7-Feb-09 9:23 
Hi Colin

I apologize for being so brief on my reply and try to elaborate here:

The basic solution for data access in design methodology would include a business layer, connecting do a data access layer, connecting to a data base, preferably using stored procedures.
Supposing we would eventually be speaking to a relational database, we try to isolate both the data access (by using the DAL gateway) and the SQL composition (by creating business objects in the business layer). Using a third party business objects (ORM) is, in effect, moving the SQL composition to more specialized hands, which, among other stuff, take care of addressing other databases for us.
This is probably the way to go and it does take care of most of the SQL. However, in the real world we still do get to write some SQL (for this matter any non generated SQL would be writing SQL weather it is somewhere in code or in a stored procedure). In the practical level, consider business processes where data should be retrieved on complex sets of criteria. Creating our business objects to handle every data retrieval scenario is impossible and definitely costly in terms of time and money. In a more abstract level, consider the fact that no matter how we wrap our SQL generation, our wraper can never provide the power of SQL itself. Therefore, we might end up writing SQL (the new entity framework and LINQ to SQL might improve things here though I am hearing they are <a href="http://efvote.wufoo.com/forms/ado-net-entity-framework-vote-of-no-confidence/">getting some heat</a>[<a href="http://efvote.wufoo.com/forms/ado-net-entity-framework-vote-of-no-confidence/" target="_blank" title="New Window">^</a>] at the moment, and considering <a href="http://realworldsa.dotnetdevelopersjournal.com/goodbyewindowsworkflowfoundationseeyouin2011.htm">Microsoft's recent move with WF</a>[<a href="http://realworldsa.dotnetdevelopersjournal.com/goodbyewindowsworkflowfoundationseeyouin2011.htm" target="_blank" title="New Window">^</a>], I wouldn't rush into it).
Now, if we have really little "direct" SQL, we would probably rewrite it for each database and enjoy the power of specific SQL dialects. I tried to emphasize using generic SQL is a last resort but I failed to mention that, when everything else is in our hands, you proposition (ORM + little server specific "direct" SQL) is the way to go. I tried to deal with: "What to do when you need server indifferent SQL?" and neglected "How to design to avoid needing server indifferent SQL?". I hope to post a correction soon.

As a side note, I would like to describe the situation that drove me into this (dark and narrow) alley: I was (and still am) building a product that integrated into another product. My data access is restricted to working via the hosting app DAL. I can perform SELECT queries but inserts updates are preformed via an object of the hosting system. I clearly couldn't use an ORM system with no db access. Worse, I have no idea what database I am working with in a given installation and I am not allowed to use stored procedures or views (at all). I did separate my data access and automated some data retrieval but still had serious SQL to consider. This is another situation where reality of a given application required some re-thinking of classic design.

Take care,

Asher

P.S.

I haven’t recognized you the first time around. I am a fan of your work here, especially of your SQL injection article.
GeneralMy vote of 2 Pin
pvandijk282-Feb-09 20:59
professionalpvandijk282-Feb-09 20:59 
GeneralRe: My vote of 2 Pin
Colin Angus Mackay3-Feb-09 4:36
Colin Angus Mackay3-Feb-09 4:36 
GeneralMy vote of 2 Pin
CKR_12-Feb-09 15:40
CKR_12-Feb-09 15:40 
JokeRe: My vote of 2 Pin
Asher Barak2-Feb-09 18:47
professionalAsher Barak2-Feb-09 18:47 
GeneralMy vote of 2 Pin
Marc Scheuner29-Jan-09 2:56
professionalMarc Scheuner29-Jan-09 2:56 
GeneralThe date format Pin
los.28-Jan-09 22:06
los.28-Jan-09 22:06 
AnswerRe: The date format Pin
Asher Barak1-Feb-09 6:50
professionalAsher Barak1-Feb-09 6:50 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.