Conditional where; Sql query/TSql for SQLServer2008 - sql

I really wanted to come up with the solution by myself for this one, but this is turning out to be slightly more challenging than I thought it would be.
The table I am trying to retrieve information would look something like below in simpler form.
Table: CarFeatures
+---+---+---+---+-----+
|Car|Nav|Bth|Eco|Radio|
+---+---+---+---+-----+
|a |y |n |n |y |
+---+---+---+---+-----+
|b |n |y |n |n |
+---+---+---+---+-----+
|c |n |n |y |n |
+---+---+---+---+-----+
|d |n |y |y |n |
+---+---+---+---+-----+
|e |y |n |n |n |
+---+---+---+---+-----+
On the SSRS report, I need to display all the cars that has all the features from the given parameters. This will receive parameters from the report like: Nav-yes/no, Bth-yes/no, Eco-yes/no, Radio-yes/no.
For instance, if the parameter input were 'Yes' for navigation and 'No' for others, the result table should be like;
+---+----------+
|Car|Features |
+---+----------+
|a |Nav, Radio|
+---+----------+
|e |Nav |
+---+----------+
I thought this would be simple, but as I try to get the query done, this is kind of driving me crazy. Below is what I thought initially will get me what I need, but didn't.
select Car,
case when #nav = 'y' then 'Nav ' else '' end +
case when #bth = 'y' then 'Bth ' else '' end +
case when #eco = 'y' then 'Eco ' else '' end +
case when #radio = 'y' then 'Radio ' else '' end As Features
from CarFeatures
where (nav = #nav -- here I don't want the row to be picked if the input is 'n'
or bth = #bth
or eco = #eco
or radio = #radio)
Basically the logic should be something like, if there is a row for every parameter that is 'yes,' list me all the features with 'yes' for that row, even though the parameters are 'no' for those other features.
Also, I am not considering to filter on the report. I want this to be on stored proc itself.
I would certainly like to avoid multiple ifs considering I have 4 parameters and the permutation of 4 in if might not be a better thing to do.
Thanks.

Your schema is awkward and denormalised, you should have 3 tables,
Car
Feature
CarFeature
The CarFeature table should consist of two columns, CarId and FeatureId. Then your could do something like,
SELECT DISTINCT
cr.CarId
FROM
CarFeature cr
WHERE
cr.FeatureId IN SelectedFeatures;
Rant
{
Not only would it be easy to add features without changing the schema,
offer better performance because of support of set based operations
covered by good indecies, overall use less storage because you no
longer need to store the No values, you would comply with some well
thought out and established patterns backed by 40+ years of
development effort and clarification.
}
If, for whatever reason, you cannot change the data or schema, you could UNPIVOT the columns like this, Fiddle Here
SELECT
p.Car,
p.Feature
FROM
(
SELECT
Car,
Nav,
Bth,
Eco,
Radio
FROM
CarFeatures) cf
UNPIVOT (Value For Feature In (Nav, Bth, Eco, Radio)) p
WHERE
p.Value='Y';
Or, you could do it old style like this Fiddle Here,
SELECT
Car,
'Nav' Feature
FROM
CarFeatures
WHERE
Nav = 'Y'
UNION ALL
SELECT
Car,
'Bth' Feature
FROM
CarFeatures
WHERE
Bth = 'Y'
UNION ALL
SELECT
Car,
'Eco' Feature
FROM
CarFeatures
WHERE
Eco = 'Y'
UNION ALL
SELECT
Car,
'Radio' Feature
FROM
CarFeatures
WHERE
Radio = 'Y'
to essentially, denormalise into subquery. Both queries give results like this,
CAR FEATURE
A Nav
A Radio
B Bth
B Radio
C Eco
D Bth
D Eco
E Nav

Try This, I believe this will solve your purpose..
SELECT Car,
tblPivot.Property AS Features,
tblPivot.Value
INTO #tmpFeature
FROM
(SELECT CONVERT(sql_variant,Car) AS Car,CONVERT(sql_variant,NAV) AS NAV, CONVERT(sql_variant,BTH) AS BTH, CONVERT(sql_variant,ECO) AS ECO,
CONVERT(sql_variant,Radio) AS Radio FROM CarFeatures) CarFeatures
UNPIVOT (Value For Property In (NAV,BTH, ECO, Radio)) as tblPivot
Where tblPivot.Value='y'
SELECT
Car,
STUFF((
SELECT ', ' + Features
FROM #tmpFeature
WHERE (Car = Results.Car)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS Features
FROM #tmpFeature Results
GROUP BY Car

Try this its working ...........
declare #table table (Car char(1),Nav char(1),Bth char(1),Eco char(1),Radio char(1))
insert into #table
select 'a', 'y' , 'n' , 'n', 'y'
union all
select 'b', 'n' , 'y' , 'n', 'n'
union all
select 'c', 'n' , 'n' , 'y', 'n'
union all
select 'd', 'n' , 'y' , 'y', 'n'
union all
select 'e', 'y' , 'n' , 'n', 'n'
select * from #table
select a.car,
Nav = left((case when a.nav = 'y' then 'Nav, ' else '' end) +
(case when a.bth = 'y' then 'Bth, ' else '' end)+
(case when a.Eco = 'y' then 'Eco, ' else '' end)+
(case when a.Radio = 'y' then 'Radio,' else '' end),
(len(((case when a.nav = 'y' then 'Nav, ' else '' end) +
(case when a.bth = 'y' then 'Bth, ' else '' end)+
(case when a.Eco = 'y' then 'Eco, ' else '' end)+
(case when a.Radio = 'y' then 'Radio,' else '' end)))-1))
from #table a

--Aha! I kind of figured out myself (very happy) :). Since the value for the columns can only be 'y' or 'n,' to ignore when the parameters value are no,
-- I will just ask it look for value that will never be there.
--If anyone has a better way of doing it or enhancing what I have (preferred) would be appreciated.
--Thanks to everyone who replied. Since this is a part of already existing table and also a piece of a big stored proc, I was reluctant to go with previous answers to the question.
--variable declaring and assignments here
select Car,
case when #nav = 'y' then 'Nav ' else '' end +
case when #bth = 'y' then 'Bth ' else '' end +
case when #eco = 'y' then 'Eco ' else '' end +
case when #radio = 'y' then 'Radio ' else '' end As Features
from CarFeatures
where (nav = (case when #nav = 'y' then 'Y' else 'B' end
OR case when #bth = 'y' then 'Y' else 'B' end
OR case when #eco = 'y' then 'Y' else 'B' end
OR case when #radio = 'y' then 'Y' else 'B' end
)

Related

Rolling Up Customer Data into One Row

I've created a query in Apache Spark in hopes of taking multiple rows of customer data and rolls it up into one row, showing what types of products they have open. So data that looks like this:
Customer Product
1 Savings
1 Checking
1 Auto
Ends up looking like this:
Customer Product
1 Savings/Checking/Auto
The query currently still has multiple rows. I tried group by, but that doesn't show the multiple products that a customer has, instead, it'll just show one product.
Is there a way to do this is Apache Spark or SQL (which is really similar to apache)? Unfortunately, I don't have MYSQL nor do I think IT will install it for me.
SELECT
"ACCOUNT"."account_customerkey" AS "account_customerkey",
max(
concat(case when Savings=1 then ' Savings'end,
case when Checking=1 then ' Checking 'end,
case when CD=1 then ' CD /'end,
case when IRA=1 then ' IRA /'end,
case when StandardLoan=1 then ' SL /'end,
case when Auto=1 then ' Auto /'end,
case when Mortgage=1 then ' Mortgage /'end,
case when CreditCard=1 then ' CreditCard 'end)) AS Description
FROM "ACCOUNT" "ACCOUNT"
inner join (
SELECT
"ACCOUNT"."account_customerkey" AS "customerkey",
CASE WHEN "ACCOUNT"."account_producttype" = 'Savings' THEN 1 ELSE NULL END AS Savings,
CASE WHEN "ACCOUNT"."account_producttype" = 'Checking' THEN 1 ELSE NULL END AS Checking,
CASE WHEN "ACCOUNT"."account_producttype" = 'CD' THEN 1 ELSE NULL END AS CD,
CASE WHEN "ACCOUNT"."account_producttype" = 'IRA' THEN 1 ELSE NULL END AS IRA,
CASE WHEN "ACCOUNT"."account_producttype" = 'Standard Loan' THEN 1 ELSE NULL END AS StandardLoan,
CASE WHEN "ACCOUNT"."account_producttype" = 'Auto' THEN 1 ELSE NULL END AS Auto,
CASE WHEN "ACCOUNT"."account_producttype" = 'Mortgage' THEN 1 ELSE NULL END AS Mortgage,
CASE WHEN "ACCOUNT"."account_producttype" = 'Credit Card' THEN 1 ELSE NULL END AS CreditCard
FROM "ACCOUNT" "ACCOUNT"
)a on "account_customerkey" =a."customerkey"
GROUP BY
"ACCOUNT"."account_customerkey"
Please try this.
scala> df.show()
+--------+--------+
|Customer| Product|
+--------+--------+
| 1| Savings|
| 1|Checking|
| 1| Auto|
| 2| Savings|
| 2| Auto|
| 3|Checking|
+--------+--------+
scala> df.groupBy($"Customer").agg(collect_list($"Product").as("Product")).select($"Customer",concat_ws(",",$"Product").as("Product")).show(false)
+--------+---------------------+
|Customer|Product |
+--------+---------------------+
|1 |Savings,Checking,Auto|
|3 |Checking |
|2 |Savings,Auto |
+--------+---------------------+
scala>
See https://learn.microsoft.com/en-us/azure/databricks/sql/language-manual/functions/collect_list and related functions
You need to use collect_list which is available with SQL or %sql.
%sql
select id, collect_list(num)
from t1
group by id
I used my own data, you need to tailor. Just demonstrating in more native SQL form.

SQL case when multiple records

I have 4 country columns that keep a track of the books in the specific region. For example, EN='Y', GE='N', and so on. I am creating a view and want to add each record in the available country column. So if EN='Y' and GE='Y' it would list them as 'en, ge' in the available country. So far what I have is:
case
when EN = 'Y' and GE = 'Y'
then 'EN, GE'
when EN = 'N' and GE = 'Y'
then 'GE'
end as 'available country'
This works but I have 4 more columns and might add more and defining each condition feels insufficient.
Is there a better way to concatenate values instead of specifying each one condition?
You could use CONCAT_WS with CASE expressions:
SELECT CONCAT_WS(',', CASE WHEN EN = 'Y' THEN 'EN' END,
CASE WHEN GE = 'Y' THEN 'GE' END,
...) AS "available country"
FROM yourTable;
But a much better table design would be something like this:
id | language | val
1 | EN | Y
1 | GE | N
Using this design, you could simply aggregate by id and filter for only those languages which have yes values, e.g. something like this:
SELECT id, ARRAY_AGG(language)
FROM yourTable
WHERE val = 'Y'
GROUP BY id;
You can turn the columns into rows (what they should be in the first place), then use string_agg() to get the comma separated list:
select t.id, f.*
from the_table t
cross join lateral (
select string_agg(colname, ',') as available_countries
from (
values (en, 'EN'),
(ge, 'GE'),
(de, 'DE'),
(fr, 'FR')
) x(flag, colname)
where flag = 'Y'
) as f
Unfortunately, I think you will have to use CASE WHEN with you current database design. Please check if this works for you.
select TRIM(BOTH ',' FROM c1_new||c2_new||c3_new||c4_new) as concat_col
from
(
select case when c1 = 'Y' then 'C1,' else null end as c1_new,
case when c2 = 'Y' then 'C2,' else null end as c2_new,
case when c3 = 'Y' then 'C3,' else null end as c3_new,
case when c4 = 'Y' then 'C4' else null end as c4_new
from TABLE
)
I have not worked in PostgreSQL. So if anybody needs Oracle equivalent :
SELECT TRIM (
TRAILING ',' FROM ( DECODE (c1, 'Y', 'c1' || ',', NULL)
|| DECODE (c2, 'Y', 'c2' || ',', NULL)
|| DECODE (c3, 'Y', 'c3' || ',', NULL)
|| DECODE (c4, 'Y', 'c4' || ',', NULL)))
FROM (SELECT 'Y' c1, 'Y' c2,'N' c3,'Y' c4 FROM DUAL)
This query returns :
c1,c2,c4

Updating column conditional on other columns

My server was crashed, damaging my database. In one of my tables I have an academic_quality column where I store school grades like A, B, C+, D. Somehow, my grades are not distributed through other columns on some rows. I thought I could create a conditional clause and create a new column, academic_quality_new, and update it after checking other columns. I tried the following query but it did not work.
SELECT academic_quality, acceptance_rate, undergrads, setting, environment, degrees_offered,
CASE WHEN (academic_quality OR acceptance_rate OR undergrads OR setting OR environment OR degrees_offered) = 'A' THEN INSERT 'A' INTO academic_quality_new
CASE WHEN (academic_quality OR acceptance_rate OR undergrads OR setting OR environment OR degrees_offered) = 'C' THEN INSERT 'B' INTO academic_quality_new
FROM [school_List_V4]
Any help would be appreciated!
You can try by adding case..when for all available grades.
First you can execute select query and check result
select * ,
case when academic_quality = 'A' OR acceptance_rate = 'A' then 'A'
else case when academic_quality ='B' OR acceptance_rate = 'B' then 'B'
else case when academic_quality = 'C' OR acceptance_rate = 'C' then 'C'
else '--'
end
end
end
from table1
then try this update query, it will update new column. If 2 cases are true then it will take first case, so case on grades should be from highest to lowest.
update table1
set new =
case when academic_quality = 'A' OR acceptance_rate = 'A' then 'A'
else case when academic_quality ='B' OR acceptance_rate = 'B' then 'B'
else case when academic_quality = 'C' OR acceptance_rate = 'C' then 'C'
else '--'
end
end
end
and final updated new column is select * from table1
academic_quality | acceptance_rate | new
A | NULL | A
NULL | B | B
NULL | NULL | --
A | B | A
C | B | B

counting records on the same table with different values possibly none sql server 2008

I have a inventory table with a condition i.e. new, used, other, and i am query a small set of this data, and there is a possibility that all the record set contains only 1 or all the conditions. I tried using a case statement, but if one of the conditions isn't found nothing for that condition returned, and I need it to return 0
This is what I've tried so far:
select(
case
when new_used = 'N' then 'new'
when new_used = 'U' then 'used'
when new_used = 'O' then 'other'
end
)as conditions,
count(*) as count
from myDB
where something = something
group by(
case
when New_Used = 'N' then 'new'
when New_Used = 'U' then 'used'
when New_Used = 'O' then 'other'
end
)
This returns the data like:
conditions | count
------------------
new 10
used 45
I am trying to get the data to return like the following:
conditions | count
------------------
new | 10
used | 45
other | 0
Thanks in advance
;WITH constants(letter,word) AS
(
SELECT l,w FROM (VALUES('N','new'),('U','used'),('O','other')) AS x(l,w)
)
SELECT
conditions = c.word,
[count] = COUNT(x.new_used)
FROM constants AS c
LEFT OUTER JOIN dbo.myDB AS x
ON c.letter = x.new_used
AND something = something
GROUP BY c.word;
try this -
DECLARE #t TABLE (new_used CHAR(1))
INSERT INTO #t (new_used)
SELECT t = 'N'
UNION ALL
SELECT 'N'
UNION ALL
SELECT 'U'
SELECT conditions, ISNULL(r.cnt, 0) AS [count]
FROM (
VALUES('U', 'used'), ('N', 'new'), ('O', 'other')
) t(c, conditions)
LEFT JOIN (
SELECT new_used, COUNT(1) AS cnt
FROM #t
--WHERE something = something
GROUP BY new_used
) r ON r.new_used = t.c
in output -
new 2
used 1
other 0
You can do it as a cross-tab:
select
sum(case when new_used = 'N' then 1 else 0 end) as N,
sum(case when new_used = 'U' then 1 else 0 end) as U,
sum(case when new_used = 'O' then 1 else 0 end) as Other
from myDB
where something = something

How do I perform an IF...THEN in an SQL SELECT?

How do I perform an IF...THEN in an SQL SELECT statement?
For example:
SELECT IF(Obsolete = 'N' OR InStock = 'Y' ? 1 : 0) AS Saleable, * FROM Product
The CASE statement is the closest to IF in SQL and is supported on all versions of SQL Server.
SELECT CAST(
CASE
WHEN Obsolete = 'N' or InStock = 'Y'
THEN 1
ELSE 0
END AS bit) as Saleable, *
FROM Product
You only need to use the CAST operator if you want the result as a Boolean value. If you are happy with an int, this works:
SELECT CASE
WHEN Obsolete = 'N' or InStock = 'Y'
THEN 1
ELSE 0
END as Saleable, *
FROM Product
CASE statements can be embedded in other CASE statements and even included in aggregates.
SQL Server Denali (SQL Server 2012) adds the IIF statement which is also available in access (pointed out by Martin Smith):
SELECT IIF(Obsolete = 'N' or InStock = 'Y', 1, 0) as Saleable, * FROM Product
The case statement is your friend in this situation, and takes one of two forms:
The simple case:
SELECT CASE <variable> WHEN <value> THEN <returnvalue>
WHEN <othervalue> THEN <returnthis>
ELSE <returndefaultcase>
END AS <newcolumnname>
FROM <table>
The extended case:
SELECT CASE WHEN <test> THEN <returnvalue>
WHEN <othertest> THEN <returnthis>
ELSE <returndefaultcase>
END AS <newcolumnname>
FROM <table>
You can even put case statements in an order by clause for really fancy ordering.
From SQL Server 2012 you can use the IIF function for this.
SELECT IIF(Obsolete = 'N' OR InStock = 'Y', 1, 0) AS Salable, *
FROM Product
This is effectively just a shorthand (albeit not standard SQL) way of writing CASE.
I prefer the conciseness when compared with the expanded CASE version.
Both IIF() and CASE resolve as expressions within a SQL statement and can only be used in well-defined places.
The CASE expression cannot be used to control the flow of execution of
Transact-SQL statements, statement blocks, user-defined functions, and
stored procedures.
If your needs can not be satisfied by these limitations (for example, a need to return differently shaped result sets dependent on some condition) then SQL Server does also have a procedural IF keyword.
IF #IncludeExtendedInformation = 1
BEGIN
SELECT A,B,C,X,Y,Z
FROM T
END
ELSE
BEGIN
SELECT A,B,C
FROM T
END
Care must sometimes be taken to avoid parameter sniffing issues with this approach however.
You can find some nice examples in The Power of SQL CASE Statements, and I think the statement that you can use will be something like this (from 4guysfromrolla):
SELECT
FirstName, LastName,
Salary, DOB,
CASE Gender
WHEN 'M' THEN 'Male'
WHEN 'F' THEN 'Female'
END
FROM Employees
Use CASE. Something like this.
SELECT Salable =
CASE Obsolete
WHEN 'N' THEN 1
ELSE 0
END
SELECT
(CASE
WHEN (Obsolete = 'N' OR InStock = 'Y') THEN 'YES'
ELSE 'NO'
END) as Salable
, *
FROM Product
Microsoft SQL Server (T-SQL)
In a select, use:
select case when Obsolete = 'N' or InStock = 'Y' then 'YES' else 'NO' end
In a where clause, use:
where 1 = case when Obsolete = 'N' or InStock = 'Y' then 1 else 0 end
From this link, we can understand IF THEN ELSE in T-SQL:
IF EXISTS(SELECT *
FROM Northwind.dbo.Customers
WHERE CustomerId = 'ALFKI')
PRINT 'Need to update Customer Record ALFKI'
ELSE
PRINT 'Need to add Customer Record ALFKI'
IF EXISTS(SELECT *
FROM Northwind.dbo.Customers
WHERE CustomerId = 'LARSE')
PRINT 'Need to update Customer Record LARSE'
ELSE
PRINT 'Need to add Customer Record LARSE'
Isn't this good enough for T-SQL?
SELECT
CASE
WHEN OBSOLETE = 'N' or InStock = 'Y' THEN 'TRUE'
ELSE 'FALSE'
END AS Salable,
*
FROM PRODUCT
Simple if-else statement in SQL Server:
DECLARE #val INT;
SET #val = 15;
IF #val < 25
PRINT 'Hi Ravi Anand';
ELSE
PRINT 'By Ravi Anand.';
GO
Nested If...else statement in SQL Server -
DECLARE #val INT;
SET #val = 15;
IF #val < 25
PRINT 'Hi Ravi Anand.';
ELSE
BEGIN
IF #val < 50
PRINT 'what''s up?';
ELSE
PRINT 'Bye Ravi Anand.';
END;
GO
Use a CASE statement:
SELECT CASE
WHEN (Obsolete = 'N' OR InStock = 'Y')
THEN 'Y'
ELSE 'N'
END as Available
etc...
A new feature, IIF (that we can simply use), was added in SQL Server 2012:
SELECT IIF ( (Obsolete = 'N' OR InStock = 'Y'), 1, 0) AS Saleable, * FROM Product
Use pure bit logic:
DECLARE #Product TABLE (
id INT PRIMARY KEY IDENTITY NOT NULL
,Obsolote CHAR(1)
,Instock CHAR(1)
)
INSERT INTO #Product ([Obsolote], [Instock])
VALUES ('N', 'N'), ('N', 'Y'), ('Y', 'Y'), ('Y', 'N')
;
WITH cte
AS
(
SELECT
'CheckIfInstock' = CAST(ISNULL(NULLIF(ISNULL(NULLIF(p.[Instock], 'Y'), 1), 'N'), 0) AS BIT)
,'CheckIfObsolote' = CAST(ISNULL(NULLIF(ISNULL(NULLIF(p.[Obsolote], 'N'), 0), 'Y'), 1) AS BIT)
,*
FROM
#Product AS p
)
SELECT
'Salable' = c.[CheckIfInstock] & ~c.[CheckIfObsolote]
,*
FROM
[cte] c
See working demo: if then without case in SQL Server.
For start, you need to work out the value of true and false for selected conditions. Here comes two NULLIF:
for true: ISNULL(NULLIF(p.[Instock], 'Y'), 1)
for false: ISNULL(NULLIF(p.[Instock], 'N'), 0)
combined together gives 1 or 0. Next use bitwise operators.
It's the most WYSIWYG method.
SELECT 1 AS Saleable, *
FROM #Product
WHERE ( Obsolete = 'N' OR InStock = 'Y' )
UNION
SELECT 0 AS Saleable, *
FROM #Product
WHERE NOT ( Obsolete = 'N' OR InStock = 'Y' )
SELECT CASE WHEN profile.nrefillno = 0 THEN 'N' ELSE 'R'END as newref
From profile
case statement some what similar to if in SQL server
SELECT CASE
WHEN Obsolete = 'N' or InStock = 'Y'
THEN 1
ELSE 0
END as Saleable, *
FROM Product
This isn't an answer, just an example of a CASE statement in use where I work. It has a nested CASE statement. Now you know why my eyes are crossed.
CASE orweb2.dbo.Inventory.RegulatingAgencyName
WHEN 'Region 1'
THEN orweb2.dbo.CountyStateAgContactInfo.ContactState
WHEN 'Region 2'
THEN orweb2.dbo.CountyStateAgContactInfo.ContactState
WHEN 'Region 3'
THEN orweb2.dbo.CountyStateAgContactInfo.ContactState
WHEN 'DEPT OF AGRICULTURE'
THEN orweb2.dbo.CountyStateAgContactInfo.ContactAg
ELSE (
CASE orweb2.dbo.CountyStateAgContactInfo.IsContract
WHEN 1
THEN orweb2.dbo.CountyStateAgContactInfo.ContactCounty
ELSE orweb2.dbo.CountyStateAgContactInfo.ContactState
END
)
END AS [County Contact Name]
If you're inserting results into a table for the first time, rather than transferring results from one table to another, this works in Oracle 11.2g:
INSERT INTO customers (last_name, first_name, city)
SELECT 'Doe', 'John', 'Chicago' FROM dual
WHERE NOT EXISTS
(SELECT '1' from customers
where last_name = 'Doe'
and first_name = 'John'
and city = 'Chicago');
As an alternative solution to the CASE statement, a table-driven approach can be used:
DECLARE #Product TABLE (ID INT, Obsolete VARCHAR(10), InStock VARCHAR(10))
INSERT INTO #Product VALUES
(1,'N','Y'),
(2,'A','B'),
(3,'N','B'),
(4,'A','Y')
SELECT P.* , ISNULL(Stmt.Saleable,0) Saleable
FROM
#Product P
LEFT JOIN
( VALUES
( 'N', 'Y', 1 )
) Stmt (Obsolete, InStock, Saleable)
ON P.InStock = Stmt.InStock OR P.Obsolete = Stmt.Obsolete
Result:
ID Obsolete InStock Saleable
----------- ---------- ---------- -----------
1 N Y 1
2 A B 0
3 N B 1
4 A Y 1
SELECT CASE WHEN Obsolete = 'N' or InStock = 'Y' THEN 1 ELSE 0
END AS Saleable, *
FROM Product
You can have two choices for this to actually implement:
Using IIF, which got introduced from SQL Server 2012:
SELECT IIF ( (Obsolete = 'N' OR InStock = 'Y'), 1, 0) AS Saleable, * FROM Product
Using Select Case:
SELECT CASE
WHEN Obsolete = 'N' or InStock = 'Y'
THEN 1
ELSE 0
END as Saleable, *
FROM Product
Using SQL CASE is just like normal If / Else statements.
In the below query, if obsolete value = 'N' or if InStock value = 'Y' then the output will be 1. Otherwise the output will be 0.
Then we put that 0 or 1 value under the Salable Column.
SELECT
CASE
WHEN obsolete = 'N' OR InStock = 'Y'
THEN 1
ELSE 0
END AS Salable
, *
FROM PRODUCT
Question:
SELECT IF(Obsolete = 'N' OR InStock = 'Y' ? 1 : 0) AS Saleable, * FROM Product
ANSI:
Select
case when p.Obsolete = 'N'
or p.InStock = 'Y' then 1 else 0 end as Saleable,
p.*
FROM
Product p;
Using aliases -- p in this case -- will help prevent issues.
SELECT
if((obsolete = 'N' OR instock = 'Y'), 1, 0) AS saleable, *
FROM
product;
For those who uses SQL Server 2012, IIF is a feature that has been added and works as an alternative to Case statements.
SELECT IIF(Obsolete = 'N' OR InStock = 'Y', 1, 0) AS Salable, *
FROM Product
It will be something like that:
SELECT OrderID, Quantity,
CASE
WHEN Quantity > 30 THEN "The quantity is greater than 30"
WHEN Quantity = 30 THEN "The quantity is 30"
ELSE "The quantity is under 30"
END AS QuantityText
FROM OrderDetails;
I like the use of the CASE statements, but the question asked for an IF statement in the SQL Select. What I've used in the past has been:
SELECT
if(GENDER = "M","Male","Female") as Gender
FROM ...
It's like the Excel or sheets IF statements where there is a conditional followed by the true condition and then the false condition:
if(condition, true, false)
Furthermore, you can nest the if statements (but then use should use a CASE :-)
(Note: this works in MySQL Workbench, but it may not work on other platforms)
For the sake of completeness, I would add that SQL uses three-valued logic. The expression:
obsolete = 'N' OR instock = 'Y'
Could produce three distinct results:
| obsolete | instock | saleable |
|----------|---------|----------|
| Y | Y | true |
| Y | N | false |
| Y | null | null |
| N | Y | true |
| N | N | true |
| N | null | true |
| null | Y | true |
| null | N | null |
| null | null | null |
So for example if a product is obsolete but you dont know if product is instock then you dont know if product is saleable. You can write this three-valued logic as follows:
SELECT CASE
WHEN obsolete = 'N' OR instock = 'Y' THEN 'true'
WHEN NOT (obsolete = 'N' OR instock = 'Y') THEN 'false'
ELSE NULL
END AS saleable
Once you figure out how it works, you can convert three results to two results by deciding the behavior of null. E.g. this would treat null as not saleable:
SELECT CASE
WHEN obsolete = 'N' OR instock = 'Y' THEN 'true'
ELSE 'false' -- either false or null
END AS saleable
There are multiple conditions.
SELECT
(CASE
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1001' THEN 'DM'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1002' THEN 'GS'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1003' THEN 'MB'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1004' THEN 'MP'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1005' THEN 'PL'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1008' THEN 'DM-27'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1011' THEN 'PB'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1012' THEN 'UT-2'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1013' THEN 'JGC'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1014' THEN 'SB'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1015' THEN 'IR'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1016' THEN 'UT-3'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1017' THEN 'UT-4'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1019' THEN 'KR'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1020' THEN 'SYB-SB'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1021' THEN 'GR'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1022' THEN 'SYB-KP'
WHEN RIGHT((LEFT(POSID,5)),4) LIKE '1026' THEN 'BNS'
ELSE ''
END) AS OUTLET
FROM matrixcrm.Transact