If-Else Statement in T-SQL - sql

I'm trying to alter the results of a Transact-SQL (MS SQL Server) report that is currently showing:
CompanyA DVCE3
CompanyB DVCE2
CompanyC DVCE3
CompanyD NULL
CompanyE DVCE3
and I would like it instead to show:
CompanyA 36
CompanyB 24
CompanyC 36
CompanyD
CompanyE 36
I'm sure the answer to this is to use some kind of if/else statement or a case statement, but I'm not sure of the syntax of this in T-SQL or where it should go in my query.
My basic query looks like this:
SELECT
companyName
, term
FROM tableA a
JOIN tableB b on a.id = b.id ...
WHERE
customerNumber IS NOT NULL
AND companyName != 'TEST'... ;
Thanks for your help.

Replace your "term" field with the following:
CASE WHEN term='DVCE3' THEN '36' WHEN term='DVCE2' THEN '24' ELSE '' END as term
I'll rewrite it for readability:
CASE
WHEN term='DVCE3' THEN '36'
WHEN term='DVCE2' THEN '24'
ELSE ''
END as term

If you only have a few replacements you could stick them in a case statement as below.
SELECT
companyName
,CASE term WHEN 'DVCE3' THEN '36' WHEN 'DVCE2' THEN '24' ELSE '' END AS term
FROM tableA a
JOIN tableB b on a.id = b.id ...
WHERE
customerNumber IS NOT NULL
AND companyName != 'TEST'... ;
If you have more or you will be repeating this logic in other queries you could maybe set up a mapping table (either a permanent table, view, or an inline TVF) that you can then join onto.

A Case statement will work. However a better answer might be to place that data into a table and do a join or just place it into a field in your company table. This makes it MUCH more extensible in the long run.
CREATE TABLE CompanyTerms (
id INT,
CompanyName NVARCHAR(100) NOT NULL,
Term NVARCHAR(100) NULL
)
...
SELECT
companyName
, c.Term
FROM tableA a
JOIN tableB b on a.id = b.id ...
JOIN CompanyTerm c ON c.id = a.id
WHERE
customerNumber IS NOT NULL
AND companyName != 'TEST'... ;

Related

Use WHERE + AND + CASE + IN when crafting T-SQL

I have a stored procedure that has a few variables that may or may not be passed. they are a list of PKs from other tables, so FKs but formatted in as a string of CSVs.
here's what the query essentially looks like
DECLARE #SomeIds VARCHAR(MAX) = ''
CREATE TABLE #TempIds (Id INT)
IF (#SomeIds = '' OR #SomeIds = NULL) INSERT INTO #TempIds VALUES (NULL)
ELSE INSERT INTO #TempIds SELECT * FROM SplitString(#SomeIds,',') -- SplitString() is a user function
SELECT cont.varchar_LastName AS LastName
,cred.varchar_CredentialName AS CredentialName
FROM [dbo].[tbl_Contacts] AS cont
LEFT JOIN [dbo].[tbl_ContactsCredentials] AS cc ON cont.pk_int_Id = cc.fk_ContactId
LEFT JOIN [dbo].[tbl_Credentials] AS cred ON cc.fk_CredentialId = cred.pk_int_Id
So this query basically gives me a full list of contacts both with and without a credential name. I don't have a WHERE clause, so not surprised.
I get data basically like:
LastName | CredentialName
---------------------------
Stevens | Admin
Arnolds | User
Bishop | NULL
Evans | NULL
So if I add a WHERE clause like this:
WHERE cred.pk_int_Id IN (SELECT * FROM #TempIds)
I get zero results.
When I run this:
SELECT * FROM #TempIds
I get this:
Id
-----------
NULL
When I run it with "real values" in #SomeIds like '1,2' then it works fine.
I presume this is because my WHERE clause is looking in the cred table and there are no NULL values in that table, so that's why I'm not getting anything.
But I'm not sure how I fix it?
I guess I really want to do something like this:
WHERE CredentialName IN (SELECT * FROM #TempIds)
But I believe to do that, I'd have to run the first query into another temp table, then run a second query on that table.
Any help is greatly appreciated.
You can avoid a temp table
WHERE (NULLIF(#SomeIds,'') IS NULL OR cred.pk_int_Id IN (SELECT value FROM SplitString(#SomeIds,',')))
Or if your Sql Server version supports STRING_SPLIT
WHERE (NULLIF(#SomeIds,'') IS NULL OR cred.pk_int_Id IN (SELECT value FROM STRING_SPLIT(#SomeIds,',')))
And then don't initialize #SomeIds to make it get all records.
I would consider using a UNION for this. Putting an OR in a WHERE clause can make for some bad execution plans, and often makes indexes unusable.
SELECT cont.varchar_LastName AS LastName
,cred.varchar_CredentialName AS CredentialName
FROM [dbo].[tbl_Contacts] AS cont
LEFT JOIN [dbo].[tbl_ContactsCredentials] AS cc
ON cont.pk_int_Id = cc.fk_ContactId
LEFT JOIN [dbo].[tbl_Credentials] AS cred
ON cc.fk_CredentialId = cred.pk_int_Id
WHERE cred.pk_int_Id IN (SELECT value FROM STRING_SPLIT(#SomeIds,','))
UNION ALL
SELECT cont.varchar_LastName AS LastName
,cred.varchar_CredentialName AS CredentialName
FROM [dbo].[tbl_Contacts] AS cont
LEFT JOIN [dbo].[tbl_ContactsCredentials] AS cc
ON cont.pk_int_Id = cc.fk_ContactId
LEFT JOIN [dbo].[tbl_Credentials] AS cred
ON cc.fk_CredentialId = cred.pk_int_Id
WHERE NULLIF(#SomeIds,'') IS NULL
I talk about using OR in UPDATES statements here. But the same logic applies to SELECT.

Fetch data from 3 three tables whichever is not null

I am trying to find the available address details from three tables.
When table 1 has the address details then get it from table1
If table 1 address has null value then consider table2,
If table 2 address has null value then consider table3, else display table1 address (null)
There are foreign keys in table 1 which can be used to join table 2 and 3 but they can be null as well in which case only data from table 1 to be considered.
In my query, I am able to join the tables when the foreign keys are available but in case they are null, the query doesn’t work!
I am not sure if I can add a ‘Case’ statement to ignore the ‘Join’ conditions in case the foreign keys are null.
Can someone please assist?
My Query is below :
SELECT donor.donor_num,
CASE
--WHEN donor.addr1 IS NULL THEN paraddress.addr1
--WHEN paraddress.addr1 IS NULL THEN enrparaddr.addr1
WHEN donor.addr1 IS NULL THEN enrparaddr.addr1
ELSE donor.addr1
END AS Address1,
CASE
--WHEN donor.addr2 IS NULL THEN paraddress.addr2
--WHEN paraddress.addr2 IS NULL THEN enrparaddr.addr2
WHEN donor.addr2 IS NULL THEN enrparaddr.addr2
ELSE donor.addr2
END AS Address2
FROM donor
JOIN enrparaddr ON enrparaddr.par_code = donor.enrol_code
--JOIN paraddress ON paraddress.par_code = donor.par_code
WHERE donor_num = '17206'
Please see attached image for the three tables
You can try below - using FULL OUTER JOIN & coalesce() function
SELECT donor.donor_num,
coalesce(donor.addr1,paraddress.addr1,enrparaddr.addr1) AS Address1,
coalesce(donor.addr2,paraddress.addr2,enrparaddr.addr2) AS Address2
FROM donor
FULL OUTER JOIN enrparaddr ON enrparaddr.par_code = donor.enrol_code
FULL OUTER JOIN paraddress ON paraddress.par_code = donor.par_code
WHERE donor_num = '17206'
SELECT donor.donor_num,CASE WHEN donor.addr1 IS NULL
THEN enrparaddr.addr1
ELSE donor.addr1
END AS Address1,
CASE WHEN donor.addr2 IS NULL
THEN enrparaddr.addr2
ELSE donor.addr2
END AS Address2
FROM donor
left join enrparaddr ON enrparaddr.par_code = donor.enrol_code
WHERE donor_num = '17206'
I would recommend:
SELECT d.donor_num,
coalesce(d.addr1, pp.addr1, epe.addr1) AS Address1,
coalesce(d.addr2, pp.addr2, epe.addr2) AS Address2
FROM donor d LEFT JOIN
paraddress pp
ON pp.par_code = d.par_code LEFT JOIN
enrparaddr epe
ON epe.par_code = d.enrol_code AND
pp.par_code IS NULL
WHERE d.donor_num = 17206 -- do not use single quotes for numbers
Notes:
You want a LEFT JOIN because you want all rows in donors.
You should be joining the tables in the order used for the COALESCE().
The second JOIN condition can be limited to cases where the first does not match.
Number constants should not use single quotes.
You can do this with simple Case .. When Statement:
Select Case
When A.ID is NULL And B.ID is NULL And C.ID is NULL Then -- when all columns contain null
NULL
When A.ID is NULL And B.ID is NULL Then
C.ID
When B.ID is NULL and C.ID is NULL Then
A.ID
When A.ID is NULL And C.ID is NULL Then
B.ID
End As ID
From A, B, C

Selecting different columns from databases

Hello I have two databases and each has the same tables. For example I have table called world and it has 4 columns: pkey1, pkey2,companyid, company_name
I made a query which searches for rows which have the same pkey1 and pkey2 but one or many of their other property is different in the 2 tables. My question is how can I see only the different properties?
Here is my query it selects the rows which have the same pkey1 and pkey2 how can I upgrade it to see the columns where there is difference in both databases and of course if there is no difference the result of the query should return NULL in the column here is an example what I want to achieve:
in first database (1,1,345,'Ron'), second database (1,1,377,'Ron') the result should be (1,1,345,null)
Basically to reference data in a different database, you'll need a database link, since you are using PostgreSQL, this documentation should help;
https://www.postgresql.org/docs/current/static/dblink.html
You'll need to use this command to create the link (in this case with a name);
SELECT dblink_connect('CONNECTIONNAME', 'REMOTEDBCONNECTIONSTRING');
Then you can use this new connection via a select query;
SELECT *
FROM dblink('CONNECTIONNAME','SELECT * FROM foo') AS t(a int, b text, c text[]);
And replace 'foo' with your 'world' table name, then change the AS into the variables that relate to pkey1, pkey2,companyid, company_name etc.
If your databases are linked, you can join both tables and with "case" statement check if the value has changed:
select a.pkey1, a.pkey2,
case when a.companyid <> b.companyid then a.companyid else null end as companyid,
case when a.company_name <> b.company_name then a.company_name else null end as company_name
from db1.dbo.world a
inner join db2.dbo.world b on a.pkey1 = b.pkey1 and a.pkey2 = b.pkey2
If you want to omit rows with no difference you can use "except":
select a.pkey1, a.pkey2,
case when a.companyid <> b.companyid then a.companyid else null end as companyid,
case when a.company_name <> b.company_name then a.company_name else null end as company_name
from (
select pkey1, pkey2, companyid, company_name
from db1.dbo.world
except
select pkey1, pkey2, companyid, company_name
from db2.dbo.world) a
inner join db2.dbo.world b on a.pkey1 = b.pkey1 and a.pkey2 = b.pkey2

sqlite extra column with 1 and 0 if record exists in related table or not

I am not so good at SQL, so I have the following tables
Stuff
and
Specialty
Let's say, the worker with name 'Bob' has two specialties. How could I get the specialty table with an extra column (let's say count) which has 1 if the record exists in Stuff and 0 otherwise.
I would like to ask if there is any way to cast a query
that returns a result for Bob as shown below?
Any suggestions would be very helpful. Thank you in advance.
(I am not sure about the title. Please do suggest if you have a better idea!)
I would be inclined to do this with a case and exists:
select sp.*,
(case when exists (select 1
from stuff s
where s.surname = 'Bob' and
s.speciality_code = sp.speciality_code
)
then 1 else 0
end) as BobHas
from specialty sp;
Use Left Outer join with Null check. Try this.
SELECT sp.specialitycode,
sp.description,
CASE
WHEN st.specialitycode IS NULL THEN 0
ELSE 1
END AS count
FROM speciality sp
LEFT OUTER JOIN (SELECT specialitycode
FROM stuff
WHERE surname = 'Bob') st
ON sp.specialitycode = st.specialitycode

SQL Query + more efficient alternative

I have a query which involves 2 tables 'Coupons' and 'CouponUsedLog' in SQL Server, the query below will obtain some information from these 2 tables for statistics study use. Somehow I feel that while my query works and returns me the desired results, I feel that I can be written in a more efficient way, can someone please advice if there's a better way to rewrite this? Am I using too many unnecessary variables and joins? Thanks.
DECLARE #CouponISSUED int=null
DECLARE #CouponUSED int=null
DECLARE #CouponAVAILABLE int=null
DECLARE #CouponEXPIRED int=null
DECLARE #CouponLastUsed Date=null
--Total CouponIssued
SET #CouponISSUED =
(
select count(*)
from Coupon C Left Join
couponusedlog CU on C.autoid = CU.Coupon_AutoID
where C.VoidedBy is null and
C.VoidedOn is null and
DeletedBy is null and
DeletedOn is null and
Card_AutoID in (Select AutoID
from Card
where MemberID = 'Mem001')
)
--Total CouponUsed
SET #CouponUSED =
(
select count(*)
from couponusedlog CU Left Join
Coupon C on CU.Coupon_AutoID = V.autoid
where CU.VoidedBy is null and
CU.VoidedOn is null and
C.Card_AutoID in (select AutoID
from Card
where MemberID = 'Mem001')
)
SET #CouponAVAILABLE = #CouponISSUED - #CouponUSED
--Expired Coupons
SET #CouponEXPIRED =
(
select Count(*)
from Coupon C Left Join
couponusedlog CU on C.autoid = CU.Coupon_AutoID
where C.VoidedBy is null and
C.VoidedOn is null and
deletedBy is null and
deletedOn is null and
Card_AutoID in (select AutoID
from Card
where MemberID = 'Mem002') and
CONVERT (date, getdate()) > C.expirydate
)
--Last Used On
SET #CouponLastUsed =
(
select CONVERT(varchar(10),
Max(VU.AddedOn), 103) AS [DD/MM/YYYY]
from couponusedlog CU Left Join
coupon C on CU.Coupon_AutoID = C.autoid
where CU.voidedBy is null and
CU.voidedOn is null and
C.Card_AutoID in (select AutoID
from Card
where MemberID = 'Mem002')
)
Select #CouponISSUED As Coupon_Issued,
#CouponUSED As Coupon_Used,
#CouponAVAILABLE As Coupon_Available,
#CouponEXPIRED As Coupon_Expired,
#CouponLastUsed As Last_Coupon_UsedOn
In general its better to do things in a single query if you you're just looking for counts of things particularly against nearly the same data set then in four separate queries.
This query combines what you need into a single query by converting your WHERE Clauses into SUMS of CASE statements. The MAX of the date is just a normal thing you can do when you're doing a count or a sum.
SELECT COUNT(*) couponissued,
SUM(CASE
WHEN deletedby IS NULL
AND deletedon IS NULL THEN 1
ELSE 0
END) AS couponused,
SUM(CASE
WHEN deletedby IS NULL
AND deletedon IS NULL
AND Getdate() > c.expirydate THEN 1
ELSE 0
END) AS couponex,
MAX(vu.addedon) CouponEXPIRED
FROM [couponusedlog] cu
LEFT JOIN [Coupon] c
ON ( cu.coupon_autoid = v.autoid )
WHERE cu.voidedby IS NULL
AND cu.voidedon IS NULL
AND ( c.card_autoid IN (SELECT [AutoID]
FROM [Card]
WHERE memberid = 'Mem001') )
You can then convert that into a Common Table Expression to do your subtraction and formatting
Are you asking this question out of a proactive desire to be as effecient as possible, or because of an actual performance issue you would like to correct? You can make this more effecient at the cost of having code that is harder to manage. If the performance is okay right now I would highly recommend you leave it because the next person to come along will be able to understand it just fine. If you make one huge effecient but garbled sql statement out of it then when you or anyone else wants to update something about it it's going to take you 3 times longer as you try to re-figure out what the heck you were thinking when you wrote it.