Select Case query not working - sql

New to SQL and in the process of developing query, with the to replicate part of an ETL process.
A billing code1 = bf, is then set to debt code 1. If billing field (debt code) exceeds 100 characters then add '*' as prefix.
However query will fall down because billing code1 = bf returns a single resultset to a debt code1 that returns large resultset.
select
case when len(format) > 100 then left(format, 100) + '*'
else format end as format
from (select case when exists (select _hs_eb_code1 from hbl_cat where hs_eb_code = 'bf)
then tbm_bllgrp._hs_eb_det1 end) as format
from tbm_bllgrp
Ideas welcomed.

select
case when len(format) > 100 then left(format, 100) + '*'
else format end as format
from tbm_bllgrp b
inner join hbl_cat hc on hc._hs_eb_code1 = b._hs_eb_det1
This is just a guess since I don't have your exactl schema and expected output, but I hope this gives you some ideas

Related

Error while using case with substring query while multiply with number

I have an issue while am trying to pull and create specific column output in SQL
select
left(PostalCode,2) as area
,case substring(PostalCode,6,1)
when substring(PostalCode,6,1) = 0 then '100'
when substring(PostalCode,6,1) > 0 then (substring(PostalCode,6,1))*100
else 'NotDigit'
end + substring(PostalCode,6,1) as [location]
from province_table
PostalCode
1K02BC19
1K03B018
1K04B519
I tried many ways to restructure the query above and am always unable to get a result
expected result
Location
NoDigit
100
500
looking forwards to your kind help
Thanks
select
left(PostalCode,2) as area
,case when isnumeric(substring(PostalCode,6,1)) = 1 and substring(PostalCode,6,1) = 0 then cast('100' as varchar(max))
when isnumeric(substring(PostalCode,6,1)) = 1 and substring(PostalCode,6,1) > 0 then cast(substring(PostalCode,6,1)*100 as varchar(max))
else 'NotDigit' end as result
from province_table
area
result
1K
NotDigit
1K
100
1K
500
Fiddle

Find What Column i Joined on when using OR

In My database I have a row with multiple Codes, EG:
ID,Code1,Code2,Code3,Code4
These codes reference a Procedure Name in another table EG:
Code1 = 'Procedure one'
Code2 = 'Procedure two'
ect.
I needed to convert this single row to show one line for every code, and corresponding procedure name EG:
ID,ProcedureName
1,'Procedure One'
1,'Procedure two'
2,'Procedure one'
To get this to work I'm using an outer join with an OR statement, not the most performance effective, but since the ProcedureName Table isn't that large, i'm not too fussed about overhead at the moment, more about getting it to work.
FROM Events EV
LEFT JOIN ProcedureName PN
ON (PN.CODE = Ev.Code1)
OR (PN.CODE = Ev.Code2)
OR (PN.CODE = Ev.Code3)
OR (PN.CODE = Ev.Code4)
This works, however Now I have the problem of being able to tell What procedure is the Primary, and Secondary. Usually the Primary/secondary is denoted purely by whatever one is in the first Code. IE the primary would be whatever is in Code1, secondary in code2, ect.
However since I have now Joined using an OR, i now have no idea what Code that the procedure has joined to.
I've thought of just doing a case statement
CASE
WHEN PN.CODE = Ev.Code1 THEN
'(Primary) ' + ISNULL(PN.NAME, '')
WHEN PN.CODE = Ev.Code2 THEN
'(Secondary) ' + ISNULL(PN.NAME, '')
WHEN PN.CODE = Ev.Code3 THEN
'(Tertiary) ' + ISNULL(PN.NAME, '')
WHEN PN.CODE = Ev.Code4 THEN
'(Quaternary) ' + ISNULL(PN.NAME, '')
END AS ProcedureName,
However this has the major issue of, on the off chance, that both code1 and code2 are the same code. Which means they will both show up as primary.
Can anyone give me any hints as to how to find out what the OR join actually Joined on? did it join on code1, code2? is there perhaps a better way to write the join that will allow me to have multiple lines per ID (depending on amount of codes) whilst still allowing me to find out where they are Code1 or code2?
I would reword the question slightly. In reality the it doesn't "join on a column", it joins on the result of a boolean expression.
So, what you want is to find out which parts of the boolean expression are true or not...
SELECT
*,
CASE WHEN PN.CODE = Ev.Code1 THEN 1 ELSE 0 END AS MatchingCode1,
CASE WHEN PN.CODE = Ev.Code2 THEN 1 ELSE 0 END AS MatchingCode2,
CASE WHEN PN.CODE = Ev.Code3 THEN 1 ELSE 0 END AS MatchingCode3,
CASE WHEN PN.CODE = Ev.Code4 THEN 1 ELSE 0 END AS MatchingCode4
FROM
Events EV
LEFT JOIN
ProcedureName PN
ON PN.CODE IN (Ev.Code1, Ev.Code2, Ev.Code3, Ev.Code4)
If you want that as a single column, you could use binary arithmetic.
SELECT
*,
CASE WHEN PN.CODE = Ev.Code1 THEN 1 ELSE 0 END +
CASE WHEN PN.CODE = Ev.Code2 THEN 2 ELSE 0 END +
CASE WHEN PN.CODE = Ev.Code3 THEN 4 ELSE 0 END +
CASE WHEN PN.CODE = Ev.Code4 THEN 8 ELSE 0 END AS MatchingCodes
FROM
Events EV
LEFT JOIN
ProcedureName PN
ON PN.CODE IN (Ev.Code1, Ev.Code2, Ev.Code3, Ev.Code4)
Here a value of 1 in MatchingCodes means that Code1 is a match. Similarly a value of 3 means Code1 and Code2 both match, or a value of 15 means that all the codes match.
EDIT: (After making it clear that you want multiple rows)
This is similar to Gordon's answer, but has slightly different behaviour; you get 1 row per match instead of 4 rows all the time, or one row with NULLs if there is no match.
SELECT
*
FROM
Events EV
OUTER APPLY
(
SELECT 1 AS MatchedCode, * FROM ProcedureName WHERE CODE = EV.Code1
UNION ALL
SELECT 2 AS MatchedCode, * FROM ProcedureName WHERE CODE = EV.Code2
UNION ALL
SELECT 3 AS MatchedCode, * FROM ProcedureName WHERE CODE = EV.Code3
UNION ALL
SELECT 4 AS MatchedCode, * FROM ProcedureName WHERE CODE = EV.Code4
)
PN
I think apply does what you want:
select e.id, v.which, v.code
from Events e cross apply
(values ('procedure1', code1), ('procedure2', code2), ('procedure3', code3), ('procedure4', code4)
) v(which, code)
If you want to filter out codes that are NULL, then add:
where v.code is null

Oracle SQL to get min number from case statement

I have this query below (in Oracle PL/SQL) which I am trying to pull a price, it seems to give me 3 records but I only want one. I want to show the lowest rate if I run into this kind of scenario, can I possibly put a min function around the 'rate' field which is in the case statement below?
select /*+ rule */ a.skucode as skucode,a.sizecode as
sizecode,b.colourdescription as colourdesc, a.season as season,
(case when sp.eventnbr in (select eventnbr from event where sysdate
between eventbegints
and eventendts) then rate else sellprice end) as listprice
from sku a, colour b, skuprcevnt sp
where a.skucode = '00000000051361264-04'
--" and a.storecode = '00000' " +
and a.storecode = '00000'
and a.colourcode = b.colourcode
and a.skucode=sp.skucode(+)
order by a.skucode, a.sizecode, b.colourdescription;
This gives the following result (but I want to see the price of 76.99 only):
SKUCODE SIZECODE COLOURDESC SEASON LISTPRICE
00000000051361264-04 XL BLACK FA-13 155
00000000051361264-04 XL BLACK FA-13 155
00000000051361264-04 XL BLACK FA-13 76.99
You can use MIN in the column list if you group the query appropriately:
select a.skucode,
a.sizecode,
b.colourdescription as colourdesc,
a.season,
MIN(case
when sp.eventnbr in (select eventnbr
from event
where sysdate between eventbegints
and eventendts)
then rate
else sellprice
end) as listprice
from sku a
INNER JOIN colour b
ON b.colourcode = a.colourcode
LEFT OUTER JOIN skuprcevnt sp
ON sp.skucode = a.skucode
where a.skucode = '00000000051361264-04' and
a.storecode = '00000'
GROUP BY a.SKUCODE, a.SIZECODE, b.COLOURDESCRIPTION, a.SEASON
order by a.skucode, a.sizecode, b.colourdescription, a.SEASON;
Share and enjoy.
The contents of your select clause will never affect the number of rows returned by a query. You need a filter in the WHERE clause along the lines of WHERE rate = (select min(rate) sku where skucode=a.skucode ).
Your example is more complicated so the actual filter would be bigger but that's just an idea of what it would look like.

SQL Calculate Percentage on 2 columns

I have a problem, I need to calculate the percentage between 2 different columns. Unfortunately I can't get it to work and when I run this all I get is "Invalid column name 'CountOfPlannedVisits'" & "Invalid column name 'CountOfPlannedVisitsClosed'"
SELECT Count(*) As CountOfPlannedVisits, MAX(datename(month, dbo.tblVisit.DateConfirmed)) AS MonthName,
SUM(CASE WHEN tblVisit.VisitTypeRef <> '5' THEN 1 ELSE 0 END) AS CountOfPlannedVisitsClosed, CAST(100.0 * SUM("CountOfPlannedVisits") / SUM(CountOfPlannedVisitsClosed) AS Decimal(5,2) ) As OverallAttendance
FROM dbo.tblContract INNER JOIN
dbo.tblCustomer ON dbo.tblContract.CustomerRef = dbo.tblCustomer.CustomerID INNER JOIN
dbo.tblContractSite ON dbo.tblContract.ContractID = dbo.tblContractSite.ContractRef INNER JOIN
dbo.tblVisit ON dbo.tblContractSite.CardNumber = dbo.tblVisit.CardNumber
WHERE (tblCustomer.CustomerNumber = '08434')
AND (tblVisit.Routine = '1')
AND year(tblVisit.DateConfirmed) = Year('2013')--#DateYear)
AND dbo.IsOnHoldEx(tblContract.OnHold, tblContractSite.OnHold, tblContract.OnHoldStartDate, tblContract.OnHoldEndDate, tblContractSite.OnHoldStartDate, tblContractSite.OnHoldEndDate) = 0
AND tblVisit.Deleted = 0 -- make sure we dont pull through deleted visits
AND (tblContractSite.DateInactive is NULL or tblContractSite.DateInactive > GetDate())
GROUP BY month(dbo.tblVisit.DateConfirmed)
Any help would be greatly appreciated as I'm not really sure where to go from here!
Thanks
You can only reference a column alias (like CountOfPlannedVisits in your case) in the order by clause. Anywhere else you have to repeat the expression or use a subquery table, something like :
select CountOfPlannedVisits,
CountOfPlannedVisitsClosed,
100 * CountOfPlannedVisits / CountOfPlannedVisitsClosed, ...
from (
select some_expression as CountOfPlannedVisits ,
some_other_expression as CountOfPlannedVisitsClosed
....
) a_table
....

Case condition broken need assistance to fix

New to SQL, so please accept my apologies. A query was created that when
If HBL_CLNT_CAT._HS_EB_CODE1 = 'BF' then value = TBM_BILLGRP._HS_EB_DET1
If HBL_CLNT_CAT._HS_EB_CODE2 = 'BF' then value = TBM_BILLGRP._HS_EB_DET2
However of the _HS_EB_DET# exceeds 100 characters add a '*'.
With assistance a query was developed, however it broken the condition rules in that the 'then statement/action would fail because it was greater number than the condition statement (select _hs_eb_code1 from hbl_cat where hs_eb_code = 'bf' that returns only 1 record).
select
case when len(format) > 100
then left(format, 100) + '*'
else format
end as format
from
( select
case when exists ( select _hs_eb_code1
from hbl_cat
where hs_eb_code = 'bf'
)
then tbm_bllgrp._hs_eb_det1
end
) as format
from tbm_bllgrp
Formatting the code would have helped you find the error. Try this:
select
case when len(format) > 100
then left(format, 100) + '*'
else format
end as format
from
( select
case when exists ( select _hs_eb_code1
from hbl_cat
where hs_eb_code = 'bf'
)
then tbm_bllgrp._hs_eb_det1
end as format
from tbm_bllgrp
) as tmp
The above query is broken in several places. A working statement could look like this:
SELECT CASE
WHEN len(x.myval) > 100 THEN
left(x.myval,100) + '*'
ELSE
x.myval
END AS format
FROM (
SELECT CASE
WHEN h.HS_EB_CODE1 = 'BF' THEN
t._HS_EB_DET1
WHEN h._HS_EB_CODE2 = 'BF' THEN
t._HS_EB_DET2
ELSE
'unknown option'
END AS myval
FROM HBL_CLNT_CAT AS h
JOIN TBM_BILLGRP AS t ON ??? -- how are the two tables connected?
WHERE ??? -- some condition or do you want all rows in the table?
) AS x
But you need to tell us first, how TBM_BILLGRP and HBL_CLNT_CAT can be joined, and how you select your rows.
BTW, upper case is pointless in SQL-Server. Identifiers are case-insensitive as long as they are not enclosed in double quotes " " or brackets [ ].