SQL Select Sum Query - sql

I need to complete the following but need to SUM on EntryValue where EntryType= 'C' - EntryType = 'D' but not sure where to include it.
SELECT SUM(EntryValue) AS EntryValue, Left(Warehouse,1) AS Branch
FROM GenJournalDetail INNER JOIN InvJournalCtl ON (GenJournalDetail.GlPeriod = InvJournalCtl.LedgPeriod) AND (GenJournalDetail.GlYear = InvJournalCtl.YearPostLedg) AND (GenJournalDetail.Journal = InvJournalCtl.GlJournal)
WHERE GenJournalDetail.GlCode = 'Z5207550' AND GlYear = '2011' AND GlPeriod = '10'
GROUP BY Left(InvJournalCtl.Warehouse,1)

Select it then group it;
SELECT SUM(EntryValue) AS EntryValueTotal, EntryType, Left(Warehouse,1) AS Branch
...
GROUP BY Left(InvJournalCtl.Warehouse,1), EntryType
Edit I didn't realise you wanted to deduct;
SELECT
SUM(CASE EntryType
WHEN 'C' THEN EntryValue
ELSE 0 END
)
-
SUM(CASE EntryType
WHEN 'D' THEN EntryValue
ELSE 0 END
) AS EntryValueTotal,
Left(Warehouse,1) AS Branch
FROM GenJournalDetail
INNER JOIN InvJournalCtl ON (GenJournalDetail.GlPeriod = InvJournalCtl.LedgPeriod) AND (GenJournalDetail.GlYear = InvJournalCtl.YearPostLedg) AND (GenJournalDetail.Journal = InvJournalCtl.GlJournal)
WHERE
GenJournalDetail.GlCode = 'Z5207550' AND GlYear = '2011' AND GlPeriod = '10'
GROUP BY Left(InvJournalCtl.Warehouse,1)

If you need to sum the column add it in the select and group:
SELECT SUM(EntryValue) AS TotEntry, ...
...
GROUP BY ...
you don't need to group an aggregated column; you need to filter query too?

Related

HAVING gives me "column...does not exist" but I see the column

This is a practice question from stratascratch and I'm literally stuck at the final HAVING statement.
Problem statement:
Find the total number of downloads for paying and non-paying users by date. Include only records where non-paying customers have more downloads than paying customers. The output should be sorted by earliest date first and contain 3 columns date, non-paying downloads, paying downloads.
There are three tables:
ms_user_dimension (user_id, acc_id)
ms_acc_dimension (acc_id, paying_customer)
ms_download_facts (date, user_id, downloads)
This is my code so far
SELECT date,
SUM(CASE WHEN paying_customer = 'no' THEN cnt END) AS no,
SUM(CASE WHEN paying_customer = 'yes' THEN cnt END) AS yes
FROM (
SELECT date, paying_customer, SUM(downloads) AS cnt
FROM ms_download_facts d
LEFT JOIN ms_user_dimension u ON d.user_id = u.user_id
LEFT JOIN ms_acc_dimension a ON u.acc_id = a.acc_id
GROUP BY 1, 2
ORDER BY 1, 2
) prePivot
GROUP BY date
HAVING no > yes;
If I remove the HAVING no > yes at the end, the code will run and I can see I have three columns: date, yes, and no. However, if I add the HAVING statement, I get the error "column "no" does not exist...LINE 13: HAVING no > yes"
Can't figure out for the sake of my life what's going on here. Please let me know if anyone figures out something. TIA!
You don't need a subquery for this:
SELECT d.date,
SUM(CASE WHEN a.paying_customer = 'no' THEN d.downloads END) AS no,
SUM(CASE WHEN a.paying_customer = 'yes' THEN d.downloads END) AS yes
FROM ms_download_facts d LEFT JOIN
ms_user_dimension u
ON d.user_id = u.user_id LEFT JOIN
ms_acc_dimension a
ON u.acc_id = a.acc_id
GROUP BY d.date
HAVING SUM(CASE WHEN a.paying_customer = 'no' THEN d.downloads END) > SUM(CASE WHEN a.paying_customer = 'yes' THEN d.downloads END);
You can simplify the HAVING clause to:
HAVING SUM(CASE WHEN a.paying_customer = 'no' THEN 1 ELSE -1 END) > 0
This version assumes that paying_customer only takes on the values 'yes' and 'no'.
You may be able to simplify the query further, depending on the database you are using.
It doesn't like aliases in the having statement. Replace no with:
SUM(CASE WHEN paying_customer = 'no' THEN cnt END)
and do the similar thing for yes.
SELECT date,
SUM(CASE WHEN paying_customer = 'no' THEN cnt END) AS no,
SUM(CASE WHEN paying_customer = 'yes' THEN cnt END) AS yes
FROM (
SELECT date, paying_customer, SUM(downloads) AS cnt
FROM ms_download_facts d
LEFT JOIN ms_user_dimension u ON d.user_id = u.user_id
LEFT JOIN ms_acc_dimension a ON u.acc_id = a.acc_id
GROUP BY 1, 2
ORDER BY 1, 2
) prePivot
GROUP BY date
HAVING SUM(CASE WHEN paying_customer = 'no' THEN cnt END) > SUM(CASE WHEN paying_customer = 'yes' THEN cnt END);

SQL query : transform rows to columns

Here's an example of my table.
I need to do a query that shows those IDs who have 0 as a fee on one of two months (11 or 12) or both.
So from the example, I need to show ID 1,3,4 but not 2, like on the screenshot below.
I tried the query below:
SELECT
t1.id, t1.month, t1.fee, t2.id, t2.month, t2.fee
FROM
table t1, table t2
WHERE t1.id = t2.id
AND t1.month = '11'
AND t2.month = '12'
AND (t1.fee = 0 OR t2.fee = 0);
But with this query, I only see ID 1,3 but not ID 4. I guess it's because of t1.id = t2.id but no idea how to do otherwise.
You can use conditional aggregation. In Postgres, this can make use of the filter syntax:
SELECT t.id,
11 as month,
MAX(t.fee) FILTER (WHERE t.month = 11) as fee_11,
12 as month,
MAX(t.fee) FILTER (WHERE t.month = 12) as fee_12
FROM t
GROUP BY t.id
HAVING MAX(t.fee) FILTER (WHERE t.month = 11) = 0 OR
MAX(t.fee) FILTER (WHERE t.month = 12) = 0;
Note: The two month columns are redundant.
you need conditional aggregation
select id,month,max(case when month=11 then fee end) fee11,
max(case when month=12 then fee end) as fee12
from (
select * from table t1
where t1.id in ( select id from table where fee=0)
) a group by id,month
Sql ansi compliant query
SELECT id,
MAX(CASE WHEN MONTH = 11 THEN MONTH ELSE NULL END) AS month11,
MAX(CASE WHEN MONTH = 11 THEN fee ELSE NULL END) AS fee11,
MAX(CASE WHEN MONTH = 12 THEN MONTH ELSE NULL END) AS month12,
MAX(CASE WHEN MONTH = 12 THEN fee ELSE NULL END ) AS fee12
FROM t
GROUP BY id
HAVING ( MAX(CASE WHEN MONTH = 11 THEN fee ELSE NULL END) = 0 OR MAX(CASE WHEN MONTH = 12 THEN fee ELSE NULL END ) = 0 )
ORDER BY id

How can I make two column from same table by two query

I've two query from same table but by two condition but how can I make two column for this two conditional count.
SELECT Count(*) FROM TBL_FT WHERE STATUS = 'X';
SELECT Count(*) FROM TBL_FT WHERE STATUS = 'Y' and
LOGDATE>trunc(sysdate);
You can use conditional aggregation:
SELECT
COUNT(CASE WHEN STATUS = 'X' THEN 1 END),
COUNT(CASE WHEN STATUS = 'Y' AND LOGDATE > trunc(sysdate) THEN 1 END)
FROM TBL_FT
You can also add a WHERE clause:
WHERE STATUS IN ('X', 'Y');
you can use something like this -
SELECT SUM(CASE
WHEN STATUS = 'X' THEN
1
ELSE
0
END) FIRST_VAL,
SUM(CASE
WHEN STATUS = 'Y'
AND LOGDATE > TRUNC(SYSDATE) THEN
1
ELSE
0
END) second_val
FROM TBL_FT;

Conditional statements within select for strings

at the moment I query my database to find all interactions within a certain date parameter. I also join that table with my InteractionAttendees then join it by TargetGroups table. InteractionAttendees tells me who attended the interaction, TargetGroup tells me about the person, if they are part of a target group such as aboriginal or francophone.
I'm having trouble setting my Aboriginal and Francophone columns. I want to set it to be true if there was any attendees that are in the TargetGroup Table.
select CONVERT(date, getdate()) as ActivityDate,
CASE when Type = 0 Then 'General'
when Type = 1 Then 'Activity'
else 'Task' End as Type,
CASE when Indepth = 0 Then 'False' else 'True' End as Indepth,
Subject,
Comments,
'false' as Aboriginal,
'false' as FrancoPhone,
'false' as Female,
'false' as Youth,
'false' as Other
from Sarnia.dbo.Interactions as X
full outer join sarnia.dbo.InteractionAttendees as Y on X.Id = Y.Interaction_Id
full outer join Sarnia.dbo.TargetGroups as Z on Y.Person_Id = Z.PersonId
where ActivityDate >= '2015-07-01' and ActivityDate <= '2015-09-30'
group by ActivityDate, Type, Indepth, Created, subject, comments
for example
Interaction Table
Id
1
Interaction Attendee Table
Id InteractionId PersonId
1 1 5
2 1 10
TargetGroups Table
Id PersonId TargetValue
1 5 Aboriginal
2 10 Francophone
So my resulted table would be
Activity Date Aboriginal Francophone
---- True True
May I ask how do I properly populate my target group columns.
You can update your query something like this: Pivot in the old fashioned way. Based on your previous questions I am assuming it is a sql server DB.
MAX(IIF(TargetValue = 'Aboriginal', 'True', 'False')) as Aboriginal,
MAX(IIF(TargetValue = 'FrancoPhone', 'True', 'False')) as FrancoPhone
If you have SQL Server 2008 or older you can use something like this
MAX(CASE WHEN TargetValue = 'Aboriginal' THEN 'True' ELSE 'False' END) as Aboriginal,
MAX(CASE WHEN TargetValue = 'FrancoPhone' THEN 'True' ELSE 'False' END) as FrancoPhone
Here is an example of how to do this with a CTE. Note, I added this to the example sql you gave, but that sql has many errors.
with igroup as
(
SELECT IID,
CASE WHEN ACOUNT > 0 THEN true ELSE false END AS Aboriginal,
CASE WHEN FCOUNT > 0 THEN true ELSE false END AS Francophone
FROM (
SELECT InteractionId as IID,
SUM(CASE WHEN TargetValue = 'Aboriginal' THEN 1 ELSE 0 END) as ACOUNT,
SUM(CASE WHEN TargetValue = 'FrancoPhone' THEN 1 ELSE 0 END) as FCOUNT
FROM sarnia.dbo.InteractionAttendees A
LEFT JOIN sarnia.dbo.TargetGroups as G on A.Person_Id = G.PersonId
GROUP BY InteractionId
) X
)
select CONVERT(date, getdate()) as ActivityDate,
CASE when Type = 0 Then 'General'
when Type = 1 Then 'Activity'
else 'Task' End as Type,
CASE when Indepth = 0 Then 'False' else 'True' End as Indepth,
Subject,
Comments,
igroup.Aboriginal,
igroup.FrancoPhone,
from Sarnia.dbo.Interactions as X
full outer join sarnia.dbo.InteractionAttendees as Y on X.Id = Y.Interaction_Id
join igroup on X.Id = igroup.IID
where ActivityDate >= '2015-07-01' and ActivityDate <= '2015-09-30'
group by ActivityDate, Type, Indepth, Created, subject, comments

SQL: Trying to understand IF/ELSE

SELECT CASE r.SourceId
WHEN '1' THEN 'ITUNES'
WHEN '2' THEN 'SFR'
WHEN '3' THEN 'ORANGE'
ELSE 'Others'
END as source
, CAST(SUM (r.SalesVolume) AS DECIMAL(14, 4) ) AS Volume
, CAST(SUM (r.SalesVolume * r.CustomerPrice) AS DECIMAL(14, 4) ) AS Value
from Rawdata r
INNER JOIN Product p
ON p.ProductId = r.ProductId
INNER JOIN Calendar c
ON r.DayId = c.DayId
WHERE c.WeekId BETWEEN (20145227) AND (20155230)
AND p.ContentFlavor IN ('SD', 'HD')
AND p.VODEST IN ('VOD','EST')
AND p.Distributor IN ('M6SND')
GROUP BY CASE r.SourceId
WHEN '1' THEN 'ITUNES'
WHEN '2' THEN 'SFR'
WHEN '3' THEN 'ORANGE'
ELSE 'Others'
END
The result of the above query is:
source Volume Value
ITUNES 48316.0000 506067.2600
This result is perfectly OK since my source table RawData doesnt contain any values for SourceId 2 or 3.
But what I basically want is the result to look like is:
source Volume Value
ITUNES 48316.0000 506067.2600
SFR 0 0
ORANGE 0 0
Others 0 0
If there is no value corresponding to any column parameter then I need it to be 0
I assume this could be done using IF/ELSE but not sure how?
with the help of a CTE this is a way to do it. (replace the first query with something more dynamic if you want)
with myChoices (choices)
as (
select
choices
from (
values
('ITUNES'),
('SFR'),
('ORANGE'),
('Others')
) [ ] (choices)
),
myQuery ([source],[Volume],[Value])
as (
SELECT CASE r.SourceId
WHEN '1' THEN 'ITUNES'
WHEN '2' THEN 'SFR'
WHEN '3' THEN 'ORANGE'
ELSE 'Others'
END as source
, CAST(SUM (r.SalesVolume) AS DECIMAL(14, 4) ) AS Volume
, CAST(SUM (r.SalesVolume * r.CustomerPrice) AS DECIMAL(14, 4) ) AS Value
from Rawdata r
INNER JOIN Product p
ON p.ProductId = r.ProductId
INNER JOIN Calendar c
ON r.DayId = c.DayId
WHERE c.WeekId BETWEEN (20145227) AND (20155230)
AND p.ContentFlavor IN ('SD', 'HD')
AND p.VODEST IN ('VOD','EST')
AND p.Distributor IN ('M6SND')
GROUP BY CASE r.SourceId
WHEN '1' THEN 'ITUNES'
WHEN '2' THEN 'SFR'
WHEN '3' THEN 'ORANGE'
ELSE 'Others'
END
)
select
c.choices,
ISNULL(q.Volume,0)Volume,
ISNULL(q.Value,0)Value
from myChoices c
left join myQuery q on
c.choices = q.[source]
Create an inline view called "Product_Inline_View", which is like
(select 1 as SourceId, 'ITUNES' as source_name
union all
select 2 as SourceId, 'SFR' as source_name
union all
select 3 as SourceId, 'ORANGE' as source_name
)
Right Join the Product_Inline_view with the Query you have, but without the CASE.
And then do the group by.