Dynamically Changing what table to select from with SQL CASE statement
-
20-08-2019 - |
Question
I'm trying to write a stored procedure and depending on a certain column value, I want to be able to change what table I select from. I'll try to give an example:
SELECT ItemNumber,
ItemType,
Description
FROM
CASE ItemType
WHEN 'A' THEN TableA
ELSE TableB
END
WHERE
CASE ItemType
WHEN 'A' THEN ItemNumber = @itemNumber
ELSE PartNumber = @itemNumber
END
As you can see, not only am I dynamically changing the table I select from, but since these two tables were made at two different times by two different people, the column names are different as well.
So, my question is: What is the best way to accomplish this, since SQL Server doesn't seem to like my query I have constructed.
If anyone who sees what I'm trying to do can suggest a better way to do this, I'd be all ears :-)
Solution
You can not use CASE statement in FROM clause, but you can use the following instead:
SELECT itemnumber, itemtype, description
FROM tablea
WHERE itemnumber = @itemnumber AND itemtype = 'A'
UNION ALL
SELECT itemnumber, itemtype, description
FROM tableb
WHERE partnumber = @itemnumber AND itemtype <> 'A'
OTHER TIPS
You could try building the dynamic SQL statement as a string, and then calling the sp_executesql stored procedure to execute the string.
See here for more information and examples.
I'm not sure why you want to do things in one SQL Statement .. I'm not a SQL Server person, but in an Oracle stored procedure you could write something like this
If itemtype = 'A'
Then
<statement for table A>
Else
<statement for Table B>
End if
Something like this should work in SQL Server, too .. maybe someone could expand on this?
You really aren't explaining where ItemType
is coming from. As suggested UNION
might be applicable if you are simply combining two tables.
Here's another possibility which may relate to your problem:
SELECT ItemNumber,
ItemType,
COALESCE(TableA.Description, TableB.Description) AS Description
FROM Items
LEFT JOIN TableA
ON Items.ItemType = 'A'
AND TableA.ItemNumber = Items.ItemNumber
LEFT JOIN TableB
ON Items.ItemType <> 'A'
AND TableB.ItemNumber = Items.ItemNumber
You are better of using UNION query to join the tables first, and then SELECT.
Also, you may consider creating a view for one of the tables, so it pulls only the columns you need while renaming them, then UNION, and then select from the UNION.
Or use a temp table to store the result from each query. Put the creation of the temp table in a CASE (pseudocode, not tested):
CASE @itemType
WHEN 'A'
SELECT ACol1 AS Col1, ACol2 AS Col2
FROM TABLE_A
INTO #tempTable
WHERE ItemNumber = @itemNumber
ELSE
SELECT BCol1 AS Col1, BCol2 AS Col2
FROM TABLE_B
INTO #tempTable
WHERE PartNumber = @itemNumber
END
SELECT * FROM #tempTable