I need assistance with a query using group by with rollup - mysql

I am trying to display the book order data showing the year of the order in the first column, the month in the second. Plus, display totals by month and by year and grand totals. Also, display messages "Yearly Total" and "Grand Total" instead of the nulls. The result is sorted by the year and month.
I keep receiving an error (Unknown column 'order_date' in 'field list') can anyone help me?
select coalesce(year(order_date), 'Grand Total') as Year
, case when year(order_date) is null then ' ' else coalesce(month(order_date), 'Year Total') end as
Month
, AmntDue
, NumberOfBooksPurch
from (
select year(order_date) as Year
, month(order_date) as Month
, sum(quantity * order_price) as AmntDue
, count(order_id) as NumberOfBooksPurch
from a_bkorders.order_headers
join a_bkorders.order_details using (order_id)
group by year(order_date), month(order_date), order_id with rollup
) tbl;

order_date is a value in the original table, but it's not being returned by the subquery so you can't reference it in the outer query. Use the aliases that the subquery returns:
select coalesce(Year, 'Grand Total') as Year
, case when Year is null then ' ' else coalesce(Month, 'Year Total') end as
Month
, AmntDue
, NumberOfBooksPurch
from (
select year(order_date) as Year
, month(order_date) as Month
, sum(quantity * order_price) as AmntDue
, count(order_id) as NumberOfBooksPurch
from a_bkorders.order_headers
join a_bkorders.order_details using (order_id)
group by Year, Month, order_id with rollup
) tbl;

Related

Avoid duplicate in query and make all the duplicated row blank

I have written query which should fetch ADJUSTMENT_AMOUNT and PAY_AMOUNT from the table ABC for different month, I have used subqueries to get this done, each ADJUSTMENT_AMOUNT and PAY_AMOUNT contains number, which is addition of multiple rows for the month by that each month I can see how much adjustment amount is available, same with PAY_AMOUNT.
But with the query that I have written, it is failing when ADJUSTMENT_AMOUNT is calculated using june,july,august,september month but PAY_AMOUNT is calculated using only september month, here in this condition PAY_AMOUNT is duplicated. I just want to avoid the duplicate values and make it blank, so basically only one row should be available for PAY_AMOUNT and rest 3 rows should be blank.
ADJ_MONTH ADJUSTMENT_AMOUNT CURRENCY PAY_MONTH PAY_AMOUNT
September 445 USD September 177.14
June 200 USD September 177.14
July 67 USD September 177.14
August 23 USD September 177.14
My query:
SELECT *
FROM
(SELECT TO_CHAR(CRE_DT, 'Month') AS ADJ_MONTH ,
SUM(ADJ_AMT) AS ADJUSTMENT_AMOUNT,
CURRENCY_CD
FROM ci_Adj
WHERE sa_id IN
(SELECT sa_id FROM ci_Sa WHERE acct_id=:F1
)
AND EXTRACT( YEAR FROM cre_dt) = EXTRACT(YEAR FROM sysdate)
GROUP BY TO_CHAR(CRE_DT, 'Month'),
CURRENCY_CD
ORDER BY TO_CHAR(CRE_DT, 'Month') DESC
),
(SELECT TO_CHAR(pae.cre_dttm, 'Month') AS PAY_MONTH ,
SUM(pa.PAY_AMT) AS PAY_AMOUNT
FROM ci_pay_event pae,
ci_pay pa
WHERE pa.acct_id =:F1
AND pa.pay_status_flg ='50'
AND pae.pay_event_id =pa.pay_event_id
AND EXTRACT( YEAR FROM pae.cre_dttm) = EXTRACT(YEAR FROM sysdate)
GROUP BY TO_CHAR(pae.cre_dttm, 'Month')
ORDER BY TO_CHAR(pae.cre_dttm, 'Month') DESC
)
Adding to points mentioned by (kfinity) and assuming the sub-queries are working fine. The below query will give all the data from the first sub-query and if it has any co-related data in the second query you get it, else the columns from query b will be null.
SELECT a.ADJ_MONTH, a.ADJUSTMENT_AMOUNT, a.CURRENCY_CD, b.PAY_MONTH, b.pay_amount
FROM
(SELECT TO_CHAR(CRE_DT, 'Month') AS ADJ_MONTH ,
SUM(ADJ_AMT) AS ADJUSTMENT_AMOUNT,
CURRENCY_CD
FROM ci_Adj
WHERE
sa_id IN (SELECT sa_id FROM ci_Sa WHERE acct_id=:F1)
AND EXTRACT( YEAR FROM cre_dt) = EXTRACT(YEAR FROM sysdate)
GROUP BY TO_CHAR(CRE_DT, 'Month'), CURRENCY_CD
ORDER BY TO_CHAR(CRE_DT, 'Month') DESC
)a,
(SELECT TO_CHAR(pae.cre_dttm, 'Month') AS PAY_MONTH ,
SUM(pa.PAY_AMT) AS PAY_AMOUNT
FROM ci_pay_event pae,
ci_pay pa
WHERE pa.acct_id =:F1
AND pa.pay_status_flg ='50'
AND pae.pay_event_id =pa.pay_event_id
AND EXTRACT( YEAR FROM pae.cre_dttm) = EXTRACT(YEAR FROM sysdate)
GROUP BY TO_CHAR(pae.cre_dttm, 'Month')
ORDER BY TO_CHAR(pae.cre_dttm, 'Month') DESC
)b
where a.ADJ_MONTH=b.pay_amount (+);

Group by not working as expected

Needs help with my SQL query
Query :
Select customer_id,
if (call_details ='International' , 'International Calls', 'National Calls'),
sum(minutes)
from call_minutes
where date between '$from' and '$to'
group by call_details
My Result is displaying as below
Please let me know why National Calls is not getting grouped. I wanted to find the sum of national calls and international calls
use below SQL:
select customer_id,
call_details,
sum(minutes) as minutes
from(
Select customer_id,
if (call_details ='International' , 'International Calls', 'National Calls') as call_details,
minutes
from call_minutes
where date between '$from' and '$to') x
group by customer_id,call_details
You don't need a subquery for this, because MySQL allows you to use column aliases in the group by (not all databases do). So:
Select customer_id,
(case when call_details = 'International'
then 'International Calls'
else 'National Calls'
end) as call_group,
sum(minutes)
from call_minutes
where date between '$from' and '$to'
group by customer_id, call_group;
Note: this assumes that you want separate rows for each customer. If not, remove customer_id from both the select and the group by:
Select (case when call_details = 'International'
then 'International Calls'
else 'National Calls'
end) as call_group,
sum(minutes)
from call_minutes
where date between '$from' and '$to'
group by call_group;
If you want a list of customer ids in each group, you can always add group_concat(customer_id).

Reformat sql to show rows where main query returns null

Consider this sql:
SELECT DATE_FORMAT( Orders.Timestamp, '%Y%m' ) AS Period,
SUM(Price) AS 'Ordersum per month and organisation', Orders.Organisation,
(
SELECT SUM(Amount) AS Returns
FROM Returns
WHERE DATE_FORMAT( Returns.Timestamp, '%Y%m' ) = Period
AND Returns.Organisation = Orders.Organisation
) Returns
FROM Orders
GROUP BY Period, Organisation
Whenever there are rows in the subquery that doesn't have an equivalent period in the main query, the row isn't displayed. The reason is that the query takes its period from the orders table, and when the period of the subquery doesn't match a period in the orders table, it simply doesn't match the query.
Is there a way to reformat this query to achieve what I want?
Sqlfiddle here http://sqlfiddle.com/#!9/ace715/1
You can use left and right join with UNION like this:
SELECT
ifnull(DATE_FORMAT( Orders.Timestamp,'%Y%m' ),DATE_FORMAT(Returns.Timestamp,'%Y%m' )) AS Period,
SUM(Price) AS 'Ordersum per month and organisation',
ifnull(Orders.Organisation,Returns.Organisation) as 'Organisation',
SUM(Amount) AS 'Returns'
FROM Orders
left JOIN Returns
on DATE_FORMAT( Orders.Timestamp,'%Y%m' ) = DATE_FORMAT(Returns.Timestamp, '%Y%m' )
and Returns.Organisation = Orders.Organisation
GROUP BY Period, Returns.Organisation, Orders.Organisation
union
select ifnull(DATE_FORMAT( Orders.Timestamp, '%Y%m' ),DATE_FORMAT(Returns.Timestamp,'%Y%m' )) AS Period,
SUM(Price) AS 'Ordersum per month and organisation',
ifnull(Orders.Organisation,Returns.Organisation),
SUM(Amount) AS 'Returns'
FROM Orders
right JOIN Returns
on DATE_FORMAT( Orders.Timestamp, '%Y%m' ) = DATE_FORMAT(Returns.Timestamp, '%Y%m' )
and Returns.Organisation = Orders.Organisation
GROUP BY Period, Returns.Organisation, Orders.Organisation

Select average monthly count, grouped by a field

I'm not sure if this has been asked before, as I don't know how to best phrase this question.
Given a query like:
SELECT DATE_FORMAT(i.created, '%Y-%m') as 'period',
COUNT(id) as 'total',
i.company_id
FROM invoice i
GROUP BY period, i.company_id
ORDER BY period DESC, total DESC
How can I return the average and/or mean count per month, grouped by company_id? It is important to only count those periods where there actually are any invoices.
If you want to exclude zero months then add HAVING condition and then select AVG() for each company using your query as a base:
SELECT company_id, AVG(total)
FROM
(SELECT DATE_FORMAT(i.created, '%Y-%m') as 'period',
COUNT(id) as 'total',
i.company_id
FROM invoice i
GROUP BY period, i.company_id
HAVING COUNT(id)>0
) as T1
GROUP BY company_id

MYSQL inline view query (top customer)

I try to make a query, so that I can see who is the top customer in a month (every month since begin till now).
Now I have the tables:
orders (orderID, orderdate, customerID, Netamount, tax, totalamount)
orderline (orderlineID, orderID, prodID, quantity, orderdate)
customer (firstname lastname zip creditcardtype etc.)
I think the other tables aren't necessarily here.
Of course there are customers who never bought a thing and customers who already bought plenty of times.
Now I used this query:
SELECT customerid, Sum(netamount)
FROM orders
GROUP BY customerid limit 1000000;
Now I see all customers who already bought sth. with the total amount they paid.
With the query
SELECT YEAR ( Orderdate ) Year ,
MONTHNAME ( Orderdate ) Month ,
COUNT(*) TotOrd ,
FROM orders
GROUP BY YEAR ( Orderdate ),
MONTH ( Orderdate );
I get a table where each row shows me the Year Month Total order (placed in that month).
Still I want just to see the Top Customer of a month.
I searched a lot in the internet still couldn't find that what I want (maybe I just googled wrong). I know that I need at least one inline view still no idea how to realize it.
Hope someone can help me out here.
You need to join back to the data to get the top customer. So, first calculate the maximum amount in each month, then join back to get the customer with that amount:
select my.year, my.month, myc.customerid, myc.totord
from (select year, month, max(totord) as maxtotord
from (SELECT YEAR ( Orderdate ) Year, MONTHNAME ( Orderdate ) Month, customerid, COUNT(*) TotOrd ,
FROM orders
GROUP BY YEAR ( Orderdate ), MONTH ( Orderdate ), customerid
) myc
group by year, month
) my join
(SELECT YEAR ( Orderdate ) Year, MONTHNAME ( Orderdate ) Month, customerid, COUNT(*) TotOrd ,
FROM orders
GROUP BY YEAR ( Orderdate ), MONTH ( Orderdate ), customerid, count(*) as totord
) myc
on my.year = myc.year and my.month = myc.month and my.maxtotord = myc.totord
Note that this is untested, so there might be a syntax error.
Also, this returns multiple customers if there are multiple customers with the max value.
Finally, this is much easier in almost any other database, because most databases now support the row_number() function.
It's a group-wise max problem but unfortunately MySQL doesn't support window functions or CTE so this can be messy.
SELECT s1.year,s1.month,s1.customerid,s1.totord FROM
(SELECT YEAR ( Orderdate ) Year ,
MONTHNAME ( Orderdate ) Month ,
customerid,
COUNT(*) TotOrd
FROM orders
GROUP BY YEAR ( Orderdate ),
MONTH ( Orderdate ),customerid) as s1
LEFT JOIN
(SELECT YEAR ( Orderdate ) Year ,
MONTHNAME ( Orderdate ) Month ,
customerid,
COUNT(*) TotOrd
FROM orders
GROUP BY YEAR ( Orderdate ),
MONTH ( Orderdate ),customerid) as s2
ON
s1.year=s2.year AND s1.month=s2.month AND s2.TorOrd>s1.TotOrd AND s1.customerid>s2.customerid
WHERE s2.customerid IS NULL;
In case of doubles it will return the customer with lower id.