SQL Query to return one of two select statements - sql

I have a query that uses a UNION ALL to return results from two different select statements.
I would like to set this up to return only the first select results, and if this first select is empty then return the results of the second select statement.
Can someone give me a simple example of how I might do this.
Thanks in advance
Brian

This checks your first query for a record returned, then executes it. Otherwise it executes the second query.
DECLARE #FirstCount int
SET #FirstCount = (SELECT COUNT (*) FROM <First query>)
IF #FirstCount > 0
BEGIN
<first query here>
END
ELSE
BEGIN
<Second query here>
END
You can also use a table variable like so:
DECLARE #FirstQuery TABLE
(
<fields>
)
SET #FirstQuery = <First Query>
IF EXISTS (SELECT * FROM #FirstQuery)
BEGIN
SELECT * FROM #FirstQuery
END
ELSE
BEGIN
<Second query here>
END

Assuming that you want a query and not a batch, you could duplicate the 1st query of your Union in the second query to determine if it yielded results, and make the 2nd query conditional on that.
E.g. only show shipments if there are no order, otherwise show both (makes no business sense, but shows the point):
select id from tb_shipment
union all
select id from tb_order where 0 = (select COUNT(*) from tb_shipment)
Without knowing your data, I cannot say if there are more efficient ways for you than a WHERE clause.

Related

Conditional statements in "WHERE" in SQL Server

What I want to achieve is to have a switch case in the where clause. I want to test if this statement returns something, if it returns null, use this instead.
Sample:
SELECT [THIS_COLUMN]
FROM [THIS_TABLE]
WHERE (IF THIS [ID] RETURNS NULL THEN DO THIS SUBQUERY)
What I mean is that it will do this query first.
SELECT [THIS_COLUMN]
FROM [THIS_TABLE]
WHERE [ID] = 'SOMETHING'
If this returns NULL, do this query instead:
SELECT [THIS_COLUMN]
FROM [THIS_TABLE]
WHERE ID = (SELECT [SOMETHING] FROM [OTHER_TABLE]
WHERE [SOMETHING_SPECIFIC] = 'SOMETHING SPECIFIC')
Note that the expected results from the intended query varies from 30 rows up to 15k rows. Hope it helps.
Adding more information:
The results for this query will be used for another query but will just focus on this query.
Providing a real case scenario:
[THIS_COLUMN] is expected to have a list of VALUES.
[THIS_TABLE] contains the latest data only(let's say 1 year's worth of data) while the [OTHER_TABLE] contains the historical data.
What I want to achieve is when I query for a data that is not with in the 1 year's worth of data, IE 'SOMETHING' is not with in the 1 year scope(or in my case it returns NULL), I will use the other query where I query the 'SOMETHING_SPECIFIC'(Or may be 'SOMETHING' from the first statement makes more sense) from the historical table.
If I as reading through the lines correctly, this might work:
SELECT THIS_COLUMN
FROM dbo.THIS_TABLE TT
WHERE TT.ID = 'SOMETHING'
OR TT.ID = (SELECT OT.SOMETHING
FROM dbo.OTHER_TABLE OT
WHERE OT.SOMETHING_SPECIFIC = 'SOMETHING SPECIFIC'
AND NOT EXISTS (SELECT 1
FROM dbo.THIS_TABLE sq
WHERE sq.ID = 'SOMETHING'
AND THIS_COLUMN IS NOT NULL))
Note, however, that this could easily not be particularly performant.
You an use union all and not exists:
select this_column
from this_table
where id = 'something'
union all
select this_column
from this_table
where
not exists (select this_column from this_table where id = 'something')
and id = (select something from other_table where something_specific = 'something specific')
The first union member attempts to find rows that match the first condition, while the other one uses the subquery - the not exists prevents the second member to return something if the first member found a match.
90% of the time you can use a query-batch (i.e. a sequence of T-SQL statements) in a single SqlCommand object or SQL Server client session, so with that in-mind you could do this:
DECLARE #foo nvarchar(50) = (
SELECT
[THIS_COLUMN]
FROM
[THIS_TABLE]
WHERE
[ID] = 'SOMETHING'
);
IF #foo IS NULL
BEGIN
SELECT
[THIS_COLUMN]
FROM
[THIS_TABLE]
WHERE
[ID] = (
SELECT
[SOMETHING]
FROM
[OTHER_TABLE]
WHERE
[SOMETHING_SPECIFIC] = 'SOMETHING SPECIFIC'
)
END
ELSE
BEGIN
SELECT #foo AS [THIS_COLUMN];
END
That said, SELECT ... FROM ... WHERE x IN ( SELECT y FROM ... ) is a code-smell in a query - you probably need to rethink your solution entirely.

SQL - Run Select Statement Based On Where Query

Hi i want to create a query which does the following. When the paramter 25 is selected it only runs part A of the query, if any other number is selected run both Table A and B select queries.
Example Below:
DECLARE #Type varchar (200)
select * from
(SELECT sort_code FROM dbo.Test 1
WHERE FUNDING_YEAR = 26)
union
(SELECT sort_code FROM dbo.Test 2
WHERE FUNDING_YEAR = 26)
Where case when #Type = 25 then select * from table2 else table 1
You just need to reference the variable in the WHERE clause
SELECT *
FROM TableA
WHERE #Type = 25
UNION
SELECT *
FROM TableB
The query above will always select everything in TableB and will only select everything in TableA when the variable is equal to 25.
Since you are using SSRS, what I would do is write the query to return all of the rows and then apply a filter in the SSRS report when the Paramater is 25. I wouldn't pass a paramater value to the SQL side unless it greatly reduces the run time of the query.
(I would have put this in a comment.)

Same query but different tables

I'm faced with a big query that is generated in a string and executed with "OPEN pCursor FOR vQuery" and I'm trying to get the query out of the string variable and as a proper "compilable" query.
I'm having this problem where a different table is query depending on a variable
vQuery := 'SELECT ...';
IF pVar = 1 Then
vQuery := vQuery || ' FROM table1';
ELSE
vQuery := vQuery || ' FROM table2';
END IF
vQuery := vQuery || ' WHERE ...';
The two tables have pretty much the same column name. Is there a way to have this as a single query
OPEN Pcursorout FOR
SELECT ... FROM CASE WHEN pVar = 1 THEN table1 ELSE table1 END WHERE ...;
Or I'm stuck at having two queries?
IF pVar = 1 Then
OPEN Pcursorout FOR SELECT ... FROM table1 WHERE ...;
ELSE
OPEN Pcursorout FOR SELECT ... FROM table2 WHERE ...;
END IF
The select and where part are large and exactly the same for both table.
You could use a UNION and use your variable pVar to only include the results from one query in the result set.
SELECT t1.col1, t1.col2, ..., t1.col10
FROM table1 t1
WHERE pVar = 1 and ...
UNION
SELECT t2.col1, t2.col2, ..., t2.col10
FROM table1 t2
WHERE pVar <> 1 and ...
This isn't exactly what you asked about -- not being required to have duplicate lists of columns for the two select statements -- but I think it might capture your intent. It will require that the columns selected by both queries have the same datatype so there will be a (somewhat weak) constraint that the columns of both query results are the same. For example, you won't be able to add a new column to one query but not the other.
Perhaps using UNION / UNION ALL to unite both queries? The requirement for using UNION/UNION ALL is that all SELECTs being united must return columns with the same names.
So if you have
SELECT t.f1,
t.f2,
t.f3
FROM t
WHERE ...
and your other query is
SELECT q.f1,
q.f2,
q.f3
FROM q
WHERE ...
you can have both running as a single SQL statement with UNION:
SELECT t.f1,
t.f2,
t.f3
FROM t
WHERE ...
UNION
SELECT q.f1,
q.f2,
q.f3
FROM q
WHERE ...
Keep in mind that if you need to return columns that exist in one table but not in the other, you can still use UNION, just return NULL and name the column correspondingly to the column name in the table that has it.
Its a bit of a kludge and you might need to look at the performance impact, but you could use an inline view that unions the two base tables, with a flag on each part that you then compare to your variable
SELECT ...
FROM (
SELECT 1 as var, table1.*
FROM table1
UNION ALL
SELECT 2 as var, table2.*
FROM table2
) t
WHERE t.var = pVar
AND ...;
Using an inline view means you don't have to duplicate the main select-list or the where clause etc. If the tables have different columns then you can (and maybe should anyway) only select the columns in the inner queries that will be referenced in the outer select-list.

Yield Return equivalent in SQL Server

I am writing down a view in SQL server (DWH) and the use case pseudo code is:
-- Do some calculation and generate #Temp1
-- ... contains other selects
-- Select statement 1
SELECT * FROM Foo
JOIN #Temp1 tmp on tmp.ID = Foo.ID
WHERE Foo.Deleted = 1
-- Do some calculation and generate #Temp2
-- ... contains other selects
-- Select statement 2
SELECT * FROM Foo
JOIN #Temp2 tmp on tmp.ID = Foo.ID
WHERE Foo.Deleted = 1
The result of the view should be:
Select Statement 1
UNION
Select Statement 2
The intended behavior is the same as the yield returnin C#. Is there a way to tell the view which SELECT statements are actually part of the result and which are not? since the small calculations preceding what I need also contain selects.
Thank you!
Yield return in C# returns rows one at a time as they appear in some underlying function. This concept does not exist in SQL statements. SQl is set-based, returning the entire result set, conceptually as a unit. (That said, sometimes queries run slowly and you will see rows returned slowly or in batches.)
You can control the number of rows being returns using TOP (in SQL Server). You can select particular rows to be returned using WHERE statements. However, you cannot specify a UNION statement that conditionally returns rows from some components but not others.
The closest you may be able to come is something like:
if UseTable1Only = 'Y'
select *
from Table1
else if UseTable2Only = 'Y'
select *
from Table2
else
select *
from table1
union
select *
from table2
You can do something similar using dynamic SQL, by constructing the statement as a string and then executing it.
I found a better work around. It might be helpful for someone else. It is actually to include all the calculation inside WITH statements instead of doing them in the view core:
WITH Temp1 (ID)
AS
(
-- Do some calculation and generate #Temp1
-- ... contains other selects
)
, Temp2 (ID)
AS
(
-- Do some calculation and generate #Temp2
-- ... contains other selects
)
-- Select statement 1
SELECT * FROM Foo
JOIN Temp1 tmp on tmp.ID = Foo.ID
WHERE Foo.Deleted = 1
UNION
-- Select statement 2
SELECT * FROM Foo
JOIN Temp2 tmp on tmp.ID = Foo.ID
WHERE Foo.Deleted = 1
The result will be of course the UNION of all the outiside SELECT statements.

Stored Procedure return multiple result sets

I need a SP to return multiple sets of results. The second set of results would be based on a column of the first set of results.
So:
declare #myTable1 table(field0 int,field1 varchar(255))
insert into #myTable1 select top 1 field0, field1 from table1
declare #myTable2 table(field0 int,field3 varchar(255))
insert into #myTable2
select field0, field3 from table2
where #myTable1.field0 = #myTable2.field0
How do return #myTable1 and #myTable2 with my SP? Is this syntax even right at all?
My apologies, I'm still a newbie at SQL...
EDIT:
So, I'm getting an error on the last line of the code below that says: "Must declare the scalar variable "#myTable1""
declare #myTable1 table(field0 int,field1 dateTime)
insert into #myTable1
select top 1 field0, field1
from someTable1 m
where m.field4 > 6/29/2009
select * from #myTable1
select *
from someTable2 m2
where m2.field0 = #myTable1.field0
If I highlight and run the code up until the second select * it works fine...
when I highlight the rest it acts like the first variable doesn't exist...
EDIT2:
Figured that problem out. Thanks guys.
declare #myTable1 table(field0 int,field1 dateTime)
insert into #myTable1
select top 1 field0, field1
from someTable1 m
where m.field4 > 6/29/2009
select * from #myTable1
select *
from someTable2 m2
where m2.field0 = (select field0 from #myTable1)
You pretty much just select two result sets
SELECT * FROM #myTable1
SELECT * FROM #myTable2
However, some tools will hide some results (e.g. pgAdmin will only show the last) and some tools have some sort of requirement to get to the next result set (e.g. .NET's IDataReader's will not allow you to Read() from the second resultset until you call NextResult()).
Edit:
An alternative in this case, since the types of the two results match, is to combine them into a single resultset:
SELECT field0, field1 from #myTable1
UNION
SELECT field0, field3 from #myTable2
You can also choose between UNION ALL or UNION DISTINCT (the default) where the latter will only send rows that aren't repeats.
At the end of the Stored Proc, put:
SELECT * FROM #myTable1
SELECT * FROM #myTable2
This will return 2 result sets.