DB2 How to use case with multiple conditions? - db2

I have a DB2 Server and I want to select data depending on the condition.
If I have the Value Value in the ColumnX, ColumnY or ColumnZ it should search for it between the TB2.Column1 and TB3.Column1
My statement is a bunch of left outer joins but it looks like that:
SELECT
CASE
WHEN (TB1.ColumnX || TB1.ColumnY || TB1.ColumnZ) = 'Value'
THEN Statement1
ELSE ' '
END AS MyColumn
FROM
TB1 LEFT OUTER JOIN TB2 ON TB1.JOINCOL = TB2.JOINCOL
LEFT OUTER JOIN TB3 ON TB2.JOINCOL2 = TB3.JOINCOL
WHERE TB1.Column1 between TB2.Column1 and TB3.Column1
But it doesn't work, is there a mistake in the syntax?

It is not possible to check for multiple equalities using just a single expression. You may use the following syntax trick:
CASE WHEN 'Value' IN (TB1.ColumnX, TB1.ColumnY, TB1.ColumnZ)
THEN Statement1 ELSE ' ' END AS MyColumn
The alternative to this would be to repeat the full equality check for each column:
SELECT
CASE
WHEN TB1.ColumnX = 'Value' OR
TB1.ColumnY = 'Value' OR
TB1.ColumnZ = 'Value'
THEN Statement1
ELSE ' '
END AS MyColumn
FROM
TB1 LEFT OUTER JOIN TB2
ON TB1.JOINCOL = TB2.JOINCOL
LEFT OUTER JOIN TB3
ON TB2.JOINCOL2 = TB3.JOINCOL
WHERE
TB1.Column1 BETWEEN TB2.Column1 AND TB3.Column1;
If you need to refer to the CASE expression in the WHERE clause, then you have two choices. First, you may subquery your current query, and assign an alias to the CASE expression:
SELECT *
FROM
(
SELECT CASE WHEN ... AS exp
FROM TB1 ...
) t
WHERE exp = ...
Or, you may avoid the subquery and just repeat the entire CASE expression in the WHERE clause.

Related

IBM DB2 Case in Where clause?

I have a SQL Statement where I have to check on conditions on rows since it has duplicates.
Condition1 is to watch if the value from a column in tb1 is between two values in a two columns of tb2 but only on rows which has a 'Y' inside.
I have something like this:
SELECT DISTINCT
tb1.columnA, tb1.columnB, tb2.columnA, tb2.columnB,
CASE
WHEN tb1.col1 = 'Y'
THEN CONCAT(tb1.col2,tb2.col2)
ELSE 'no changes'
END as conditionColumn
FROM
tb1 left outer join tb2 on tb1.columnX tb2.columnX
WHERE
CASE
WHEN tb1.col1 = 'Y'
THEN Condition1
ELSE Condition2
END
From what I saw before, a case statement is not allowed in the where clause?
How can I handle this then?
EDIT
When I have a 'Y' in tb1.col1
the where clause should output me an ID specified in tb1.columnA and only the rows which values from tb1.ColumnB is between tb2.columnA and tb2.columnB. If it doesn't have a Y inside then it should simply just give me the ID
so I used this, but it gives me an syntax error:
SELECT DISTINCT
tb1.columnA, tb1.columnB, tb2.columnA, tb2.columnB,
CASE
WHEN tb1.col1 = 'Y'
THEN CONCAT(tb1.col2,tb2.col2)
ELSE 'no changes'
END as conditionColumn
FROM
tb1 left outer join tb2 on tb1.columnX tb2.columnX
WHERE
CASE
WHEN tb1.col1 = 'Y'
THEN tb1.columnA = 'MyID'
AND tb1.columnB BETWEEN tb2.columnA and tb2.columnB
ELSE tb1.columnA = 'MyID'
END
If you want to do this
WHERE
CASE
WHEN tb1.col1 = 'Y'
THEN Condition1
ELSE Condition2
END
then, likely what you are wanting is this
WHERE
( tb1.col1 = 'Y' AND Condition1 )
OR ( tb1.col1 <> 'Y' AND Condition2 )
You seem to be confused about the purpose of a WHERE clause...
All a WHERE clause does is decide rather or not a given row is returned. It can't change the data being returned.
To change the data, you need a CASE in the columns selected...
something like so...
SELECT DISTINCT
CASE
WHEN tb1.col1 = 'Y'
AND tb1.columnB BETWEEN tb2.columnA and tb2.columnB
then 'MyID'
ELSE tb1.columnA
END as newColumnA,
tb1.columnB, tb2.columnA, tb2.columnB,
CASE
WHEN tb1.col1 = 'Y'
THEN CONCAT(tb1.col2,tb2.col2)
ELSE 'no changes'
END as conditionColumn
FROM
tb1 left outer join tb2 on tb1.columnX tb2.columnX

How to avoid duplicates in the STRING_AGG function

My query is below:
select
u.Id,
STRING_AGG(sf.Naziv, ', ') as 'Ustrojstvena jedinica',
ISNULL(CONVERT(varchar(200), (STRING_AGG(TRIM(p.Naziv), ', ')), 121), '')
as 'Partner',
from Ugovor as u
left join VezaUgovorPartner as vup
on vup.UgovorId = u.Id AND vup.IsDeleted = 'false'
left join [TEST_MaticniPodaci2].dbo.Partner as p
on p.PartnerID = vup.PartnerId
left join [dbo].[VezaUgovorUstrojstvenaJedinica] as vuu
on vuu.UgovorId = u.Id
left join [TEST_MaticniPodaci2].hcphs.SifZavod as sf
on sf.Id = vuu.UstrojstvenaJedinicaId
left join [dbo].[SifVrstaUgovora] as vu
on u.VrstaUgovoraId = vu.Id
group by u.Id, sf.Naziv
My problem is that I can have more sf.Naziv and also only one sf.Naziv so I have to check if there is one and then show only one result and if there is two or more to show more results. But for now the problem is when I have only one sf.Naziv, query returns two sf.Naziv with the same name because in first STRING_AGG i have more records about p.Naziv.
I have no idea how to implement DISTINCT into STRING_AGG function
Any other solutions are welcome, but I think it should work with DISTINCT function.
It looks like distinct won't work, so what you should do is put your whole query in a subquery, remove the duplicates there, then do STRING_AGG on the data that has no duplicates.
SELECT STRING_AGG(data)
FROM (
SELECT DISTINCT FROM ...
)
I like this format for distinct values:
(d is required but you can use any variable name there)
SELECT STRING_AGG(LoadNumber, ',') as LoadNumbers FROM (SELECT DISTINCT LoadNumber FROM [ASN]) d
A sample query to remove duplicates while using STRING_AGG().
WITH cte AS (
SELECT DISTINCT product
FROM activities
)
SELECT STRING_AGG(product, ',') products
FROM cte;
Or you can use the following query. The result is same -
SELECT STRING_AGG(product, ',') as products
from (
SELECT product
FROM Activities
GROUP BY product
) as _ ;

MariaDB - order by with more selects

I have this SQL:
select * from `posts`
where `posts`.`deleted_at` is null
and `expire_at` >= '2017-03-26 21:23:42.000000'
and (
select count(distinct tags.id) from `tags`
inner join `post_tag` on `tags`.`id` = `post_tag`.`tag_id`
where `post_tag`.`post_id` = `posts`.`id`
and (`tags`.`tag` like 'PHP' or `tags`.`tag` like 'pop' or `tags`.`tag` like 'UI')
) >= 1
Is it possible order the results by number of tags in posts?
Maybe add there alias?
Any information can help me.
Convert your correlated subquery into a join:
select p.*
from posts p
join (
select pt.post_id,
count(distinct t.id) as tag_count
from tags t
inner join post_tag pt on t.id = pt.tag_id
where t.tag in ('PHP', 'pop', 'UI')
group by pt.post_id
) pt on p.id = pt.post_id
where p.deleted_at is null
and p.expire_at >= '2017-03-26 21:23:42.000000'
order by pt.tag_count desc;
Also, note that I changed the bunch of like and or to single IN because you are not matching any pattern i.e. there is no % in the string. So, better using single IN instead.
Also, if you have defined your table names, column names etc keeping keywords etc in mind, you shouldn't have the need to use the backticks. They make reading a query difficult.

Concatenate the result of multiple case when statement

I would like to display a concatenation of multiple string built upon when statement when the condition is met. As follow :
select
case
when T1.Field is not null then 'T1,'
when T2.Field is not null then /*last results*/ + 'T2,'
when T3.Field is not null then /*last results*/ + 'T3,'
end
from T1
left outer join T2 on ...
left outer join T3 on ...
Finally found out ... I didn't realize this was possible before :
select
case when T1.Field is not null then 'T1,' else '' end
+ case when T2.Field is not null then 'T2,' else '' end
+ case when T3.Field is not null then 'T3,' else '' end as result
from T1
left outer join T2 on ...
left outer join T3 on ...
Why not just try using ISNULL?
Something like
ISNULL(T1.Field,'') + ISNULL(T2.Field,'') + ... + ISNULL(TN.Field,'')

How to add a join based on parameter passed in stored procedure

Can I add a inner join or left join or right join based on parameter value. The only way right now I have is writing a dynamic query like
set #sql = 'select * from dbo.products PM(nolock)
'+ case when #orgunit is not null then ' join productorgunit pou on PM.ProductNumber = pou.ProductNumber '
else ''
end
+ '
Exec(#sql).
I hope there is something like
Select * from dbo.products PM(nolock)
case when #orgunit is not null then join productorgunit pou on PM.ProductNumber = pou.ProductNumber
end
Can you not just use a LEFT OUTER JOIN?
SELECT PM.*, pou.ProductNumber
FROM dbo.Products PM LEFT OUTER JOIN ProductOrgUnit pou ON
PM.ProductNumber = pou.ProductNumber
That will return all records from Products, and only return data from ProductOrgUnit if there is a matching record (otherwise the pou fields will be null in the resultset).
Alternatively you could have two separate queries in your sproc and use a T-SQL IF statement to select which one to run.