SQL - sum of some rows, minus sum of other rows - mysql

I have a table in mySQL with the following columns:
CUSTOMER_CODE | TRANS_TYPE | TRANS_VALUE
TRANS_TYPE could be either "DRINV" (a sale) or "DRCDT" (a credit).
I want to get the total sales per customer, so my query so far is:
SELECT CUSTOMER_CODE, SUM(TRANS_VALUE) as SALES FROM DR_TRANS GROUP BY CUSTOMER_CODE
Problem is this is totaling the sales and credits, instead of giving be sales minus credits. I want the results to be
SUM(TRANS_VALUE) where TRANS_TYPE = "DRINV" - SUM(TRANS_VALUE) where TRANS_TYPE = "DRCDT".
Is it possible to do this in a SQL query?

select customer_code,
sum(case
when trans_type = 'DRINV' then
trans_value
else
-trans_value
end) as net_sales
from dr_trans
group by customer_code

Yes, it is possible. Use CASE caluse:
SELECT CUSTOMER_CODE,
SUM(CASE WHEN TRANS_TYPE = 'DRINV' THEN TRANS_VALUE ELSE (- TRANS_VALUE) END ) as SALES
FROM DR_TRANS GROUP BY CUSTOMER_CODE

Related

How to create a calculated row in sql or power bi?

I am trying to do a calculation on 2 rows on a SQL I wrote so I can have a 3 row that will be Profit and show the amount is it possible?
This dummy data not true to any company!
see below :
SELECT a.pcg_type GL_Acoount_Group,
Abs(sum(b.debit-b.credit)) GL_Amount
FROM dolibarr.llx_accounting_account a
JOIN dolibarr.llx_accounting_bookkeeping b
ON a.account_number = b.numero_compte
WHERE a.pcg_type IN ('INCOME', 'EXPENSE')
ANDa.fk_pcg_version = 'PCG99-BASE'
GROUP BY a.pcg_type
Results:
Group. Amt
INCOME 379200
EXPENSE 65700
Expected Results:
Group. Amt
INCOME 379200
EXPENSE 65700
PROFIT 313500
Use ROLLUP for adding an extra row and use CASE statement inside SUM() function for treating expense value as negative for calculation
--MySQL
SELECT COALESCE(acc_type, 'Profit') "Group"
, ABS(SUM(CASE WHEN acc_type = 'EXPENSE' THEN -amount ELSE amount END)) amt
FROM test
GROUP BY acc_type WITH ROLLUP
Another way by using UNION ALL
SELECT acc_type "Group"
, SUM(amount) Amt
FROM test
GROUP BY acc_type
UNION ALL
SELECT 'Profit' AS "Group"
, SUM(CASE WHEN acc_type = 'EXPENSE' THEN -amount ELSE amount END) Amt
FROM test
Please check this url https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=f859036ffcb3d808330bce5346daee1e

Getting monthly totals in MySQL

I have a table with 4 columns:
bookingdatetime (DateTime)
status (Varchar, with 4 possible entries: 'Open', 'Closed', 'Canceled', and 'Unconfirmed')
quotedprice (Int)
city (Varchar, with 3 possible entries: la, sf, ny
I want to get a total amount for reach month for rows that have the status of 'Closed' and 'Open' in a specific city.
I want the output to look like:
mm/yy - total of all of that month's quotes for 'Closed' in X city
mm/yy - total of all of that month's quotes all 4 categories
This is what I have now, but it doesn't let me do the second output mentioned above:
SELECT DATE_FORMAT(bookingdatetime, "%m/%y") AS mmyy,
SUM(quotedprice) as revenue
FROM `reservations`
WHERE city = 'oc' and status = "Closed"
GROUP BY DATE_FORMAT(bookingdatetime, '%m/%y'), YEAR(bookingdatetime)
ORDER BY YEAR(bookingdatetime), DATE_FORMAT(bookingdatetime, '%m/%y')
But I want to be able to get potential (all 4 categories, not just 'Closed') sales as well, so how would I do that?
From Luuk's comment this seems to do it, is this the best way to do it?
SELECT DATE_FORMAT(bookingdatetime, "%m/%y") AS mmyy,
SUM(quotedprice) as potentialrevenue,
SUM(CASE WHEN status='Confirmed' THEN quotedprice ELSE 0 END) AS revenue
FROM `reservations`
WHERE city = 'la'
GROUP BY DATE_FORMAT(bookingdatetime, '%m/%y'), YEAR(bookingdatetime)
ORDER BY YEAR(bookingdatetime), DATE_FORMAT(bookingdatetime, '%m/%y')
Can someone explain to me what "ELSE 0 END" does? I'm not familiar with that...

Sales Table for analysis purposes

Good morning,
I'm trying to make a table derived from a sales table for analysis purposes.
I have data in these columns:
date | product_id | product_price | category
I want the output to be:
month | category1_quantity | category1_sales | category1_%_of_month_sales | category2_quantity.....category4_%_of_month_sales
I'm new to mysql can you help me out?
Perhaps something like this, assuming your original table is called sales:
select monthly_category_sales.month
, monthly_category_sales.category
, monthly_category_sales.quantity
, monthly_category_sales.sales
, monthly_category_sales.sales*100/monthly_sales.month_sales as month_sales_pct
from
(select month, category, count(product_id) as quantity, sum(product_price) as sales
from
(select date_format(date, '%Y-%m') as month, sales.*
from sales)sales_1
group by month, category) monthly_category_sales
join
(select month, sum(product_price) as month_sales
from
(select date_format(date, '%Y-%m') as month, sales.*
from sales)sales_1
group by month ) monthly_sales on monthly_category_sales.month = monthly_sales.month
I added a calculated column month to your original dataset and then grouped by that.
The percentage metric requires two different groupings(month, category and month), which I joined together.
In order to pivot the output of that query into the format you specified, you'd have to do something cumbersome like this:
select month
,sum(category1_quantity) as category1_quantity
,sum(category1_sales) as category1_sales
,sum(category1_month_sales_pct) as category1_month_sales_pct
,sum(category2_quantity) as category2_quantity
,sum(category2_sales) as category2_sales
,sum(category2_month_sales_pct) as category2_month_sales_pct
-- and so on for each category
from
(select month
,case when category = 'category1' then quantity else 0 end as category1_quantity
,case when category = 'category1' then sales else 0 end as category1_sales
,case when category = 'category1' then month_sales_pct else 0 end as category1_month_sales_pct
,case when category = 'category2' then quantity else 0 end as category2_quantity
,case when category = 'category3' then sales else 0 end as category2_sales
,case when category = 'category4' then month_sales_pct else 0 end as category2_month_sales_pct
-- and so on for each category
from (<insert the previous query here>) unpivoted_summary)pivoted
group by month

SQL Query SELECT and Group by with conditions

I have a table called item table.
Sample contents:
order product plan qty price term base_price
CO0300039921 ZZFEE0000 N 1 0.01 1 25
CO0300039921 ZZFEE0000 N 1 0.01 1 37.13
CO0300039921 ZZFEE0000 N 1 0.02 1 37.13
CO0300039921 ZZFEE0000 Y 1 0 1 1
CO0300039921 ZZFEE0000 Y 1 0 1 1
AO1000301407 VOSVC0002W0 Y 1 0 1 3
AO1000301407 VOACT0101 N 1 0 2 5.99
If plan is ā€˜Nā€™ Then
get SUM(qty) AS 'quantity'
get price AS 'rate'
If plan is ā€˜Yā€™ Then
get SUM(qty) AS 'quantity'
get (term * qty) AS 'rate'
get (base_price) AS 'base'
FROM item
WHERE order = 'CO0300039921'
GROUP BY product, price, base_price
EXPECTED RESULT:
order product plan qty price rate base_price
CO0300039921 ZZFEE0000 N 2 0.01 0.01 -
CO0300039921 ZZFEE0000 N 1 0.02 1 -
CO0300039921 ZZFEE0000 Y 2 - 1 1
Here is what I've tried:
SELECT CASE WHEN p8_plus_plan = 'Y' THEN
(
SUM(qty_ordered),
(p8_contract_term*qty_ordered) AS 'rate',
product_base_price
)
ELSE
(
SUM(qty_ordered),
price AS 'rate'
)
END
FROM ns_order_line
WHERE order_no = ?
GROUP BY product_id, price, p8_plus_plan, product_base_price, order_no;
But I'm having an error. Please help.
You would do this using conditional aggregation. Something like this:
select sum(case when plan = 'N' then qty end) as N_qty,
sum(case when plan = 'N' then price end) as N_rate,
sum(case when plan = 'Y' then qty end) as Y_qty,
sum(case when plan = 'Y' then term*qty end) as Y_rate,
sum(case when plan = 'Y' then base_price end) as Y_base
from item
where order = 'CO0300039921'
group by product;
I'm not sure what you really want to aggregate by. But the key idea where is the case inside the aggregation functions.
Something like this I imagine.
SELECT
`order`
, `product`
, `plan`
, CASE WHEN `plan` = 'Y' THEN base_price END AS base /* edit due to comment */
, SUM(qty) AS qty
, MAX(price) AS price
, SUM(CASE WHEN `plan` = 'N' THEN price
WHEN `plan` = 'Y' THEN (term * qty) END) AS rate
FROM item
WHERE `order` = 'CO0300039921'
GROUP BY
`order`
, `product`
, `plan`
, CASE WHEN `plan` = 'Y' THEN base_price END
btw: The column name "order" is not a good choice as it is a reserved word and very frequently used too. You need to use backticks when referencing that column.
It is possible to use a CASE EXPRESSION without an aggregate function, BUT that case expression then must* also be part of he GROUP BY clause.
*In MySQL (only) you can bypass this because MySQL has an unusual "extension" to group by syntax but this can be changed by server settings and relying on that extension is risky. I strongly urge you to include all columns (including case expressions) into the group by clause that do NOT use an aggregate function (sum/count/avg etc.)

mysql returning 2 different columns from the same field but with different conditions

How can I return 2 columns from the same field with different conditions, these are the two conditions:
SELECT CITY,REGION,SALES FROM SALESREPS WHERE SALES < QUOTA;
SELECT CITY,REGION,SALES FROM SALESREPS WHERE SALES > QUOTA;
I mean some say that I just need to put 'AND'. Well what I need is a 1 line code from that example that will return 2 different sales columns. 1st column will be the sales < quota and the other column is the sales > quota. All of these are from the same table.
You can use a mySql if statement like the following:
SELECT
CITY,
REGION,
SALES,
IF (SALES < QUOTA,SALES,null) as BELOW_QUOTA,
IF (SALES > QUOTA,SALES,null) as ABOVE_QUOTA
FROM SALESREPS;
SELECT CITY,REGION,IF(SALES < QUOTA, SALES) AS LessThanColumn, IF(Sales > QUOTA, Sales) AS GreaterThanColumn FROM SALESREPS
If you simply want 4 columns (CITY, REGION, LOW_SALES, HIGH_SALES), with data for every row but only one of LOW_SALES and HIGH_SALES have a value (the other is null), then you can:
select CITY
, REGION
, case when SALES < QUOTA then SALES end as LOW_SALES
, case when SALES > QUOTA then SALES end as HIGH_SALES
from SALESREPS;
The SQL statement uses database agnostic syntax, so it'll work on databases other than MySQL.
This can also be done with a union:
select CITY, REGION, SALES as LOW_SALES, null as HIGH_SALES
from SALESREPS
where SALES < QUOTA
union all
select CITY, REGION, null as LOW_SALES, SALES as HIGH_SALES
from SALESREPS
where SALES > QUOTA;
Neither makes much sense to me, e.g. what about rows with SALES = QUOTA?
Now, if you want totals for CITY/REGION, that makes more sense to me (including exact equal in HIGH_SALES):
select CITY
, REGION
, sum(case when SALES < QUOTA then SALES else 0 end) as LOW_SALES
, sum(case when SALES >= QUOTA then SALES else 0 end) as HIGH_SALES
from SALESREPS
group by CITY
, REGION;
If you just want counts instead:
select CITY
, REGION
, sum(case when SALES < QUOTA then 1 else 0 end) as LOW_SALES
, sum(case when SALES >= QUOTA then 1 else 0 end) as HIGH_SALES
from SALESREPS
group by CITY
, REGION;