IF THEN in SQL Select Statement - sql

I'm writing a report to return vendor names from journal transactions. Here are the basics of the query below.
I am using data from two views:
Journal detail view = pa_journal_detail
Vendor detail view = ap_vendor
Match on Vendor Number:
The vendor number is contained in the following fields:
ap_vendor.a_vendor_number
pa_journal_detail.jl_ref1 [under certain criteria shown below] ONLY WHEN the journal source code is "API" or "APM"
The source code is stored in the field pa_journal_detail. jl_source_code
The vendor name is stored in the field ap_vendor.a_vendor_name
This is the query I had started with. It is returning incorrect syntax errors when I attempt to run.
SELECT
CASE
WHEN pa_journal_detail. jl_source_code = ‘API’
OR pa_journal_detail. jl_source_code = ‘APM’
THEN(
SELECT a_vendor_name
FROM ap_vendor
INNER JOIN pa_journal_detail
ON pa_journal_detail.jl_ref1 = ap_vendor.a_vendor_number)
ELSE 0
END as a_vendor_name, *
FROM pa_journal_detail
Here is the full query below. I have also tried it with the "TOP 1" included as well. I am now getting the error that there is incorrect syntax near the keyword AS.
SELECT
pa_journal_detail.a_project
,pa_journal_detail.jl_seg2
,pa_journal_detail.jl_seg3
,pa_journal_detail.jl_seg4
,pa_journal_detail.jl_source_code
,pa_journal_detail.jl_ref1
,pa_journal_detail.jl_gl_org
,pa_journal_detail.jl_gl_obj
,pa_journal_detail.jl_line_num
,pa_journal_detail.jl_journal_num
,pa_journal_detail.jl_jnl_year_period
,pa_journal_detail.jl_journal_number
,pa_journal_detail.jl_journal_seq
,(SELECT(CASE
WHEN pa_journal_detail. jl_source_code = 'API'
OR pa_journal_detail. jl_source_code = 'APM'
THEN(
SELECT TOP 1 a_vendor_name
FROM ap_vendor
RIGHT JOIN pa_journal_detail
ON pa_journal_detail.jl_ref1 = ap_vendor.a_vendor_number
)
ELSE 0
END as 'a_vendor_name', *
FROM pa_journal_detail))
FROM pa_journal_detail
This is what I ended up with and its working now! Thank you all!
SELECT
pa_journal_detail.a_project
,pa_journal_detail.jl_seg2
,pa_journal_detail.jl_seg3
,pa_journal_detail.jl_seg4
,pa_journal_detail.jl_source_code
,pa_journal_detail.jl_ref1
,pa_journal_detail.jl_gl_org
,pa_journal_detail.jl_gl_obj
,pa_journal_detail.jl_line_num
,pa_journal_detail.jl_journal_num
,pa_journal_detail.jl_jnl_year_period
,pa_journal_detail.jl_journal_number
,pa_journal_detail.jl_journal_seq
,iif((pa_journal_detail.jl_source_code = 'API'
OR pa_journal_detail.jl_source_code = 'APM')
,(SELECT TOP 1 a_vendor_name
FROM ap_vendor
RIGHT JOIN pa_journal_detail
ON pa_journal_detail.jl_ref1 = ap_vendor.a_vendor_number)
,0) as 'a_vendor_name'
FROM pa_journal_detail

for string compare you need to use single quote
CASE
WHEN pa_journal_detail. jl_source_code = 'API'
OR pa_journal_detail. jl_source_code = 'APM'
THEN(
SELECT top 1 a_vendor_name -- here you need limit or top 1
FROM ap_vendor
INNER JOIN pa_journal_detail
ON pa_journal_detail.jl_ref1 = ap_vendor.a_vendor_number
)
ELSE 0
END as a_vendor_name, *
FROM pa_journal_detail

There is also iif(). I use it far more often than I should, I just like have a tiny little if for simple conditional work instead of big ole' Case statement.
select iif(1 = 1,'True','False')
-- any series that results in a boolean
select iif((1 = 1 and 0 = 0) and (5 / 1 = 5 and 5 % 10 = 5),'True','False')
for your query
SELECT
pa_journal_detail.a_project
,pa_journal_detail.jl_seg2
,pa_journal_detail.jl_seg3
,pa_journal_detail.jl_seg4
,pa_journal_detail.jl_source_code
,pa_journal_detail.jl_ref1
,pa_journal_detail.jl_gl_org
,pa_journal_detail.jl_gl_obj
,pa_journal_detail.jl_line_num
,pa_journal_detail.jl_journal_num
,pa_journal_detail.jl_jnl_year_period
,pa_journal_detail.jl_journal_number
,pa_journal_detail.jl_journal_seq
,iif(pa_journal_detail.jl_source_code = 'API' OR pa_journal_detail.jl_source_code = 'APM',(SELECT TOP 1 a_vendor_name
FROM ap_vendor
RIGHT JOIN pa_journal_detail
ON pa_journal_detail.jl_ref1 = ap_vendor.a_vendor_number)
,0)
'a_vendor_name', *
FROM pa_journal_detail))
FROM pa_journal_detail

I think a case expression may be the wrong tool for the job. If you want to join a table sometimes, a left join may be easier:
SELECT p.*, a.a_vendor_name
FROM pa_journal_detail p
LEFT JOIN ap_vendor a ON p.jl_ref1 = a.a_vendor_number AND
p.jl_source_code IN ('API', 'APM')

Related

Case When + IN combination

I'm a bit stuck in my coding here... I have this extense and complex code, but I'm actually failling by the end of it. I'm getting the SQL Error [42804]: ERROR: argument of CASE/WHEN must be type boolean, not type character varying
The thing, is: when "bairro" matches a row from "SUB_COUNTRY_DB", get psd.name, else get z.name. Any tips on how I could accomplish this?
select distinct
aa.mes,
--aa.modalidade,
--to_date(aa.created_date, 'yyyy-mm-dd') data_captacao,
ucl.ja_comprou_lf as comprou_lf,
case when bairro in (select sub_country from sub_country_DB)
then psd.name
else z.name
end loja,
count (distinct aa.customer_uid) qtde_socios,
count (distinct aa.assinatura_uid) qtde_assinaturas
from assinaturas_ativas aa
left join ultima_compra_loja_fisica ucl on (aa.customer_uid = ucl.customer_uid
and aa.mes = ucl.mes)
left join zip_code z on (aa.customer_uid = z.customer_uid
and aa.mes = z.mes)
left join SUB_COUNTRY_DB psd
on (psd.district = aa.bairro)
group by 1,2,3--,4
Try variants like:
moving condition to an inner query
CASE WHEN EXISTS (SELECT DISTINCT sub_country FROM sub_country_DB WHERE sub_country = barrio)
ANY (PostgreSQL only)
CASE WHEN bairro = ANY(ARRAY_AGG(select sub_country from sub_country_DB))

Sorry I need to hide

Elon Reeve Musk FRS is an entrepreneur and business magnate. He is the founder, CEO, and Chief Engineer at SpaceX; early-stage investor, CEO, and Product Architect of Tesla, Inc.; founder of The Boring Company; and co-founder of Neuralink and OpenAI.
Your inner select returns a table. That can't be used as parameter to match a WHERE IN condition. Instead try using an INNER JOIN
sum(decode(
select sum(dou.noukn)
from dou
join v_kzeiritsu on
dou.zeiritsu = v_kzeiritsu.zeiritsu
)) as noukn2;
Just move your sum logic inside select as follows:
(SELECT SUM(DOU$2.NOUKN)
FROM SDNISHI.V_KZEIRITSU V
WHERE DOU$2.ZEIRITSU = V.ZEIRITSU) AS NOUKN2
In case If it gives aggregation error then use sum(above query) AS NOUKN2
Your code is very strange. For instance, it seems to assume that V_KZEIRITSU has one row. But, you can move this to the FROM clause:
SELECT SUM(CASE WHEN DOU.ZEIRITSU = K.ZEIRITSU THEN DOU.NOUKN ELSE 0 END) AS NOUKN2
FROM DOU LEFT JOIN
V_KZEIRITSU K
ON 1=1 -- in case the table is really empty
A slightly more reasonable version would be:
SELECT SUM(DOU.NOUKN) AS NOUKN2
FROM DOU LEFT JOIN
V_KZEIRITSU K
ON DOU.ZEIRITSU = K.ZEIRITSU -- in case the table is really empty
It seems rather unlikely to me that this is what you really intend. If not, I would suggest that you ask a new question with appropriate same data, desired results, and explanation of the results. A non-working query should not be expected to provide the same level of information.
I'd say that it is, actually, as simple as
select sum(dou.noukn)
from dou
where dou.zeiritsu in (select zeiritsu from v_kzeiritsu)
(I'm not sure what dou is (table? alias?), but I hope you do.)
After you edited the question, I'm editing the answer. I marked with "--> this" two lines that - in my opinion - might help. As previously, the whole sum(case ...) as noukn2 is replaced by a simple sum(dou$2.noukn).
Note that - in Oracle - you can't use as keyword for table alias. For example:
no: from employees as e
yes: from employees e
Here's your query:
SELECT DOU$2.CUSTCD AS CUSTCD,
DOU$2.CHUNO AS CHUNO,
DOU$2.LINNO AS LINNO,
DOU$2.SHIPDAYYM AS SHIPDAYYM,
SUM (DOU$2.NOUKN) AS NOUKN,
SUM (DOU$2.ZEIKN) AS ZEIKN,
SUM (dou$2.noukn) AS noukn2 --> this
FROM SDNISHI.T_HCHUMON_DOUSOU DOU$2
INNER JOIN SDNISHI.SY_KANRI KNR ON KNR.SHIPDAYYM = DOU$2.SHIPDAYYM
INNER JOIN SDNISHI.T_HCHUMON_MEI MEI
ON MEI.CUSTCD = DOU$2.CUSTCD
AND MEI.CHUNO = DOU$2.CHUNO
AND MEI.LINNO = DOU$2.LINNO
AND MEI.SHIPDAYYM = DOU$2.SHIPDAYYM
AND MEI.USEDNGKBN = '0'
AND MEI.CANCELKBN = '0'
LEFT OUTER JOIN SDNISHI.T_HCHUMON_HD HD
ON HD.CUSTCD = MEI.CUSTCD
AND HD.CHUNO = MEI.CHUNO
AND HD.LINNO = MEI.LINNO
AND HD.USEDNGKBN = '0'
AND HD.CANCELKBN = '0'
AND isnull (HD.CANKBN, '00') = '00'
JOIN v_keziritsu vk ON vk.zeiritsu = dou$2.zeiritsu --> this
WHERE DOU$2.USEDNGKBN = '0'
AND DOU$2.CANCELKBN = '0'
AND ( ( MEI.CHGDELKBN = '1'
AND MEI.HDOUSOUKBN = '02'
AND ( MEI.CHUSU > 0
OR MEI.BCHUSU > 0))
OR ( MEI.CHGDELKBN != '1'
AND HD.HDOUSOUKBN = '02'
AND ( MEI.CHKBTNFGA = '1'
AND HD.CHUSU > 0)
OR ( MEI.CHKBTNFGB = '1'
AND HD.BCHUSU > 0)))
GROUP BY DOU$2.CUSTCD,
DOU$2.CHUNO,
DOU$2.LINNO,
DOU$2.SHIPDAYYM

SQL avoid 0 in the calculation

Can anyone help me try to solve this equation? The "Lost_Weight" is a calculation field and I'm trying to get the result of HWeight - renWeight = '0' if the renWeight is 0. The where clause has a controversial statement that put a Challenge to me to make that happen. See below.
SELECT TOP (100) PERCENT dbo.Name.ID,
dbo.Name.CO_ID,
dbo.Name.FULL_NAME,
dbo.Name.STATE_PROVINCE, dbo.Tops_Profile.START_WGHT,
dbo.Tops_Profile.RENEWAL_WEIGHT,
dbo.Tops_Profile.H_WEIGHT - dbo.Tops_Profile.RENEWAL_WEIGHT AS Lost_Weight,
dbo.Tops_Profile.H_WEIGHT,
dbo.Name.JOIN_DATE,
dbo.Name.BIRTH_DATE,
RIGHT(dbo.TOPS_AWARDS.AWARD_TYPE, 15) AS AWARDS_TYPE,
dbo.TOPS_AWARDS.AWARD_CATEGORY,
dbo.TOPS_AWARDS.AWARD_DATE,
dbo.vw_RegDirs.TARGET_ID AS
RD_ID,
dbo.vw_Coords.TARGET_ID AS Coord_ID,
dbo.vw_Coords.FULL_NAME AS
Coord_Name,
dbo.vw_AreaCapts.TARGET_ID AS AC_ID, dbo.Name.STATUS
FROM dbo.Name INNER JOIN dbo.Tops_Profile
ON dbo.Name.ID = dbo.Tops_Profile.ID
INNER JOIN dbo.vw_RegDirs
ON dbo.Name.CO_ID = dbo.vw_RegDirs.CHAPTER
INNER JOIN dbo.vw_Coords
ON dbo.Name.CO_ID = dbo.vw_Coords.CHAPTER
INNER JOIN dbo.vw_AreaCapts
ON dbo.Name.CO_ID = dbo.vw_AreaCapts.CHAPTER
LEFT OUTER JOIN dbo.TOPS_AWARDS
ON dbo.Name.ID = dbo.TOPS_AWARDS.ID
WHERE (dbo.Tops_Profile.RENEWAL_WEIGHT <> '0')
AND (dbo.Name.STATUS = 'a')
AND (dbo.Tops_Profile.H_WEIGHT - dbo.Tops_Profile.RENEWAL_WEIGHT >= 100')
OR (dbo.Name.STATUS = 'a') AND (dbo.TOPS_AWARDS.AWARD_TYPE LIKE '%Century%')
right now if the renewal_weight is 0 it automatically give me the number from the H_WEIGHT in the Lost_Weight field and I need the result to be 0 if the RENEWAL_WEIGHT is 0.
I'm guessing 0 is a special value in this situation. This can be fixed by using CASE
Replace
dbo.Tops_Profile.H_WEIGHT - dbo.Tops_Profile.RENEWAL_WEIGHT AS Lost_Weight
With
CASE WHEN RENEWAL_WEIGHT = 0 THEN 0
ELSE dbo.Tops_Profile.H_WEIGHT - dbo.Tops_Profile.RENEWAL_WEIGHT
END AS Lost_Weight

How can I refactor this query

How can I rewrite this SQL code? I would like to avoid the repetitive execution of the case for every record.
SELECT chcr.chsid,
CASE
WHEN EXISTS
(SELECT 1
FROM hdr_run chre,
clmerr ce
WHERE chre.chsid = chcr.chsid
AND chre.run_nmbr < chcr.last_run_nmbr
AND chre.clm_error_sid = ce.clm_error_sid
GROUP BY chre.chsid
HAVING COUNT(chre.clm_error_sid) > 0
)
THEN 'Appended'
ELSE 'Never Appended'
END Run_Detail
FROM
clm_res chcr,
clm_der chde
WHERE chde.chsid = chcr.chsid
Have a look at that query please:
SELECT
chcr.chsid,
CASE
WHEN ce.clm_error_sid IS NOT NULL AND COUNT(chre.clm_error_sid, 0) > 0
THEN 'Appended'
ELSE 'Never Appended'
END Run_Detail
FROM
clm_res chcr
JOIN clm_der chde ON chde.chsid = chcr.chsid
LEFT JOIN hdr_run chre ON chre.chsid = chcr.chsid AND chre.run_nmbr < chcr.last_run_nmbr
LEFT JOIN clmerr ce ON chre.clm_error_sid = ce.clm_error_sid
GROUP BY chcr.chsid
If there's more than one clm_der for each clm_res based on their chsid, we'd have to double check that the COUNT is not counting the extras from clm_der.
I have no data to test this on so all I can go on is the SQL you've provided but from a brief look it does not appear that the GROUP BY and HAVING COUNT() > 0 statements are required as the combination of the INNER JOIN condition in the sub-query and the use of EXISTS in the outer query does the same thing.
Does this have exactly the same functionality:
SELECT chcr.chsid,
CASE
WHEN EXISTS
( SELECT 1
FROM hdr_run chre
INNER JOIN
clmerr ce
ON (chre.clm_error_sid = ce.clm_error_sid)
WHERE chre.chsid = chcr.chsid
AND chre.run_nmbr < chcr.last_run_nmbr
)
THEN 'Appended'
ELSE 'Never Appended'
END Run_Detail
FROM clm_res chcr
INNER JOIN
clm_der chde
ON ( chde.chsid = chcr.chsid );
SQLFIDDLE
Also, repeated execution of the CASE statement is not a bad thing as the optimizer should not duplicate executions of the sub-query.

Sql in sql server with convert

I am trying to use convert in an where clause in the select statement. My query looks like this:
SELECT DISTINCT TOP 10 [SurveyResult].*
,[Ticket].[RefNumber]
FROM [SurveyResult]
LEFT JOIN [Ticket] ON [SurveyResult].[TicketID] = [Ticket].[TicketID]
JOIN [SurveyResponse] AS SurveyResponse1 ON [SurveyResult].[ResultID] = SurveyResponse1.[ResultID]
JOIN [QuestionAnswer] AS QuestionAnswer1 ON SurveyResponse1.[AnswerID] = QuestionAnswer1.[AnswerID]
JOIN [SurveyQuestion] AS SurveyQuestion1 ON QuestionAnswer1.[QuestionID] = SurveyQuestion1.[QuestionID]
WHERE SurveyQuestion1.[SurveyID] = [SurveyResult].[SurveyID]
AND SurveyQuestion1.[QuestionID] = 'C86CB39A-8FE0-4FE8-B38F-17F1BE611016'
AND CONVERT(INT, SurveyResponse1.[Response]) >= 1
AND CONVERT(INT, SurveyResponse1.[Response]) <= 5
The problem is that I get some errors when converting the values to integer in the where statement.
I know I have some rows that don't contain numbers in the Response column but I filter those so without the convert part in the where clause I get only numbers so it works like this:
SELECT TOP 1000 [ResponseID]
,[ResultID]
,[Response]
FROM [WFSupport].[dbo].[SurveyResponse]
JOIN QuestionAnswer ON SurveyResponse.AnswerID = QuestionAnswer.AnswerID
WHERE QuestionAnswer.QuestionID = 'C10BF42E-5D51-46BC-AD89-E57BA80EECFD'
And in the results I get numbers but once I add the convert part in the statement I I get an error that it can't convert some text to numbers.
Either do like Mark says or just have NULL values default to something numerical, this would give you a where statement like:
WHERE SurveyQuestion1.[SurveyID] = [SurveyResult].[SurveyID]
AND SurveyQuestion1.[QuestionID] = 'C86CB39A-8FE0-4FE8-B38F-17F1BE611016'
AND CONVERT(INT, ISNULL(SurveyResponse1.[Response],0)) BETWEEN 1 AND 5
The important part is the ISNULL() function and I also used BETWEEN to avoid duplicate converts.
Try:
SELECT DISTINCT TOP 10
[SurveyResult].*,
[Ticket].[RefNumber]
FROM
[SurveyResult]
LEFT JOIN [Ticket] ON [SurveyResult].[TicketID] = [Ticket].[TicketID]
JOIN [SurveyResponse] AS SurveyResponse1
ON [SurveyResult].[ResultID] = SurveyResponse1.[ResultID]
JOIN [QuestionAnswer] AS QuestionAnswer1
ON SurveyResponse1.[AnswerID] = QuestionAnswer1.[AnswerID]
JOIN [SurveyQuestion] AS SurveyQuestion1
ON QuestionAnswer1.[QuestionID] = SurveyQuestion1.[QuestionID]
where SurveyQuestion1.[SurveyID] = [SurveyResult].[SurveyID]
AND SurveyQuestion1.[QuestionID] = 'C86CB39A-8FE0-4FE8-B38F-17F1BE611016'
AND CASE SurveyQuestion1.[QuestionID]
WHEN 'C86CB39A-8FE0-4FE8-B38F-17F1BE611016'
THEN Convert(int, SurveyResponse1.[Response])
ELSE 0
END BETWEEN 1 AND 5
(The AND SurveyQuestion1.[QuestionID] = 'C86CB39A-8FE0-4FE8-B38F-17F1BE611016' is retained in case the query is using an index on QuestionID - if not, it can be removed, as the same condition is implicit in the subsequent CASE condition.)
Try this one -
SELECT DISTINCT TOP 10 sr.*, t.[RefNumber]
FROM dbo.SurveyResult sr
JOIN dbo.SurveyResponse sr2 ON sr.[ResultID] = sr2.[ResultID]
JOIN dbo.QuestionAnswer sa ON sr2.[AnswerID] = sa.[AnswerID]
JOIN dbo.SurveyQuestion sq ON sa.[QuestionID] = sq.[QuestionID] AND sq.[SurveyID] = sr.[SurveyID]
LEFT JOIN dbo.Ticket t ON sr.[TicketID] = t.[TicketID]
WHERE sq.[QuestionID] = 'C86CB39A-8FE0-4FE8-B38F-17F1BE611016'
AND CAST(ISNULL(sr2.[Response], 0) AS INT) BETWEEN 1 AND 5