How to fix ORA-00905 missing keyword with case expression - sql

I have problem with case in the line I marked it below.
I need it to be shown like
debits | credits | total debits | total credits
The SQL query is:
SELECT cv_amount,
case when cv_amount > 0 then cv_amount else 0 end as debits,
case when cv_amount < 0 then cv_amount*-1 else 0 end as credits,
sum(case when cv_amount > 0 then cv_amount else 0)--- ERROR SHOWEN HERE--- end as d,
sum(case when cv_amount < 0 then cv_amount*-1 else 0) end as c
FROM dof
where currency_code = 368
AND to_DATE('05/05/19', 'DD/MM/YY') and to_DATE('05/05/19', 'DD/MM/YY')
group by cv_amount

There is a syntax error in the following two lines
sum(case when cv_amount > 0 then cv_amount else 0) end as d,
sum(case when cv_amount < 0 then cv_amount*-1 else 0) end as c
the end should be with in the parentheses, so the query wil be:
sum(case when cv_amount > 0 then cv_amount else 0 end) as d,
sum(case when cv_amount < 0 then cv_amount*-1 else 0 end) as c

You don't really need case for this:
select cv_amount,
greatest(cv_amount, 0) as debits,
abs(least(cv_amount, 0)) as credits,
sum(greatest(cv_amount, 0)) as d,
sum(abs(least(cv_amount, 0))) as c
from dof
where currency_code = 368 and
<something goes here> = date '2019-05-05'
group by cv_amount;
The bigger issues are that the where clause doesn't make sense. And the aggregation by cv_amount doesn't really make sense.

Related

Query % of x item based on x+y total

I'm running a SQL command which returns me the following table
What I need now, is to retrieve how much % corretiva is from total, and how much % preventiva is from total for each month, so there must be another 2 columns like preventivas% and corretivas% as example, I know MES.1 (month 1), will return preventiva =100%, and corretiva = 0%,
This is my query
SELECT
MONTH(workOrderDate) AS MES,
(SUM(CASE WHEN WorkType = '02' AND workOrderDescription = 'preventiva' THEN 1.0 ELSE 0 END)) AS preventiva,
(SUM(CASE WHEN workOrderDescription = 'CORRETIVA' THEN 1 ELSE 0 END)) AS corretivas,
SUM(CASE WHEN WorkType = '02' AND workOrderDescription = 'preventiva' THEN 1.0 ELSE 0 END + CASE WHEN workOrderDescription = 'CORRETIVA' THEN 1 ELSE 0 END) AS total
FROM
WorkOrder
WHERE
YEAR(workOrderDate) = 2018
AND lastUpdateData IS NOT NULL
GROUP BY
MONTH(workOrderDate);
I can't seem to figure out how to achieve the wanted result, would anyone please help me?
Thanks!
You can take your existing query, put it into a CTE, and then calculate your percentages in the main SELECT, like this:
;WITH subresults AS
(
SELECT
MES = MONTH(workOrderDate)
,preventiva = ( SUM(CASE WHEN WorkType = '02'
AND workOrderDescription = 'preventiva'
THEN 1.0
ELSE 0 END
)
)
,corretivas = ( SUM(CASE WHEN workOrderDescription = 'CORRETIVA' THEN 1 ELSE 0 END))
,total = SUM(CASE WHEN WorkType = '02'
AND workOrderDescription = 'preventiva'
THEN 1.0
ELSE 0 END + CASE WHEN workOrderDescription = 'CORRETIVA' THEN 1 ELSE 0 END
)
FROM WorkOrder
WHERE
YEAR(workOrderDate) = 2018
AND lastUpdateData IS NOT NULL
GROUP BY MONTH(workOrderDate)
)
SELECT
s.MES
,s.preventiva
,s.corretivas
,s.total
,preventivasPct = CASE WHEN s.total <> 0 THEN (s.preventiva / s.total) * 100.0 ELSE NULL END
,corretivasPct = CASE WHEN s.total <> 0 THEN (s.corretivas / s.total) * 100.0 ELSE NULL END
FROM subresults s
EDIT: I added CASE statements to preventivasPct and corretivasPct. When the total is 0, the CASE will return NULL. Feel free to change NULL to some other value if you want. I've found that usually 0 or NULL is the correct answer when encountered with divide-by-zero when calculating percentages.

Why doesn't the "having" clause work?

For the following query:
select count(distinct email_address)
from
(
select distinct email_address,
case when elq_activity_type='EmailSend' then 1 else 0 end 'Sends',
case when elq_activity_type='Bounceback' then 1 else 0 end 'Bounces',
case when elq_activity_type='EmailOpen' then 1 else 0 end 'Opens',
case when elq_activity_type='EmailClickthrough' then 1 else 0 end 'Clicks'
from elq_stg_activity
) a
having sum(sends-bounces)>0
The having clause doesn't seem to be doing anything. What am I doing wrong?
Need to get all unique emails that had an email delivered to them (send-bounce).
Thanks!
I think you want this:
select count(email_address)
from (select email_address,
sum(case when elq_activity_type = 'EmailSend' then 1 else 0 end) Sends,
sum(case when elq_activity_type = 'Bounceback' then 1 else 0 end) as Bounces,
sum(case when elq_activity_type = 'EmailOpen' then 1 else 0 end) as Opens,
sum(case when elq_activity_type = 'EmailClickthrough' then 1 else 0 end) as Clicks
from elq_stg_activity
group by email_address
) a
where sends = bounces;
There are numerous issues with your query. This is the only sensible interpretation I could think of.

How Do I Use Case When with Group By statement

I have made a query but it don't give me what i want :
SELECT Designation_projet, COUNT(*) AS [Nb Demande], CASE WHEN Validation = 0 THEN COUNT(*) END AS Validée, CASE WHEN Validation = 1 THEN COUNT(*)
END AS NonValidée, CASE WHEN Commandé = 0 THEN COUNT(*) END AS NonCommandé,
CASE WHEN Commandé <> 0 THEN COUNT(*) END AS Commandé, SUM(TotalHT) AS TotalHT
FROM V_DemandeAchat
GROUP BY Designation_projet,Commandé,Validation
Please help me to achieve my gool.
Thanks in advance
You can do this using condition aggregation. That means that the CASE expression is the argument to SUM() -- it goes "inside" not "outside":
SELECT Designation_projet, COUNT(*) AS [Nb Demande],
SUM(CASE WHEN Validation = 0 THEN 1 ELSE 0 END) as Validée,
SUM(CASE WHEN Validation = 1 THEN 1 ELSE 0 END) as NonValidée,
SUM(CASE WHEN Commandé = 0 THEN 1 ELSE 0 END) AS NonCommandé,
SUM(CASE WHEN Commandé <> 0 THEN 1 ELSE 0 END) END AS Commandé,
SUM(TotalHT) AS TotalHT
FROM V_DemandeAchat
GROUP BY Designation_projet;
If you want one row per Designation_projet, then that should be the only key in the GROUP BY.
Assuming Validation takes on only two values, you can simplify the first two aggregation expressions:
SELECT Designation_projet, COUNT(*) AS [Nb Demande],
SUM(1 - Validation) as Validée,
SUM(Validation = 1) as NonValidée,
SUM(CASE WHEN Commandé = 0 THEN 1 ELSE 0 END) AS NonCommandé,
SUM(CASE WHEN Commandé <> 0 THEN 1 ELSE 0 END) END AS Commandé,
SUM(TotalHT) AS TotalHT
FROM V_DemandeAchat
GROUP BY Designation_projet;
You may be able to simplify the Commandé expressions as well.
Try this
SELECT Designation_projet, COUNT(*) AS [Nb Demande],sum(CASE WHEN Validation = 1 THEN 1 else 0 END AS Validée,sum( CASE WHEN Validation = 1 THEN 1 else 0
END AS NonValidée, sum(CASE WHEN NonCommandé <> 1 THEN 1 else 0 END AS NonCommandé,
sum(CASE WHEN Commandé <> 1 THEN 1 else 0 END AS Commandé, SUM(TotalHT) AS TotalHT
FROM V_DemandeAchat
GROUP BY Designation_projet

Counting specific cells in SQL Server

I have a table like this:
The RP Type column specifies the type of rate plan which can be (low, high, normal)
I want to create a view in which I can see number of each subscribers' which can be high, normal, low.
It should be like this I guess:
Create view t as
select
SubID,
Count(something) as NumeOfHIGH,
Count(Something) as NumOfLOW,
Count(Something) as NumOfNormal
Group by SubID
I might be wrong..Thank you
You can form your query in the following way:
SELECT SubID,
SUM (
CASE
WHEN RP_Type='High' THEN 1
ELSE 0 END
) AS NumOfHigh,
SUM (
CASE
WHEN RP_Type='Low' THEN 1
ELSE 0 END
) AS NumOfLow,
SUM (
CASE
WHEN RP_Type='Normal' THEN 1
ELSE 0 END
) AS NumOfNormal
FROM
<table_name>
Group by SubID
If there are multiple RP_Type in each of High, Low and Normal Category, you can include each type with WHEN in respective category.
For more information and reference: Conditional Processing using CASE
i tried this :
select SubscriberID
,COUNT(*) AS NumOfPlans
,SUM([SP active days]) as ActiveDays
,SUM(Case when [RP Type]='low' then 1 else 0 end ) as #LowPlan
,SUM(Case when [RP Type]='high' then 1 else 0 end ) as #NormalPlan
,SUM(Case when [RP Type]='high' then 1 else 0 end ) as #HighPlan
,SUM(Case when [RP Type]='promotion' then 1 else 0 end ) as #PromotionsPlan
,SUM(Case when [RP Type]='portal' then 1 else 0 end ) as #PortablePlan
,SUM(Case when [RP Type]='newyear' then 1 else 0 end ) as #NewYearPlan
,SUM(Case when [RP Type]='hamaval1' then 1 else 0 end ) as #HamrahAval1Plan
,SUM(Case when [RP Type]='hamaval2' then 1 else 0 end ) as #HamrahAval2Plan
,SUM(Case when [RP Type]='samsung' then 1 else 0 end ) as #SamsungPlan
,SUM(Case when [RP Type]='DEMO' then 1 else 0 end ) as #DemoPlan
,SUM(Case when [RP Type]IS null then 1 else 0 end ) as #NuLL
,SUM([Extra Quota]) as SumGIG
from [Cus Consumption].[dbo].CustData
where [Expiry Date]<= '2014 - 01 - 15'
group by [SubscriberID]
The ironic thing is that i does not return a correct answer..I don't know why #Rohit Aggrawal
is this helpful?
Create view t as
select From [tableName]
[Rp Type],count(*) as NumberOfSubscribers
Group by [Rp Type]
This gives you Number of subscribers in each type, and type
Hope this helpful

SQL group join table

Hi I want to display out the record in the format as below. How to I display the format as below ?
Branch Total Payment Total Discount Total Net Payment
A 10,000 2,000 8,000
B 29,190 1,540 27,656
Here are my query for the above. Please help me. Thanks.
SELECT TranID, ProjCode,
CASE WHEN IsActive='N' THEN 'Cancellation' ELSE PaymentType END As PaymentType,
CASE WHEN PaymentType='Withdrawal' THEN 0 ELSE (CASE WHEN IsActive='N' THEN 0 ELSE Sale END) END As Sale ,
CASE WHEN PaymentType='Withdrawal' THEN 0 ELSE (CASE WHEN IsActive='N' THEN 0 ELSE Sale_Before_CutOff END) END As Sale_Before_CutOff ,
CASE WHEN PaymentType='Withdrawal' THEN 0 ELSE (CASE WHEN IsActive='N' THEN 0 ELSE Net END) END As Net ,
CASE WHEN PaymentType='Withdrawal' THEN 0 ELSE (CASE WHEN IsActive='N' THEN 0 ELSE Net_Before_CutOff END) END As Net_Before_CutOff ,
CASE WHEN PaymentType='Withdrawal' THEN Net ELSE 0 END As Withdrawal,
CASE WHEN PaymentType='Withdrawal' THEN Net_Before_CutOff ELSE 0 END As Withdrawal_Before_CutOff,
CASE WHEN IsActive='N' THEN Net ELSE 0 END As Cancellation,
CASE WHEN IsActive='N' THEN Net_Before_CutOff ELSE 0 END As Cancellation_Before_CutOff,
CASE WHEN IsActive='N' THEN 0 ELSE Discount END As Discount,
CASE WHEN IsActive='N' THEN 0 ELSE Discount_Before_CutOff END As Discount_Before_CutOff, AdditionalCommission,AdditionalCommission_Before_CutOff, Remark, UserStamp, BusinessDay,
TranDate, BranchID, StaffCode, IsActive,Quantity
FROM
(SELECT c.INTERNAL_TRAN_NUM AS TranID, c.PROJECT_CODE AS ProjCode, c.PAYMENT_TYPE AS PaymentType,d.QUANTITY As Quantity,
CASE WHEN DATEPART(hh,c.TRAN_DATE) > DATEPART(hh, f.CUT_OFF_TIME) THEN c.TOTAL_PAYMENT ELSE 0 END AS Sale,
CASE WHEN DATEPART(hh, c.TRAN_DATE)<= DATEPART(hh, f.CUT_OFF_TIME) THEN c.TOTAL_PAYMENT ELSE 0 END AS Sale_Before_CutOff,
CASE WHEN DATEPART(hh, c.TRAN_DATE)> DATEPART(hh, f.CUT_OFF_TIME) THEN c.NET_PAYMENT ELSE 0 END AS Net,
CASE WHEN DATEPART(hh, c.TRAN_DATE) <= DATEPART(hh,f.CUT_OFF_TIME) THEN c.NET_PAYMENT ELSE 0 END AS Net_Before_CutOff,
CASE WHEN DATEPART(hh, c.TRAN_DATE) > DATEPART(hh,f.CUT_OFF_TIME) THEN c.DISCOUNT_AMOUNT ELSE 0 END AS Discount,
CASE WHEN DATEPART(hh, c.TRAN_DATE) <= DATEPART(hh,f.CUT_OFF_TIME) THEN c.DISCOUNT_AMOUNT ELSE 0 END AS Discount_Before_CutOff,
CASE WHEN DATEPART(hh, c.TRAN_DATE) > DATEPART(hh, f.CUT_OFF_TIME) THEN d.USER_DEF8 ELSE 0 END As AdditionalCommission,
CASE WHEN DATEPART(hh, c.TRAN_DATE) <= DATEPART(hh, f.CUT_OFF_TIME) THEN d.USER_DEF8 ELSE 0 END As AdditionalCommission_Before_CutOff,
c.REMARKS AS Remark, c.USER_STAMP AS UserStamp,CAST(DATEADD(hh, - DATEPART(hh, f.CUT_OFF_TIME), c.TRAN_DATE) AS DATE) AS BusinessDay,
c.TRAN_DATE AS TranDate, e.BRANCH_ID AS BranchID, d.STAFF_CODE AS StaffCode, c.ISACTIVE AS IsActive
FROM SC_TRAN_HEADER AS c
INNER JOIN SC_TRAN_DETAIL AS d ON d.INTERNAL_TRAN_NUM = c.INTERNAL_TRAN_NUM
INNER JOIN SC_BRANCH AS e ON c.BRANCH_NUM = e.INTERNAL_NUM
INNER JOIN SC_COMMISSION AS f ON f.BRANCH_NUM = c.BRANCH_NUM) AS TMP
The best that I can come up with, based on the information in your question, is:
with cte as (<your query here>)
select branchid, sum(sale) as payment, sum(discount) as discount,
sum(sale) - sum(discount)
from cte
group by branchid;
If this is not correct, then edit your question to provide more information to help resolve your question.
FIRST, I would try to simplify the readability of this query from all the case/when conditions. First, you do case/when in your preliminary query on repeated tests to get before and after cut-off period, then others you do based on withdrawal or NOT withdrawal and yet again for Active vs Not Active.
Simple math multipliers... consider your query segment... your inner query to get the values of Sale and Sale_Before_CutOff.
CASE WHEN DATEPART(hh,c.TRAN_DATE) > DATEPART(hh, f.CUT_OFF_TIME) THEN c.TOTAL_PAYMENT ELSE 0 END AS Sale,
CASE WHEN DATEPART(hh, c.TRAN_DATE)<= DATEPART(hh, f.CUT_OFF_TIME) THEN c.TOTAL_PAYMENT ELSE 0 END AS Sale_Before_CutOff,
Both test the date part for the cutoff time, and the answer can be Before, or After, never both. You do the same tests for Net, Net_Before_Cutoff, Withdrawal, Withdrawal_Before_Cutoff.
CASE WHEN PaymentType='Withdrawal' THEN 0 ELSE (CASE WHEN IsActive='N' THEN 0 ELSE Net END) END As Net ,
CASE WHEN PaymentType='Withdrawal' THEN 0 ELSE (CASE WHEN IsActive='N' THEN 0 ELSE Net_Before_CutOff END) END As Net_Before_CutOff ,
CASE WHEN PaymentType='Withdrawal' THEN Net ELSE 0 END As Withdrawal,
CASE WHEN PaymentType='Withdrawal' THEN Net_Before_CutOff ELSE 0 END As Withdrawal_Before_CutOff,
THEN, in your main part of the query, you are applying yet again a nested case/when(case/when)
CASE WHEN PaymentType='Withdrawal' THEN 0 ELSE (CASE WHEN IsActive='N' THEN 0 ELSE Sale END) END As Sale ,
CASE WHEN PaymentType='Withdrawal' THEN 0 ELSE (CASE WHEN IsActive='N' THEN 0 ELSE Sale_Before_CutOff END) END As Sale_Before_CutOff ,
CASE WHEN PaymentType='Withdrawal' THEN 0 ELSE (CASE WHEN IsActive='N' THEN 0 ELSE Net END) END As Net ,
CASE WHEN PaymentType='Withdrawal' THEN 0 ELSE (CASE WHEN IsActive='N' THEN 0 ELSE Net_Before_CutOff END) END As Net_Before_CutOff ,
CASE WHEN PaymentType='Withdrawal' THEN Net ELSE 0 END As Withdrawal,
CASE WHEN PaymentType='Withdrawal' THEN Net_Before_CutOff ELSE 0 END As Withdrawal_Before_CutOff,
What I would do, is from your subquery qualifying records, I would get the raw amount columns and 6 flags to act as multiplers.
SELECT ...
c.TOTAL_PAYMENT,
c.Net_Payment,
c.Discount_Amount,
CASE WHEN DATEPART(hh,c.TRAN_DATE) > DATEPART(hh, f.CUT_OFF_TIME)
THEN 1 ELSE 0 END as AfterMult,
CASE WHEN DATEPART(hh,c.TRAN_DATE) > DATEPART(hh, f.CUT_OFF_TIME)
THEN 0 ELSE 1 END as BeforeMult,
CASE WHEN c.PaymentType='Withdrawal'
THEN 1 ELSE 0 END as WithdrawalMult,
CASE WHEN c.PaymentType='Withdrawal'
THEN 0 ELSE 1 END as NotAWithdrawalMult,
CASE WHEN c.IsActive='N'
THEN 1 ELSE 0 END As NotActiveMult,
CASE WHEN c.IsActive='N'
THEN 0 ELSE 1 END As ActiveMult, ...
Notice, the same condition is applied to both parts, only the THEN/ELSE swaps the multiplier from a 1 to 0 respectively to what it should represent. So, for any given record, example result would be
Total_Payment Net_Payment Discount_Amount AfterMult BeforeMult WithdrawalMult NotAWithdrawalMult NotActiveMult ActiveMult
100 86 14 1 0 1 0 0 1
200 170 30 0 1 0 1 1 0
Now, simple thoughts... if you want to know how much total payments were before a cutoff and were NOT withdrawls, in your upper query it would be
Total_Payment * BeforeMult * NotAWithdrawal = TotalPayments_BeforeCutoff
vs payments AFTER cutoff
Total_Payment * AfterMult * NotAWithdrawal = TotalPayments_BeforeCutoff
Similar consideration for your Active vs Not active. Use that multiplier, no sense in doing nested cases when you already have determined its status when pulling the records. Lets take a look at your "Sale" column... The inner query getting the record is using the "Total_Payment" field
CASE WHEN DATEPART(hh,c.TRAN_DATE) > DATEPART(hh, f.CUT_OFF_TIME) THEN c.TOTAL_PAYMENT ELSE 0 END AS Sale,
then in the upper is a nested case/when.
CASE WHEN PaymentType='Withdrawal' THEN 0 ELSE (CASE WHEN IsActive='N' THEN 0 ELSE Sale END) END As Sale ,
The only time you care about the sale amount is when it is AFTER the cutoff, is NOT a withdrawal and when it IS Active, so just multiply those flags
Total_Payment * AfterMult * NotAWithdrawalMult * ActiveMult as Sale
Total_Payment * BeforeMult * NotAWithdrawalMult * ActiveMult as Sale_Before_Cutoff
Finally, you have so many other columns in the table being pulled and not used, why keep them. And for what you are trying to get the SUM() of, its going to be much easier to read it something like
SUM( Total_Payment * AfterMult * NotAWithdrawalMult * ActiveMult ) as TotalSale
SUM( Total_Payment * BeforeMult * NotAWithdrawalMult * ActiveMult ) as TotalSale_Before_Cutoff
All that being said, I offer you this... please confirm context, but should make sense from above. Also, note, the last 3 column I added were the final total you are probably looking for where the summation did not care as to before or after the time cutoff... just the fact it was a valid payment/discount/net, was Active, and on two of them was NOT a withdrawal... Seeing this, you would need to confirm its accuracy. The first 6 summations show based on respective after cutoff (no column name suffix) vs BEFORE the cutoff (column name HAS the suffix)
SELECT
PQ.Branch_Name, <-- CONFIRM COLUMN FROM PreQuery (PQ alias)
SUM( PQ.Total_Payment * PQ.AfterMult * PQ.NotAWithdrawalMult * PQ.ActiveMult ) as TotalSale,
SUM( PQ.Total_Payment * PQ.BeforeMult * PQ.NotAWithdrawalMult * PQ.ActiveMult ) as TotalSale_BeforeCutoff,
SUM( PQ.Discount_Amount * PQ.AfterMult * PQ.ActiveMult ) as TotalDiscount,
SUM( PQ.Discount_Amount * PQ.BeforeMult * PQ.ActiveMult ) as TotalDiscount_BeforeCutoff,
SUM( PQ.Net_Payment * PQ.AfterMult * PQ.NotAWithdrawalMult * PQ.ActiveMult ) as Net,
SUM( PQ.Net_Payment * PQ.BeforeMult * PQ.NotAWithdrawalMult * PQ.ActiveMult ) as Net_BeforeCutoff,
SUM( PQ.Total_Payment * PQ.NotAWithdrawalMult * PQ.ActiveMult ) as TotalSaleAll,
SUM( PQ.Discount_Amount * PQ.ActiveMult ) as TotalDiscountAll,
SUM( PQ.Net_Payment * PQ.NotAWithdrawalMult * PQ.ActiveMult ) as NetAll
from
( select
e.Branch_Name, <-- GUESSING ON THIS COLUMN FOR ACTUAL BRANCH
c.Total_Payment,
c.Net_Payment,
c.Discount_Amount,
CASE WHEN DATEPART(hh,c.TRAN_DATE) > DATEPART(hh, f.CUT_OFF_TIME)
THEN 1 ELSE 0 END as AfterMult,
CASE WHEN DATEPART(hh,c.TRAN_DATE) > DATEPART(hh, f.CUT_OFF_TIME)
THEN 0 ELSE 1 END as BeforeMult,
CASE WHEN c.PaymentType='Withdrawal'
THEN 1 ELSE 0 END as WithdrawalMult,
CASE WHEN c.PaymentType='Withdrawal'
THEN 0 ELSE 1 END as NotAWithdrawalMult,
CASE WHEN c.IsActive='N'
THEN 1 ELSE 0 END As NotActiveMult,
CASE WHEN c.IsActive='N'
THEN 0 ELSE 1 END As ActiveMult
FROM
SC_TRAN_HEADER AS c
INNER JOIN SC_TRAN_DETAIL AS d
ON c.INTERNAL_TRAN_NUM = d.INTERNAL_TRAN_NUM
INNER JOIN SC_BRANCH AS e
ON c.BRANCH_NUM = e.INTERNAL_NUM
INNER JOIN SC_COMMISSION AS f
ON c.BRANCH_NUM = f.BRANCH_NUM ) AS PQ
group by
PQ.Branch_Name <-- AGAIN, confirm column name here