MYSQL select sum by months including with null values - mysql

I'm working on a mysql request that make the sum of values by months including those with null values.
The request result send only the first line without making the sum operation.
SELECT SUM(IFNULL(t1.sub_total,0)) AS amount,
am.a_month AS date
FROM (
SELECT ifnull(vn.sub_total,0) as sub_total,
cast(DATE_FORMAT(order_date, '%M') as char) as mdate
FROM orders_new vn
WHERE order_status = 1
AND order_date BETWEEN '2022-01-01' AND '2022-12-31'
GROUP BY DATE_FORMAT(order_date, '%M')
) t1
RIGHT OUTER JOIN all_months am on t1.mdate = am.a_month
group by am.a_month
order by a_month_id asc;
result
below the source table

You don't need the GROUP BY clause in the subquery. Your query should be:
SELECT
SUM(IFNULL(t1.sub_total, 0)) AS amount,
am.a_month AS date
FROM
(SELECT
IFNULL(vn.sub_total, 0) AS sub_total,
CAST(DATE_FORMAT(order_date, '%M') AS char) AS mdate
FROM
orders_new vn
WHERE
order_status = 1
AND order_date BETWEEN '2022-01-01' AND '2022-12-31') t1
RIGHT OUTER JOIN
all_months am ON t1.mdate = am.a_month
GROUP BY
am.a_month
ORDER BY
a_month_id ASC;

Related

How to set default value from mysql join interval yearmonth

I have problem with my query. I have two tables and I want join them to get the results based on primary key on first table, but I missing 1 data from first table.
this my fiddle
as you can see, I missing "xx3" from month 1
I have tried to change left and right join but, the results stil same.
So as you can see I have to set coalesce(sum(b.sd_qty),0) as total, if no qty, set 0 as default.
You should cross join the table to the distinct dates also:
SELECT a.item_code,
COALESCE(SUM(b.sd_qty), 0) total,
DATE_FORMAT(d.sd_date, '%m-%Y') month_year
FROM item a
CROSS JOIN (
SELECT DISTINCT sd_date
FROM sales_details
WHERE sd_date >= '2020-04-01' - INTERVAL 3 MONTH AND sd_date < '2020-05-01'
) d
LEFT JOIN sales_details b
ON a.item_code = b.item_code AND b.sd_date = d.sd_date
GROUP BY month_year, a.item_code
ORDER BY month_year, a.item_code;
Or, for MySql 8.0+, with a recursive CTE that returns the starting dates of all the months that you want the results, which can be cross joined to the table:
WITH RECURSIVE dates AS (
SELECT '2020-04-01' - INTERVAL 3 MONTH AS sd_date
UNION ALL
SELECT sd_date + INTERVAL 1 MONTH
FROM dates
WHERE sd_date + INTERVAL 1 MONTH < '2020-05-01'
)
SELECT a.item_code,
COALESCE(SUM(b.sd_qty), 0) total,
DATE_FORMAT(d.sd_date, '%m-%Y') month_year
FROM item a CROSS JOIN dates d
LEFT JOIN sales_details b
ON a.item_code = b.item_code AND DATE_FORMAT(b.sd_date, '%m-%Y') = DATE_FORMAT(d.sd_date, '%m-%Y')
GROUP BY month_year, a.item_code
ORDER BY month_year, a.item_code;
See the demo.

How to add a value in a rollup row in MySQL?

I made a Query to get salaries and in the end a rollup to sum the result but i want to add a text 'Total'.
select which as 'Salaries', IFNULL(SUM(which1),0) as actual,IFNULL(SUM(which2),0) As estimated
from(select Type_expenses_table as which, sum(Amount_expenses_table) as which1, null as which2
From bacci.expenses_table
WHERE Date_expenses_table >= '2017-01-01'
AND Date_expenses_table < '2017-01-01' + INTERVAL 1 YEAR
AND Categories_table = 'salaries'
group by Type_expenses_table
union all
select estimated_type as which, null as which1, sum(estimated_amount) as which2
From bacci.estimated_expenses_table
Where estimated_year = '2017'
AND Categories = 'salaries'
group by estimated_type
) ae
group by which with rollup;
I want to put Total instead of null

MySQL Query NOT IN another Query

SELECT DISTINCT d.customer_id, d.date_added FROM `order` d
WHERE d.customer_id NOT IN (
SELECT DISTINCT i.customer_id
FROM `order` i
WHERE i.date_added > '2015-02-15 14:00:00'
)
ORDER BY d.date_added DESC;
The above query should return customer_id of customers who have not ordered after 15 Feb 2015 (I think). But very first record is
17168, 2015-08-16 17:36:00
What am I doing wrong?
This below query
SELECT DISTINCT i.customer_id,i.date_added FROM `order` i
WHERE i.date_added > '2015-02-15 14:00:00'
ORDER BY i.date_added ASC;
returns expected result i.e. list of customer ids for orders placed after 15 Feb
P.S. customer_id can not be NULL
Can customer_id or data_added be NULL? Try
SELECT DISTINCT d.customer_id,d.date_added
FROM order d
WHERE d.customer_id NOT IN
(SELECT DISTINCT i.customer_id FROM order i
WHERE i.date_added > '2015-02-15 14:00:00'
and customer_id IS NOT NULL
and i.date_added IS NOT NULL)
ORDER BY d.date_added DESC;
Edit
The way you wrote your query will get you customer_ids with an order before '2015-02-15 14:00:00'. But if the customer ordered something after this date they might be in the resultset.
Edit2
Why not write
SELECT DISTINCT customer_id, date_added
FROM order
WHERE date_added <= '2015-02-15 14:00:00'
ORDER BY date_added DESC;
I would use a correlated not exists query to exclude all customers that have any order after the specified date:
SELECT o1.customer_id, o1.date_added
FROM `order` o1
WHERE NOT EXISTS (
SELECT 1
FROM `order` o2
WHERE date_added > '2015-02-15 14:00:00'
AND o1.customer_id = o2.customer_id
)
ORDER BY o1.date_added DESC;
If you want customers who have not ordered since a certain date, I would just use group by and having:
SELECT o.customer_id, MAX(o.date_added) as most_recent
FROM `order` o
GROUP BY o.customer_id
HAVING MAX(o.date_added) <= '2015-02-15 14:00:00';

How can i get count of customers per day by unique and repeat customer for specific date?

I am trying to get a result from my order table to get list of counts of customers who 1st time ordered and repeat orders. Something like below.
Date 1st time time repeat order
2014-09-01 43 90
2014-09-02 3 45
2014-09-03 12 30
2014-09-04 32 0
2014-09-05 1 98
I am beginner in sql and i ma using mysql.
My table structure is like.
OrderNumber int
OrderDate datetime
CustomerID int
I have tried this query in mysql but it only gives me first timed ordered count.
SELECT DATE(OrderDate), COUNT(*)
FROM orders T JOIN (
SELECT MIN(OrderDate) as minDate, CustomerID
FROM orders
GROUP BY CustomerID) T2 ON T.OrderDate = T2.minDate AnD T.CustomerID = T2.CustomerID
GROUP BY DATE(T.OrderDate)
You can get the total orders per day by grouping on OrderDate:
SELECT OrderDate, COUNT(OrderNumber) AS total FROM orders GROUP BY OrderDate
And you can get the no. of first orders per day from the following query :
SELECT OrderDate, COUNT(q1.CustomerID) AS first FROM (SELECT CustomerID, min(OrderDate) AS OrderDate FROM orders GROUP BY CustomerID)q1 GROUP BY q1.OrderDate
Now join these two on OrderDate to get the distribution of first and repeated orders :
SELECT a.OrderDate, a.first, (b.total - a.first) AS repeated FROM
(SELECT OrderDate, COUNT(q1.CustomerID) AS first FROM (SELECT CustomerID, min(OrderDate) AS OrderDate FROM orders GROUP BY CustomerID)q1 GROUP BY q1.OrderDate)a
JOIN
(SELECT OrderDate, COUNT(OrderNumber) AS total FROM orders GROUP BY OrderDate)b
on(a.OrderDate = b.OrderDate)
A slightly complicated query but this should do:
First Time Users: Just Group by customerID to get the min orderdate and then group by on that date to get the number of new users on a particular day. Query would look like this:
select date(mdate) as day, COUNT(*) from (select customerid, min(orderdate) as mDate from orders GROUP BY CustomerID)q1 GROUP BY day;
Repeat Users: First filter out all such orderno which were placed as first orders and then do a group by orderdate to get repeat. Query would be :
select date(orderdate) day, COUNT(*) from (select * from orders where orderno not in (select orders.orderno from orders JOIN (select customerid, min(orderdate) as mdate from orders GROUP BY CustomerID)as order2 ON (orders.customerid = order2.customerid) and (orders.orderdate = order2.mdate))) as q1 GROUP BY day;
You can do a join on day for both these queries to get combined results in a way you mentioned. Let me know if doesn't work
EDIT:
This would be the complete query: Here I am doing a UNION on both left and right outer joins since it might happen that you come across where there are no new requests or no repeated requests. This would take care of both the scenarios.
select q2.*, q3.repeated from (select date(mdate) as day, COUNT(*) as first from (select customerid, min(orderdate) as mDate from orders GROUP BY CustomerID)q1 GROUP BY day) as q2 LEFT OUTER JOIN (select date(orderdate) day, COUNT(*) as repeated from (select * from orders where orderno not in (select orders.orderno from orders JOIN (select customerid, min(orderdate) as mdate from orders GROUP BY CustomerID)as order2 ON (orders.customerid = order2.customerid) and (orders.orderdate = order2.mdate))) as q1 GROUP BY day) as q3 on q2.day = q3.day UNION select q2.*, q3.repeated from (select date(mdate) as day, COUNT(*) as first from (select customerid, min(orderdate) as mDate from orders GROUP BY CustomerID)q1 GROUP BY day) as q2 RIGHT OUTER JOIN (select date(orderdate) day, COUNT(*) as repeated from (select * from orders where orderno not in (select orders.orderno from orders JOIN (select customerid, min(orderdate) as mdate from orders GROUP BY CustomerID)as order2 ON (orders.customerid = order2.customerid) and (orders.orderdate = order2.mdate))) as q1 GROUP BY day) as q3 on q2.day = q3.day
this is my answer but not sure is still can improve.
SELECT userID, COUNT(*) AS repeat_order_cnt FROM
(SELECT DATE(OrderDate) AS order_DT, userID, COUNT(*) AS no_of_order FROM order
AND YEAR(orderDate) = '2015'
AND MONTH(orderDate) = '01'
GROUP BY order_DT,userID) AS order2
GROUP BY userID
HAVING COUNT(*) > 1

Invalid operation: column "[column_name]" must appear in the GROUP BY clause or be used in an aggregate function;

I have read almost 10+ questions related to mine but no one worked in my case. As i have 3 tables in my DB and i am trying to calculate sale from them with respect to time (Yearly sale). where i need to GROUP BY my query by date_added. In MYSQL it worked fine and give me fine result but in redshift i am stuck.
MYSQL QUERY:
SELECT
MONTHNAME(o.date_added) AS MONTH,
YEAR(o.date_added) AS YEAR,
COUNT(o.order_id) AS orders,
FROM
order o
LEFT JOIN(
SELECT
op.order_id,
SUM(op.quantity) AS op_qty,
SUM(op.total) AS total,
SUM(op.cost) AS cost
FROM
order_product op
GROUP BY
op.order_id
) op
ON
op.order_id = o.order_id
LEFT JOIN(
SELECT
order_id,
SUM(IF(CODE = 'coupon', VALUE, 0)) AS coupon
FROM
order_total
WHERE
1
GROUP BY
order_id
) ot
ON
ot.order_id = o.order_id
WHERE
(
DATE(o.date_added) >= DATE_ADD(NOW(), INTERVAL - 24 MONTH) AND DATE(o.date_added) <=
DATE(NOW())) AND(o.order_status_id = '22' OR o.order_status_id = '23')
GROUP BY
MONTH(o.date_added),
YEAR(o.date_added)
ORDER BY
date_added ASC
LIMIT 0, 25
This MYSQL query working very fine but when i convert it to RedShift's POSTGRE format it gives me error of Invalid operation: column "o.date_added" must appear in the GROUP BY clause or be used in an aggregate function;
POSTGRES Query:
SELECT
EXTRACT(MONTH FROM o.date_added) AS month,
EXTRACT(YEAR FROM o.date_added) AS year,
COUNT(o.order_id) AS orders
FROM
orders o
LEFT JOIN
(
SELECT
op.order_id,
SUM(op.quantity) AS op_qty,
SUM(op.total) AS total,
SUM(op.cost) AS cost
FROM
order_product op
GROUP BY
op.order_id
) op
ON op.order_id = o.order_id
LEFT JOIN
(
SELECT
order_id,
SUM(CASE
WHEN CODE = 'coupon' THEN VALUE
ELSE 0
END) AS coupon
FROM
order_total
WHERE
1
GROUP BY
order_id
) ot
ON ot.order_id = o.order_id
WHERE
(
DATE(o.date_added) >= now() + interval '-24 month'
AND DATE(o.date_added) <= DATE(NOW())
)
AND (
o.order_status_id = '22'
OR o.order_status_id = '23'
)
GROUP BY
(EXTRACT(MONTH FROM o.date_added), EXTRACT(YEAR FROM o.date_added))
ORDER BY
o.date_added ASC LIMIT 25
Is there any syntax error in postgre query and also why i need to add o.date_added in GROUP BY
Your ORDER BY clause has o.date_added in it but your actual result set does not have it. The ORDER BY is done after the query is done.
You can use:
ORDER BY month asc, year asc LIMIT 25
Also, you can remove the extra parentheses from the GROUP BY:
GROUP BY EXTRACT(MONTH FROM o.date_added), EXTRACT(YEAR FROM o.date_added)
DB-Fiddle
See Redshift documentation for use of now() function. Use getdate() instead, as the now() seems to be deprecated.
A column in an ORDER BY clause in a query containing GROUP BY works as if it were mentioned in the SELECT clause.
You have
SELECT
MONTHNAME(o.date_added) AS MONTH,
YEAR(o.date_added) AS YEAR,
COUNT(o.order_id) AS orders,
FROM
order o
...
GROUP BY
MONTH(o.date_added),
YEAR(o.date_added)
ORDER BY
date_added ASC
LIMIT 0, 25
In MySQL this takes advantage of its notorious nonstandard handling of GROUP BY (read this. https://dev.mysql.com/doc/refman/8.0/en/group-by-handling.html)
What you want, to get a query that works in multiple DBMSs, is this instead.
ORDER BY
MONTH(o.date_added) ASC,
YEAR(o.date_added) ASC
Adding o.date_added to your GROUP BY clause is incorrect, because you are grouping not by the entire date, but by the month and year of the date.
I found the ERROR.I used SQL Workbench and get the Error about NOW() function that i was using in my POSTGRE query.
Simply, i juts replaced NOW() with CURRENT_DATE and things worked for me. Also, i get Error for LIMIT 0, 25 but in POSTGRE , they allow LIMIT 25 [OFFSET n] .
Now my query looks like:
SELECT
EXTRACT(MONTH FROM o.date_added) AS month,
EXTRACT(YEAR FROM o.date_added) AS year,
COUNT(o.order_id) AS orders
FROM
orders o
LEFT JOIN
(
SELECT
op.order_id,
SUM(op.quantity) AS op_qty,
SUM(op.total) AS total,
SUM(op.cost) AS cost
FROM
order_product op
GROUP BY
op.order_id
) op
ON op.order_id = o.order_id
LEFT JOIN
(
SELECT
order_id
FROM
order_total
WHERE
1
GROUP BY
order_id
) ot
ON ot.order_id = o.order_id
WHERE
(
DATE(o.date_added) >= CURRENT_DATE + interval '-24 month'
AND DATE(o.date_added) <= DATE(CURRENT_DATE)
)
GROUP BY EXTRACT(MONTH FROM o.date_added), EXTRACT(YEAR FROM o.date_added)
ORDER BY year ASC, month ASC LIMIT 25
NOTE: IF YOU ARE WORKING ON REDSHIFT. IT DO NOT BERIEF ABOUT ERROR. I RECOMMEND TO USE SQL WORKBENCH. IT EXPLAIN ABOUT ERROR.