tags:

views:

849

answers:

6

I need to write a a query that gets a set of information from a table, but if there is no information for that specific client, then use the default set. I was wondering if there is a way to avoid query duplication in an if(exists()) statement.

For example:

IF( EXISTS( SELECT * FROM UserTable WHERE Name = @UserName))
BEGIN
    SELECT * FROM UserTable WHERE Name = @UserName))
END
ELSE
BEGIN
    SELECT * FROM UserTable WHERE Name = 'Jon Skeet'))
END

The first two selects (exists and the true part of the if) are the exact same. I want to avoid running the same query twice if the statement is true. I know the exists stops once the first true condition is met but that is still O(n) worst case.

Another option I know of, is put the information in a temp table and check if information is there, if not return the default information.

Both ways would work but what is the best way to do it? Are there other ways to do this? Is there some way to do this in the WHERE clause since that's the only thing that is different?

Edit: Fixed example to return a row not just a single item. So the answers of dumping the select to a single variable would be equal to a temp table I assume. Also, to not anger Jon Skeet, spelled his name right

+1  A: 

You can select into a variable check the variable if it comes back null run the get default query

something like this:

Declare @uID int;

SELECT @uID = UserID FROM UserTable WHERE Name = @UserName

IF (@uID is null)
begin 
'Select default here'
End

select @uID
Jeremy
+3  A: 

How about:

DECLARE @UserID int;
SELECT @UserID = UserID FROM UserTable WHERE Name = @UserName

IF(@UserID IS NULL)
BEGIN
    SELECT @UserID=UserID FROM UserTable WHERE Name = 'Jon Skeet'))
END

SELECT @UserID
JerSchneid
This works for selecting a single variable, what about a complete row(fixed the example in the question)? This would be the same as using a temp table. Would you consider a temp table good for this or would that be adding too much complexity that you don't need?
Joe Stropich
I don't think you need a temp table (but I wouldn't be afraid of them either). I like @Tom H's first answer if you want to do a SELECT *
JerSchneid
A: 

You don't say what DBMS you are using, but it clearly isn't Oracle (which is the one I know). However, I would expect your DBMS would allow you to do something like this pseudo-code:

SELECT UserID FROM UserTable WHERE Name = @UserName
IF <no data returned by that> 
BEGIN
    SELECT UserID FROM UserTable WHERE Name = 'John Skeet'
END

In Oracle this would be:

BEGIN
    SELECT UserID INTO v_UserID FROM UserTable WHERE Name = :UserName;
EXCEPTION
    WHEN NO_DATA_FOUND THEN
    SELECT UserID INTO v_UserID FROM UserTable WHERE Name = 'John Skeet';
END
Tony Andrews
+4  A: 

You could do this:

SELECT TOP 1
     UserID
FROM
     UserTable
WHERE
     Name IN (@UserName, 'John Skeet')
ORDER BY
     CASE WHEN Name = 'John Skeet' THEN 2 ELSE 1 END

(or use LIMIT or whatever the method is for your RDBMS)

Or you could do this:

DECLARE @UserID INT

SELECT
     @UserID = UserID
FROM
     UserTable
WHERE
     Name = @UserName

IF (@UserID IS NULL)
     SELECT
          @UserID = UserID
     FROM
          UserTable
     WHERE
          Name = 'John Skeet'

SELECT @UserID AS UserID

Or this:

SELECT
     COALESCE(T2.UserID, T1.UserID)
FROM
     UserTable T1
LEFT OUTER JOIN UserTable T2 ON
     T2.Name = @UserName
WHERE
     T1.Name = 'John Skeet'

Or this:

SELECT
     UserID
FROM
     UserTable
WHERE
     Name = @UserName

IF (@@ROWCOUNT = 0)  -- MS SQL Server specific, your RDBMS method will vary
     SELECT
          UserID
     FROM
          UserTable
     WHERE
          Name = 'John Skeet'
Tom H.
That is a lot of options!
JerSchneid
A: 

Unless you are going to define a set of variables for each field you are returning (and it's only one record) I think the most efficent way is to make the call twice. The temp table would probably cost more.

Josh
+1  A: 

If you are concerned about performance, I think you probably don't need to be - most DBMSes should optimize away the duplication. If you are still concerned about performance, run it both ways to see if your DBMS has any problem with it.

If you're concerned about code - maintainability of duplicate code sections, readability, and the like, then study the above answers with that in mind. You may find that the duplication is your least-worst option. It's a shame SQL isn't more malleable.

Carl Manaster