Is it possible to use CASE statement in WHERE condition like below?
SELECT act.id_activity FROM activity act
LEFT JOIN work w ON w.id_work = act.id_work
WHERE
w.work_type=1
AND w.work_tender in (1,2)
AND act.id_activity_type IN
(CASE WHEN w.work_tender=1 THEN '2,3' WHEN w.work_tender=2 THEN '2,3,4,9' END)
it returns no error but the results always display act.id_activity_type = 2 instead of 2,3 or 2,3,4,9
In this case 1 work (table work) can have many activities (table activity). i want to display activities based on work.work_tender type. if work.work_tender=1 then need to choose activity.id_activity_type IN (2,3). if work.work_tender=2 then need to choose activity.id_activity_type IN (2,3,4,9)
You can try to write correct logic by OR & AND.
SELECT act.id_activity FROM activity act
LEFT JOIN work w ON w.id_work = act.id_work
WHERE
w.work_type=1
AND (
(act.id_activity_type IN ('2','3') AND w.work_tender=1) OR
(act.id_activity_type IN ('2','3','4','9') AND w.work_tender=2)
)
I think case is used for that case. I think it is possible to use in that case. And also for orderby phrase.
Maybe you can try with this:
SELECT *
FROM activity a
JOIN work w
ON w.work_tender=
CASE WHEN a.id_activity_type IN (2,3) THEN 1
WHEN a.id_activity_type IN (2,3,4,9) THEN 2 END;
I'm using CASE expression here to assign value matching w.work_tender if the a.id_activity_type fit the condition. So, if a.id_activity_type IN (2,3) THEN 1 will match with w.work_tender=1 similarly with a.id_activity_type IN (2,3,4,9) THEN 2 will match with w.work_tender=2.
Demo fiddle
Related
Good day,
I have a small issue with MySQL Distinct.
Trying the following query in my system :
SELECT DISTINCT `booking_id`, `booking_ticket`, `booking_price`, `bookingcomment_id`, `bookingcomment_message` FROM `mysystem_booking`
LEFT JOIN `mysystem_bookingcomment` ON `mysystem_booking`.`booking_id` = `mysystem_bookingcomment`.`bookingcomment_link`
WHERE `booking_id` = 29791
The point is that there are bookings like 29791 that have many comments added.
Let's say 10. Then when running the above query I see 10 results instead of one.
And that's not the way DISTINCT supposes to work.
I simply want to know if there are any comments. If the comment ID is not 0 then there is a comment. Of course I can add COUNT(blabla) as comment_number but that's a whole different story. For me now I'd like just to have this syntax right.
You may try aggregating here, to find which bookings have at least a single comment associated with them:
SELECT
b.booking_id,
b.booking_ticket,
b.booking_price
FROM mysystem_booking b
LEFT JOIN mysystem_bookingcomment bc
ON b.booking_id = bc.bookingcomment_link
WHERE
b.booking_id = 29791
GROUP BY
b.booking_id
HAVING
COUNT(bc.bookingcomment_link) > 0;
Note that depending on your MySQL server mode, you might have to also add the booking_ticket and booking_price columns to the GROUP BY clause to get the above query to run.
You can try below - using a case when expression
SELECT DISTINCT `booking_id`, `booking_ticket`, `booking_price`, `bookingcomment_id`,
case when `bookingcomment_message`<>'0' then 'No' else 'Yes' end as comments
FROM `mysystem_booking`
LEFT JOIN `mysystem_bookingcomment` ON `mysystem_booking`.`booking_id` = `mysystem_bookingcomment`.`bookingcomment_link`
WHERE `booking_id` = 29791
i have the follwoing query:
SELECT COALESCE(income_adsense, income_adsense_u) AS "REV",
CASE COALESCE(income_adsense, income_adsense_u)
WHEN income_adsense THEN "REAL"
WHEN income_adsense_u THEN "USER"
END AS source
FROM revenue_report LIMIT 1;
which will return answer like this:
REV | source
376 | REAL
now the query works fine but the problem is i want to execute this select couple of times for different entity (adsense in the example).
the best i could get is this:
SELECT rr.site_id, ws.website_name,
CASE COALESCE(income_adsense, income_adsense_u)
WHEN income_adsense THEN "REAL"
WHEN income_adsense_u THEN "USER"
END AS adsense_source,
CASE COALESCE(income_taboola, income_taboola_u)
WHEN income_taboola THEN "REAL"
WHEN income_taboola_u THEN "USER"
END AS taboola_source
FROM revenue_report rr
INNER JOIN websites ws ON ws.website_id = rr.site_id
WHERE (data_date BETWEEN '2017-03-18' AND '2017-03-18')
GROUP BY site_id
LIMIT 1
but the problem here is i'm missing the "REV" value from the upper example. I know it doesn't exists in the second query, but this is the last working attempt. any idea how can i add the "REV" value logic to the second query?
in the second query i will get this structure of result:
site_id|website_name|adsense_source|taboola_source
but here im missing the COALESCE result from the first query which in the example was 376
Well why can't you just include it in your SELECT list like
SELECT rr.site_id, ws.website_name,
COALESCE(income_adsense, income_adsense_u) AS "REV", //Here
CASE COALESCE(income_adsense, income_adsense_u)
WHEN income_adsense THEN "REAL"
WHEN income_adsense_u THEN "USER"
END AS adsense_source,
CASE COALESCE(income_gol, income_gol_u)
WHEN income_taboola THEN "REAL"
WHEN income_taboola_u THEN "USER"
END AS taboola_source
FROM revenue_report rr
INNER JOIN websites ws ON ws.website_id = rr.site_id
WHERE (data_date BETWEEN '2017-03-18' AND '2017-03-18')
GROUP BY site_id
LIMIT 1
I'm working with a large stored procedure, I'm having trouble with a small portion of it.
When I execute a query on the table im joining, there can be 0, 1 or 2 results. If there are 0 results, I don't really care, my code returns null values, no big deal. If there is 1 result, my code returns the correct values, however, if there are 2 results, I am having trouble selecting the second result.
My code below works until the second OutterApply(the AHM2 stuff). Does anyone see what I am doing wrong?
The animal ID is identical for both OuterApplys. I just need to return the second result, if there is one, and if it is not the same as the first one.
SELECT TOP 1
AHM.AnimalHerdManagementId,
AHM.HerdManagementId,
AHM2.AnimalHerdManagementId,
AHM2.HerdManagementId,
HM.Code AS HerdManagementCode,
HM2.Code AS HerdManagementCode2
OUTER APPLY
(
SELECT TOP 1 AHM.AnimalHerdManagementId, AHM.HerdManagementId
FROM dbo.AnimalHerdManagement AHM
WHERE AHM.AnimalId = A.AnimalId AND ISNULL(AHM.EffectiveFrom, #EffectiveFrom) <= #EffectiveFrom
ORDER BY AHM.EffectiveFrom DESC
) AHM
LEFT JOIN dbo.HerdManagement HM ON AHM.HerdManagementId = HM.HerdManagementId
OUTER APPLY
(
SELECT TOP 1 AHM2.AnimalHerdManagementId, AHM2.HerdManagementId
FROM dbo.AnimalHerdManagement AHM2
WHERE AHM2.AnimalId = A.AnimalId AND AHM2.AnimalHerdManagementId != AHM.AnimalHerdManagementId AND ISNULL(AHM2.EffectiveFrom, #EffectiveFrom) <= #EffectiveFrom
ORDER BY AHM2.EffectiveFrom DESC
) AHM2
LEFT JOIN dbo.HerdManagement HM2 ON AHM2.HerdManagementId = HM2.HerdManagementId
I think I can help you with the OUTER APPLY but the method of getting the two different values is going to need some help as my solution is a total hack.
First, you don't need to join on the outer apply. The join is implied. So you can completely eliminate the join syntax from your query.
Second, AnimalHerdManagement looks/seems like a special table called a Junction Table. All the data contained in it is contained elsewhere (That it contains completely redundant data is why it's called a special table). But that is minor.
Finally, here is some example code I threw together that accomplishes what you are after. The method I am using to retrieve different results on the two outer apply's is a hack, but if you are sure that will always be true, it might work. I am not able to get a multi-level outer apply to work.
select * from AH_Animal A
outer apply
(
select max (HerdManagementID) as HerdMgmtID1 from AH_AnimalHerdManagement HM1 where HM1.AnimalID = A.AnimalID
) as z
outer apply
(
select min (HerdManagementID) as HerdMgmtID2 from AH_AnimalHerdManagement HM2 where HM2.AnimalID = A.AnimalID
) as zz
I hope that helped. There has to be another solution to this, as this would not work at all if you ever expected 3 results.
Query Results:
To match up some new schema to old, I'm having to do some ugly contortions that I figure could be done in a better way. For reference, I asked another question about this match-up process here: Creating View from Related Child Tables
I've placed a simplified example in SQLFiddle but the gist of it is, that the only way I can see reconciling these two different schemas is to do two case statements on the same value, something like this:
SELECT
CASE
WHEN n.FooBarStatusId = 1 OR n.FooBarStatusId = 2
THEN 1
ELSE 0
END as [IsFoo],
CASE
WHEN n.FooBarStatusId = 2
THEN 1
ELSE 0
END as [IsBar]
from Parent p
left join OldStuff o on p.ParentId = o.ParentId
left join NewStuff n on p.ParentId = n.ParentId
Is there a better and/or more efficient way of accomplishing the same thing? These case statements could be hit hundreds of times in a given query and I'm concerned about this specific logic.
I've thought about extracting this specific logic out (it is part of a larger query to build a view) into a temp table or perhaps even a table-valued function, but even still I can't come up with a way around using multiple case statements.
Just corrected grammar...
I found another solution:
select
p.Name,
ISNULL(o.IsFoo, CONVERT(BIT, n.FooBarStatusId)) as [IsFoo],
ISNULL(o.IsBar, CONVERT(BIT, n.FooBarStatusId * (n.FooBarStatusId - 1))) as [IsBar],
from Parent p
left join OldStuff o on p.ParentId = o.ParentId
left join NewStuff n on p.ParentId = n.ParentId
The only one arithmetic solution could be slow:
select
p.Name,
ISNULL(o.IsFoo, CAST( (n.FooBarStatusId % 0.35) * 4 AS int)) AS [IsFoo],
ISNULL(o.IsBar, n.FooBarStatusId/2) [IsBar]
from Parent p
left join OldStuff o on p.ParentId = o.ParentId
left join NewStuff n on p.ParentId = n.ParentId
Personally, I do not like to use the division, because of could be involved floating point operations, that way, it would be very slow.
As you have two columns, you will need two expressions... but they might not have to be CASE expressions. Reading your question, I get the impressions that the only possible values in the column are 0,1,2, and that this is an int type? If that's correct, you can use arithmetic rather than boolean logic to get what you need. Try this:
CAST( (n.FooBarStatusId % .35) * 4 AS int) AS [IsFoo],
n.FooBarStatusId/2 [IsBar]
I use data from http://geonames.org. The table structure is as follows:
GN_Name 1 - 0:N GN_AlternateName
They are linked on:
(PK)GN_Name.GeoNameId == (FK)GN_AlternateName.GeoNameId
GN_Name is the main table containing all place names.
GN_AlternateName contains names in other languages if any.
EX:
GN_Name.Name - Stockholm
GN_AlternateName.AlternateName - Estocolmo (if IsoLanguage=="es")
Rules:
I want to use GN_AlternateName.AlternateName if it exists for the specified language and if it starts with the search string.
If not, i want to use GN_Name.Name if it starts with the search string.
I want GeoNameId to be unique.
Basically I could outer join in first record only, but that seemed to decrease performance.
I've got the following SQL (basically modified SQL from a LINQ query). The problem is that it only finds 'Estocolmo' if search string starts with "stock". "estoc" yields nothing.
select
distinct(n.GeoNameId) as Id,
an.IsoLanguage,
CASE WHEN (an.AlternateName like N'estoc%')
THEN an.AlternateName
ELSE n.Name
END AS [The name we are going to use]
from GN_Name as n
LEFT OUTER JOIN GN_AlternateName as an
ON n.GeoNameId = an.GeoNameId
AND 'es' = an.IsoLanguage
WHERE n.Name like N'estoc%'
UPDATE
Thanks Rahul and Lee D.
I now have the following:
select
distinct(n.GeoNameId) as Id,
an.IsoLanguage,
CASE WHEN (an.AlternateName like N'estoc%')
THEN an.AlternateName
ELSE n.Name
END AS [The final name]
from GN_Name as n
LEFT OUTER JOIN GN_AlternateName as an
ON n.GeoNameId = an.GeoNameId
AND 'es' = an.IsoLanguage
WHERE (n.Name LIKE N'estoc%' OR an.AlternateName LIKE N'estoc%')
This performs LIKE twice on an.AlternateName. Is there any way i could get rid of on LIKE clause?
UPDATE 2
Andriy M made a nice alternative query using COALESCE. I changed it a little bit and ended up with the following:
SELECT Id, LocalisedName
FROM (
SELECT
n.GeoNameId AS Id,
an.IsoLanguage,
COALESCE(an.AlternateName, n.Name) AS LocalisedName
FROM n
LEFT JOIN GN_AlternateName AS an ON n.GeoNameId = an.GeoNameId
AND IsoLanguage = 'es'
) x
WHERE LocalisedName LIKE 'estoc%'
This query does exactly what i am looking for. Thanks!
Here's a probable solution of the problem, which uses a slightly different apporach:
SELECT Id, LocalisedName
FROM (
SELECT
n.GeoNameId AS Id,
an.IsoLanguage,
COALESCE(an.AlternateName, n.Name) AS LocalisedName
FROM GN_Name AS n
LEFT JOIN GN_AlternateName AS an ON n.GeoNameId = an.GeoNameId
AND IsoLanguage = 'es'
) x
WHERE LocalisedName LIKE 'estoc%'
(Changed it based on your update.)
If I understand correctly, in your example the value 'Estocolmo' is in the GN_AlternateName.AlternateName column, so would be filtered out by the where clause which only looks at GN_Name.Name. What if you change the last line of SQL to:
WHERE n.Name LIKE N'estoc%' OR an.AlternateName LIKE N'estoc%'
I'm assuming 'estoc%' is your search string.
I guess you need to modify the WHERE clause to check in GN_AlternateName table as well
WHERE n.Name like N'estoc%' OR an.AlternateName like 'N'estoc%'