Possible to do math inside of a sum statement? - sql

I'm by no means an expert in DB2 so apologies if this is a novice question. I am looking for a specific requirement. I am summing through a table based on a case statement but am wondering if we could subtract an amount if a field is present in the row.
SELECT CODE,
SUM(CASE SUBSTR(DATE,4,2)
WHEN '01' THEN AMT
END) as JanuaryTotal
FROM Table1
I'm looking to see if we can simply, if another field is present, if we can instead of summing it, simply subtract it from the total that is currently in place.
SELECT CODE,
SUM(CASE SUBSTR(DATE,4,2)
WHEN '01' THEN CASE WHEN TYPE = 'X'
THEN - AMT // some possible way to do this?
ELSE AMT
END) as JanuaryTotal
FROM Table1
Again, apologies. i know this code doesnt run but just giving a visual of something to see if it's possible to do.

SELECT CODE, SUM(
CASE
WHEN SUBSTR(DATE,4,2) = '01' THEN AMT
WHEN TYPE = 'X' THEN 0 - AMT
ELSE AMT
END
) as JanuaryTotal
FROM Table1

Sometimes it helps to indent. Also, it is not quite clear what to do if the sub-string is not 01 -- I'm guessing you don't want to add anything.
SELECT CODE,
SUM(CASE SUBSTR(DATE,4,2)
WHEN '01' THEN
CASE
WHEN TYPE = 'X' THEN -1 * AMT
ELSE AMT
END
ELSE 0 -- SUBSTR(DATE,4,2) is not '01'
END) as JanuaryTotal
FROM Table1

The simplest final query is to flatten out your conditions so they stand alone:
SELECT CODE, SUM(CASE
WHEN SUBSTR(DATE,4,2) AND TYPE = 'X' THEN 0-AMT
WHEN SUBSTR(DATE,4,2) AND THEN AMT END) as JanuaryTotal
FROM Table1
Note that there are two forms of CASE:
CASE <expression>
WHEN <value> THEN ...
WHEN <value> THEN ...
and
CASE
WHEN <condition> THEN ...
WHEN <condition> THEN ...
I switched your query from using the first form to the second form.

SELECT CODE, SUM(
CASE
WHEN SUBSTR(DATE,4,2) = '01' and TYPE = 'X' THEN -AMT
else AMT
END
) as JanuaryTotal
FROM Table1
group by CODE

Related

How to present a particular SQL queried row as columns in output

I need to present the attached output in PIC1 as the result in PIC2. The query used for generating PIC1 output in SQLDeveloper:
select subs_nm, as_of_date, run_status, (select max (tp.pr_vl)
from ual_mng.tqueue tq, ual_mng.tparams tp, ual_mng.tstatus ts
WHERE tq.tid = tp.tid AND tq.tid = ts.tid and tq.run_id = pcm.run_id and tp.pr_nm in ('TOT_RECORD_CNT')) as RECORD_COUNT
from UAL_MNG.PCM_SUBS_RUN_DTL_VW pcm where SUBS_NM='S_TS2_AQUA_A1_RLAP_DL' and AS_OF_DATE in ('2021-09-01','2021-09-02') order by run_start_dtm desc;
Appreciate all help.
If you don't need it to be dynamic (ie. it will only be two columns and you know which two months they are) you can do
select subs_nm,
max(case when as_of_date = '2021-09-01' then RECORD_COUNT else 0 end) as SEP1,
max(case when as_of_date = '2021-09-02' then RECORD_COUNT else 0 end) as SEP2,
from (
-- Your query
)
group by subs_nm
You can work out the percentage difference using the same expressions.
nb. I would always use an explicit date format mask. This might not run on a different machine / software. So use to_date('2021-09-01', 'yyyy-mm-dd')
Posting the query, which worked in the script :
select subs_nm, SEP1, SEP2, round((((SEP1-SEP2)/SEP1)*100),2) as DIFF_PER from ( select subs_nm,
max(case when as_of_date='2021-09-01' then RECORD_COUNT else '0' end) as SEP1,
max(case when as_of_date='2021-09-02' then RECORD_COUNT else '0' end) as SEP2 from (-- *Main Query*);

Using SUM SEC_TO_TIME in MariaDB

Reference from How to sum time using mysql
I want to SUM Field LogsFormatted.Late Every month with query :
SELECT
SUM(CASE
WHEN MONTH (LogsFormatted.DateIn) = 1
THEN SEC_TO_TIME( SUM( TIME_TO_SEC(LogsFormatted.Late)))
ELSE 0 END
) AS '1'
FROM
HrAttLogsFormatted AS LogsFormatted
But the result is
1111 - Invalid use of group function
Where is the problem with the query? resulting in an error output.. Thank you in advance
[EDIT-SOLVED] It's Solved with simply apply
Change format SUM at the beginning of the query
SEC_TO_TIME(SUM(
CASE WHEN MONTH(LogsFormatted.DateIn) = 1 THEN
TIME_TO_SEC(LogsFormatted.Late) END)
) AS '1'
You don't need to call the sum() so many times. You can also move the case condition to the WHERE clause:
SELECT SUM(TIME_TO_SEC(lf.Late))
FROM HrAttLogsFormatted lf
WHERE MONTH(lf.DateIn) = 1 ;
If you want conditional aggregation, then do:
SELECT SUM(CASE WHEN MONTH(lf.DateIn) = 1 THEN TIME_TO_SEC(lf.Late) END)
FROM HrAttLogsFormatted lf;

SQL server View - loop help (while loop)

I've been asked to produce a dataset using a view in SQL and have a number of products (eg 'a a','b b','c c') and I want to work out totals over 5 years (1,2,3,4,5) and output the totals as total_a_a_yr1, total_b_b_yr1....(see the below code)
Rather than writing out loads of lines of code is there a more efficient way of coding?
I thought about creating a procedure but I don't think you can use an EXEC within a view. I may be wrong. A while loop might be the way to go but I'm unsure about using declares in views.
Any help would be appreciated. Thanks
,sum(case when product = 'a a' and floor(datediff(dd, date1,date2)/365.25)<1
then amount_received else null end) as total_a_a_yr1
,sum(case when product = 'a a' and floor(datediff(dd, date1,date2)/365.25)<(2)
then amount_received else null end) as total_a_a_yr2
,sum(case when product = 'a a' and floor(datediff(dd, date1,date2)/365.25)<(3)
then amount_received else null end) as total_a_a_yr3
,sum(case when product = 'a a' and floor(datediff(dd, date1,date2)/365.25)<(4)
then amount_received else null end) as total_a_a_yr4
,sum(case when product = 'a a' and floor(datediff(dd, date1,date2/365.25)<(5)
then amount_received else null end) as total_a_a_yr5
First, the default value for a case statement is NULL so, "ELSE NULL" is not necessary. Second, this formula is probably not doing exactly what you think: floor(datediff(dd, date1,date2)/365.25). What I mean is, if you are operating under the assumption that there is a leap year every four years, you are incorrect. Leap years don't happen on years divisible by 100 UNLESS it can also be divided by 400. I could be misunderstanding what you're trying to do however.
You're correct, You can't use dynamic SQL (e.g. EXEC '<sql code>') in a view. There's very little you can't do with a tally table. Here's how you'd generate your code programatically using a tally table (I'm going to 1 to 100):
with yourExpression(ex) as
(
select ',sum(case when product = ''''a a'''' and floor(datediff(dd, date1,date2)/365.25)<
then amount_received else null end) as total_a_a_yr'
),
iTally(N) as
(
select top(100) cast(row_number() over (order by (select null)) as varchar(3))
from sys.all_columns
)
select stuff(ex,78,0,'('+N+')')+N
from iTally
cross join yourExpression;
You can copy/paste and execute the query as is; it will return:
,sum(case when product = ''a a'' and floor(datediff(dd, date1,date2)/365.25)<(1)
then amount_received else null end) as total_a_a_yr1
,sum(case when product = ''a a'' and floor(datediff(dd, date1,date2)/365.25)<(2)
then amount_received else null end) as total_a_a_yr2
,sum(case when product = ''a a'' and floor(datediff(dd, date1,date2)/365.25)<(3)....
--<truncated for brevity> ... as total_a_a_yr100

Sum by Distinct Values

I have the below code which brings though a sum of where a day 'GRLastDt' has complete or not complete however I hadn't accounted for duplicated Return IDs. Is there a way to return a sum by day for each Return ID?
For example day 24/5/15 may have 5 Lines to the day which have 'X' in Complete however 2 lines have duplicated return ids 'RtnId' and therefore the sum total would be 4 rather than 5 for 24/5/15.
SELECT
CONVERT(varchar(15), GRLastDt, 111) AS Date_,
SUM(CASE WHEN Complete = 'X' THEN 1 ELSE 0 END) AS Complete,
SUM(CASE WHEN Complete <> 'X' /*and RtnDt <>GRLastDt*/THEN 1 ELSE 0 END) AS Due
FROM [dbo].[vw_AN_Admin_VendorReturns]
WHERE (GRLastDt >= GETDATE() - 30)
GROUP BY CONVERT(varchar(15), GRLastDt, 111),GRLastDt
If I understand your problem right I think you can change this line:
SUM(CASE WHEN Complete = 'X' THEN 1 ELSE 0 END) AS Complete,
to this:
COUNT(DISTINCT CASE WHEN Complete = 'X' THEN RtnId END) AS Complete,
You probably want the same change for the Due calculation.

Merging data SQL Query

I have a query request where I have to show one customer activity for each web-site but it has to be only one row each, instead of one customer showing multiple times for each activity.
Following is the query I tried but brings lot more rows. please help me as how I can avoid duplicates and show only one customer by each row for each activity.
SELECT i.customer_id, i.SEGMENT AS Pistachio_segment,
(CASE when S.SUBSCRIPTION_TYPE = '5' then 'Y' else 'N' end ) PB_SUBS
(CASE WHEN S.SUBSCRIPTION_TYPE ='12' THEN 'Y' ELSE 'N' END) Daily_test,
(CASE when S.SUBSCRIPTION_TYPE ='8' then 'Y' else 'N' end) COOK_4_2
FROM IDEN_WITH_MAIL_ID i JOIN CUSTOMER_SUBSCRIPTION_FCT S
ON I.IDENTITY_ID = S.IDENTITY_ID and I.CUSTOMER_ID = S.CUSTOMER_ID
WHERE s.site_code ='PB' and s.subscription_end_date is null
Sounds like you need to group by customer_id and perform aggregations for the other columns you are selecting. For example:
sum(case when s.subscription_type = '5' then 1 else 0 end) as pb_subs_count
You could try one of two things:
Use a GROUP BY statement to combine all records with the same id, e.g.,
...
WHERE s.site_code ='PB' and s.subscription_end_date is null
GROUP BY i.customer_id
Use the DISTINCT command in your SELECT, e.g.,
SELECT DISTINCT i.customer_id, i.SEGMENT, ...
you could use a aggregation (SUM) on customer_id, but what do you expect to happen on the other fields? for example, if you have SUBSCRIPTION_TYPE 5 and 13 for the same customer (2 rows), which value do you want?
Perhaps you are looking for something like this:
SELECT i.customer_id, i.SEGMENT AS Pistachio_segment,
MAX(CASE when S.SUBSCRIPTION_TYPE = '5' then 'Y' else 'N' end ) PB_SUBS
MAX(CASE WHEN S.SUBSCRIPTION_TYPE ='12' THEN 'Y' ELSE 'N' END) Daily_test,
MAX(CASE when S.SUBSCRIPTION_TYPE ='8' then 'Y' else 'N' end) COOK_4_2
FROM IDEN_WITH_MAIL_ID i JOIN CUSTOMER_SUBSCRIPTION_FCT S
ON I.IDENTITY_ID = S.IDENTITY_ID and I.CUSTOMER_ID = S.CUSTOMER_ID
WHERE s.site_code ='PB' and s.subscription_end_date is null
GROUP BY i.customer_id, i.SEGMENT
I can't be sure, though, without knowing more about the tables involved.