Conditional SQL Statement - sql

I would like to ask if it is possible to create a SQL statement with an if or similar structure.
I have two queries and would like to combine them into one. The only difference between the two is that one has additional AND conditions on its WHERE clause.
I tried doing a select case, but was not very successful. I will create a parameter "test" that will take 1 or 2, and that condition should determine which query to run.
Here are the queries...
Query 1
SELECT ID,AVG(B.VOL) AS PVOL
FROM (SELECT VAR1 AS ID, SUM(VOL) AS PVOL FROM table1 WHERE VAR1='xyz'
AND DATE_D>'10/28/2013' AND DATE_D<'10/31/2013'
AND CUSTOMER='Market' AND MARKET='South' AND PROJECT=0
GROUP BY VAR1,DATE_D) B GROUP BY ID
Query 2
SELECT ID,AVG(B.VOL) AS PVOL
FROM (SELECT VAR1 AS ID, SUM(VOL) AS PVOL FROM table1 WHERE VAR1='xyz'
AND DATE_D>'10/28/2013' AND DATE_D<'10/31/2013'
AND PROJECT=0
GROUP BY VAR1,DATE_D) B GROUP BY ID

You could create a sproc that accepts the "test" parameter that you hope to build your IF statement around.
create procedure --sprocname
(
#test int
)
as
begin
set nocount on
if
#test = --bool
select statement 1
else
select statement 2
end
sorry for the poor format I was in a hurry setting it up

You can add the condition based on your parameter #test like below
same query can be used , based on the parameter the condition will be varied.
SELECT ID,AVG(B.VOL) AS PVOL
FROM (SELECT VAR1 AS ID, SUM(VOL) AS PVOL FROM table1 WHERE VAR1='xyz'
AND DATE_D>'10/28/2013' AND DATE_D<'10/31/2013'
AND ( (#test = 1 AND CUSTOMER='Market' AND MARKET='South' AND PROJECT=0 )
OR ( #test =2 AND PROJECT=0 )
)
GROUP BY VAR1,DATE_D) B GROUP BY ID

Related

Get different query back based on a condition in PostgreSQL

I'm having a hard time with sql and probably this will look stupid but it shows what I am trying to achieve.
SELECT
CASE WHEN ( ( SELECT 1 FROM table_1 WHERE = condition ) IS NULL ) THEN
SELECT 'No result'::varchar
ELSE
SELECT
val_1,
val_2,
val_3
FROM
table_1
END;
A null answer is not good in my situation, I can't just use the sub-query as the main. And even if I could that would still leave the question open if the two tables were NOT the same like:
SELECT
CASE WHEN ( ( SELECT 1 FROM table_1 WHERE = condition ) IS NULL ) THEN
SELECT 'No result'::varchar
ELSE
SELECT
val_1,
val_2,
val_3
FROM
table_2 --TABLE REPLACED!
END;
As CASE-WHEN only works for one column it would be horrifying to have 20 of them with the same condition. Any help is appreciated! Thanks!
So you want to SELECT the table_log and if the result is not NULL show it to the client and if it is NULL show a message?
I created a fake table for testing. What you are looking for is the last SELECT-statement:
DROP TABLE IF EXISTS table_log;
CREATE TEMP TABLE table_log (
id INTEGER
,log_info VARCHAR)
;
INSERT INTO table_log VALUES
(1, 'test_entry')
;
ANALYZE table_log;
SELECT
COALESCE(b.log_info, 'No changes done!') AS log_info
FROM
(SELECT 'Fake-Data') a
LEFT OUTER JOIN (SELECT * FROM table_log WHERE id = 1) b ON (1=1);
If the given id = 1, you get the result, if it is something else (because it is not in the test-table) the premade message is given.
Here is a link to the db<>fiddle.

When select from insert into returns no values do something different

I want to insert rows into a table. The table is empty when I start. My query is as follows:
Select TOP 1 *
INTO #Result
FROM #SmallTable
WHERE CategoryID=11
ORDER BY ExpValue DESC;
It works flawless. But I want now to account for the case where the this returns no value. But I'm not sure how to approach this.
I could either make a case and select and ask if SELECT TOP 1 returns any values. Or I could check after I insert if there is a value present. But which approach would be better? Or is there an even better one?
You could use a union trick here to insert a dummy value should the first query not return any records:
INSERT INTO #Result (col)
SELECT TOP 1 col
FROM
(
SELECT TOP 1 col, 1 AS pos FROM #SmallTable WHERE CategoryID = 11 ORDER BY ExpValue DESC
UNION ALL
SELECT 'NA', 2
) t
ORDER BY pos;
Look at ##ROWCOUNT
This returns the number of rows affected by the last procedure.
IF ##ROWCOUNT = 0
PRINT 'Warning: No rows were inserted';
You can use apply :
select top (1) coalesce(st.CategoryID, 0) as CategoryID, . .
into #destination
from ( values (11)
) t(CategoryID) left join
#SmallTable st
on st.CategoryID = t.CategoryID
order by st.ExpValue desc;

SQL query to select with Range condition in source table

Have a scenario to select the value from table where range condition is present in source table.
Like,
TableA
ID value condition
1 20 A-M
2 50 N-Z
Select value from TableA where condition = 'C%'
--want to select TableA value from TableB by passing person name starts with like,
-- Here C is item name starts with
-- Should compare with range (A-M) and return first row.
-- Condition column is varchar(3)
I have seen the solution on other way where range can be compared with input value, but here the range is present in the source table. Please help.
If I have understood what you are after correctly you can use
SELECT TOP 1 B.*
FROM TableB B
WHERE B.Name LIKE (SELECT CONCAT('[',condition,']%') FROM TableA WHERE ID =1)
ORDER BY B.Id
If I understand correctly, you should be structuring TableA as:
ID value Lower Upper
1 20 A M
2 50 N Z
Then you want:
select a.*
from tableA a
where left(#name, 1) between a.lower and a.upper;
You can get this to work with your format, by doing:
select a.*
from tableA a
where left(#name, 1) between left(a.condition) and right(a.condition);
But I don't recommend that. Better to store the condition in two columns.
I would use QUOTENAME() function as
SELECT *
FROM TableA
WHERE #Condition LIKE QUOTENAME(Condition);
This will be as
WHERE 'C' LIKE [A-M] --return True
Demo1
Demo2
Always you should try to add data and DDL for setup correctly the test scenario, here my proposed solution:
DECLARE #SourceA AS TABLE
(
ID INT,
Value INT,
Condition VARCHAR(100)
);
INSERT INTO #SourceA ( ID ,
Value ,
Condition
)
VALUES ( 1 , -- ID - int
110 , -- Value - int
'A-M' -- Condition - varchar(100)
),(2,250,'N-Z')
DECLARE #Alphabet VARCHAR(200)='A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z';
; WITH MyCTE AS
(
SELECT ID,Value,Condition, SUBSTRING(#Alphabet, PATINDEX('%'+ LEFT(Condition,1) + '%' ,#Alphabet),(LEN(#Alphabet)-PATINDEX('%'+ RIGHT(Condition,1) + '%' ,#Alphabet))+1) AS FormattedCondition
FROM #SourceA
)
SELECT * FROM MyCTE
WHERE MyCTE.FormattedCondition LIKE '%C%'

return a default record from a sql query

I have a sql query that I run against a sql server database eg.
SELECT * FROM MyTable WHERE Id = 2
This may return a number of records or may return none. If it returns none, I would like to alter my sql query to return a default record, is this possible and if so, how? If records are returned, the default record should not be returned. I cannot update the data so will need to alter the sql query for this.
Another way (you would get an empty initial rowset returned);
SELECT * FROM MyTable WHERE Id = 2
IF (##ROWCOUNT = 0)
SELECT ...
SELECT TOP 1 * FROM (
SELECT ID,1 as Flag FROM MyTable WHERE Id = 2
UNION ALL
SELECT 1,2
) qry
ORDER BY qry.Flag ASC
You can have a look to this post. It is similar to what you are asking
Return a value if no rows are found SQL
I hope that it can guide you to the correct path.
if not exists (SELECT top 1 * FROM mytable WHERE id = 2)
select * from mytable where id= 'whatever_the_default_id_is'
else
select * from mytable where id = 2
If you have to return whole rows of data (and not just a single column) and you have to create a single SQL query then do this:
Left join actual table to defaults single-row table
select
coalesce(a.col1, d.col1) as col1,
coalesce(a.col2, d.col2) as col2,
...
from (
-- your defaults record
select
default1 as col1,
default2 as col2,
...) as d
left join actual as a
on ((1 = 1) /* or any actual table "where" conditions */)
The query need to return the same number of fields, so you shouldn't do a SELECT * FROM but a SELECT value FROM if you want to return a default value.
With that in mind
SELECT value FROM MyTable WHERE Id = 2
UNION
SELECT CASE (SELECT count(*) FROM MyTable WHERE Id = 2)
WHEN 0 THEN 'defaultvalue'
END

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.