I have to preface this by telling you that I am just learning SQL. My task is to validate a report generated by T-SQL written by a consultant that used to work for our company. Can someone explain to me what the following section is doing? I understand the idea of a LEFT OUTER JOIN, but I don't understand how the case statement evaluates.
From
ShipmentQty
LEFT OUTER JOIN ShipmentCost ON
Case when ShipmentQty.RSLDNM <> 0 Then
0
Else
ShipmentQty.SDSHPN
End = ShipmentCost.FHSHPN
AND
ShipmentQty.RSLDNM = ShipmentCost.FHLDNM
I assume that the expression runs without error, but again, my task is not to run the SQL, only to validate each step of the code. Thank you in advance and please forgive my inexperience.
It just means that if ShipmentQty.RSLDNM is not 0, then use 0, otherwise, use ShipmentQty.SDSHPN
It can be easier to understand the logic without the case. This is probably the equivalent logic:
From ShipmentQty LEFT OUTER JOIN
ShipmentCost
ON ((ShipmentCost.FHSHPN = 0 AND ShipmentQty.RSLDNM <> 0) OR
(ShipmentCost.FHSHPN = ShipmentQty.SDSHPN AND ShipmentQty.RSLDNM = 0)
) AND
ShipmentQty.RSLDNM = ShipmentCost.FHLDNM
I say "probably" because this does not take NULL values of ShipmentQty.RSLDNM into account. So, if RSLDNM is zero, then the comparison is FHSHPN to SDSHPN. If RSLDNM is not zero, then FHSHPN needs to be zero.
the join is simple, the case is just a condition (Watch this link), when the field ShipmentQty.RSLDNM <> 0 then the join will use a 0 as value, if else the join will use ShipmentQty.SDSHPN as value.
Related
Hello I am missing something because my code errors.
select * from ##ScheduleDetail SD
left join ##HolidayFilterTbl HF on SD.Scheduledate = HF.Testdate
where (ScheduleDate = testdate)
and
(Case
when HF.IsHoliday = 1 then (overtime = 1 and makeup = 0)
else
(overtime = 0 and Makeup = 0)
end
)
and
DOW = 5
order by ActivityStartTime
I've attempted several combinations and each one errors at either the first equal sign or the second. What am I missing?
The branches of a case expression can only return values, not additional expressions to be evaluated in the where condition. You could, however, simulate this behavior with the and and or logical operators:
select *
from ##ScheduleDetail SD
left join ##HolidayFilterTbl HF on SD.Scheduledate = HF.Testdate
where (ScheduleDate = testdate) and
((HF.IsHoliday = 1 and overtime = 1 and makeup = 0) or
(overtime = 0 and Makeup = 0)) and
DOW = 5
order by ActivityStartTime
Note that you have makeup = 0 on both branches of the case expression in the question (or both sides of the or in the answer), so you could extract it out of it and simplify the condition a bit:
select *
from ##ScheduleDetail SD
left join ##HolidayFilterTbl HF on SD.Scheduledate = HF.Testdate
where ScheduleDate = testdate and
makeup = 0 and
((HF.IsHoliday = 1 and overtime = 1) or
overtime = 0) and
DOW = 5
order by ActivityStartTime
If you are still wanting to know how to utilize a CASE Statement Expression in a WHERE Clause the CASE Expression must be compared to a value as that is the syntax understood for conditions contained within a WHERE Clause. See below a mock example.
SELECT *
FROM ##ScheduleDetail SD
LEFT JOIN ##HolidayFilterTbl HF ON SD.Scheduledate = HF.Testdate
WHERE(ScheduleDate = testdate)
AND
/* If you wish to stick with using a CASE Expression within the WHERE Clause set the the CASE Expression equal to 'something'. I usually stick with 1 or 0 'true/false'.
| You simply have to create your own True/False evaluation. You can add your logic checks within a CASE Expression within
| the WHERE Clause and when your logic is TRUE THEN return 1. Basically you are saying when 1 = 1 then return Record.
*/
1 =
Case
WHEN HF.IsHoliday = 1 AND makeup = 0 THEN
CASE WHEN (overtime = 1 OR overtime = 0) THEN 1 END /* Return 1 here to evaluation to TRUE */
ELSE
0 /* You can add another CASE here if needed and when the condition you write in evaluations to 1 'true' return record */
END
AND
DOW = 5
ORDER BY ActivityStartTime;
There are a few reasons I've used CASE Expressions within a WHERE Clause over using AND/ORs. Just one minor reason is it allows me to contain and organize logic in a WHERE Clause inside CASE Expressions rather than having multiple AND/ORs all nested together. I've also found that using CASE Expressions in the WHERE Clause is useful when encountering Dynamic queries that accept variables to be later inserted into the SQL before being sent to the database for processing. In the case of using Dynamic SQL there are times when a CASE Statement MUST be used due to the fact that there could be data that is being compared against in the WHERE clause that is NOT a column.field value but a hardcoded value that is compared to perhaps a user selection or status (as examples)... it might be a static value passed in via the application which is how my web application works that I support which is why I bring it up.
Basically it's good to know how to use a CASE Expression in a WHERE Clause as there are some cases when the ONLY way to evaluate certain data is by using a CASE Expression .
I have no data to test this against and that's not the point. The point of my answer is to simply provide to you an alternative to the existing answer. In my opinion this logic is basic and the already provided answer is the correct one however my answer is to demonstrate how you could go about using a CASE in a WHERE Clause.
If interested see this SO Post for the differences between a CASE Statement vs a CASE Expression however know that this terminology slightly differs between databases.
As an example of this... SQL Server refers to these as Simple vs Searched but refers to all of it as a CASE Expression. Therefore a CASE Expression can either be a Simple or a Searched CASE that can be used within a Statement.
So I'm trying to put a subquery within a CASE statement. The subquery itself is working fine, but if I put it in another code it can't process. What can I do best to solve?
CASE WHEN dbo.T1.TYPE = 0
THEN dbo.Data.QTY * dbo.Data.SALESPRICE
ELSE
CASE WHEN dbo.T1.TYPE = 1
THEN dbo.Data.QTY *
(
SELECT dbo.Data.ID,
CASE WHEN SUM(dbo.Data.QTY) = 0
THEN SUM(dbo.Data.SALESPRICE)
ELSE SUM(dbo.Data.SALESPRICE) / SUM(dbo.Data.QTY)
END AS REVph
FROM dbo.Data LEFT OUTER JOIN
dbo.T1ON dbo.Data.ID = dbo.T1.ID
WHERE (dbo.T1.TYPE = 1)
GROUP BY dbo.Data.ID
)
ELSE 0
END
END
You are using a subquery in a context where a single value is allowed. Such a subquery is called a scalar subquery.
However, the subquery is returning more than one column. That is not allowed. A scalar subquery can only return one column and at most one row.
Your question is rather unclear on what you want to accomplish, so I can only explain the problem that you are having.
I'm trying to use case function at Join and I failed to execute the Query.
What I'm doing wrong?
left join vortex_dbo.vw_public_material_history on
CASE
WHEN vw_public_request_material_location_mir.material_request_id = (substring(vw_public_material_history.comments,12,6))
then vw_public_request_material_location_mir.material_request_id
else null
end
What I wish to get is join rows only if I have "true" from the "When"
I feel I miss something here.
Your CASE expression makes no sense. A CASE expression results in a value, in your case for example in material_request_id. So you'd get
left join vortex_dbo.vw_public_material_history on material_request_id
in case of a string match. You do notice that this ON clause is incomplete?
You are probably looking for
left join vortex_dbo.vw_public_material_history on
vw_public_request_material_location_mir.material_request_id =
(substring(vw_public_material_history.comments,12,6))
That would read better with table aliases:
from vw_public_request_material_location_mir mir
left join vortex_dbo.vw_public_material_history hist on
mir.material_request_id = (substring(hist.comments,12,6))
As to your data model: It seems strange that you have an ID hidden in a string. You may want to re-consider your table design.
I am relatively new to SQL and am trying to apply the case function within a view.
While I understand the fundamentals of it, I am having difficulty applying it in the way that I need.
I have 3 columns ApplicationID, ServerName and ServerShared? (true/false).
Each application can have many servers associated to it, while each server only has 1 server type.
I would like to use case to create a further field which can take three values dependent upon whether the values of ServerShared related to an application are all True = Shared, False = Non-shared, Both True and False = Partially shared.
My thoughts were using count function within the case function to set statements where:
if 'count true > 0 and count false > 0' then ServerShared? =
partially if 'count true > 0' and 'count false = 0' then
ServerShared = true and vice versa.
I believe the above logic a way of achieving my result, yet I would appreciate help in both how to structure this within a case statement and any wisdom if there is a better way.
Thanks in advance!
If I get your question right, this should do the trick. Maybe you need to add further columns or adapt the logic. But you should get the logic behind.
SELECT ServerName,
CASE
WHEN COUNT(distinct ServerShared) = 2
THEN N'Server shared'
WHEN MIN(ServerShared) = 0
THEN N'Server not shared'
WHEN MAX(ServerShared) = 1
THEN N'Server shared'
END as ServerShared
FROM myTable
GROUP BY ServerName
There are two main ways to do this problem (super generic answer from non expert :D)
less often executed (one off?), slow execution with potential exponential time increases as rows go up:
This is similar to your suggested solution and involves putting other queries in the Select / field list part of the query - this will get executed for every row returned by the main part of the query (bad news generally speaking):
select
applicationID
, Case (select count * from table as b where a.applicationid = b.applicationid and shareserver=true)
WHEN 0 then 'Non-Shared'
WHEN (select count * from table where a.applicationid = b.applicationid) then 'Shared'
ELSE 'Partially-Shared' END as ShareType
from
tabls as a
get all your data once then perform just the comparison row by row. this is what i would use by default.. its basically better as far as i know but sometimes can be harder to think through.
this line is here to fix formatting issue
select
a.applicationid
,case
when sharedservers = 0 then 'Non-Shared'
when totalservers=sharedservers then 'Shared'
else 'Partially-Shared' END as ShareType
FROM
(select applicationID, count(*) as TotalServers from table) as a
LEFT OUTER JOIN (select applicationID, count(*) as SharedServersfrom table where sharedserver = true) as b
ON a.applicationid=b.applicationid
these queries are just written off the top of my head let me know if there are bug :/
note also the two uses of case statement. one with CASE *value* WHEN *possible value* THEN .. and the second way CASE WHEN *statement that evaluates to boolean* THEN ..
I have been doing this
SELECT
movi.Usuario AS RowUsuario, movi.MovID, MIN(Art.Descripcion1),
MIN(com.ReferenciaExtra), MIN(com.Unidad), MIN(Art.UnidadCompra),
MIN(movi.FechaEmision),
error = CASE
WHEN MIN (com.Unidad) NOT LIKE
CASE
WHEN MIN (ar.Unidad) LIKE com.Unidad THEN art.Unidad
END
THEN 1
ELSE 0
END
FROM
CompraD com
INNER JOIN
Mov movi ON com.ID = movi.ID
INNER JOIN
Art ON com.Articulo = Art.Articulo
WHERE
movi.Mov = 'Requisicion
ORDER BY
movi.FechaEmision ASC
`when 'com.unidad' dont match with art.Unidad, add 1 or 0 if they match
SQL Server says:
incorrect syntax CASE
The incorrect syntax error is referring to the
error = CASE part.
It should be
CASE statement END AS error
However I'm not sure if that will solve your problem as the case statements looks a little odd to me but get that bit the right way around and then let us know of any further error messages.
Possibly...
SUM(CASE WHEN com.Unidad <> ar.Unidad THEN 1 ELSE 0 END AS error)
Also, you are missing a GROUP BY clause, if you want to use aggregate functions (MIN for example) you need to GROUP BY the non aggregate fields.
You have WHEN MIN (ar.Unidad) LIKE com.Unidad THEN art.Unidad but I do not see ar aliased anywhere.
Also you need to either have GROUP BY or OVER clause with your MINs.
If you want more details you'll have to give more details and context.