SQL Sub query with Grouping - mysql

SELECT customer_email, count(*) AS Order_Count,
MAX(created_at) as Last_Order_Date,
SUM(base_total_paid) AS Total_Lifetime_Sales,
SUM(base_total_offline_refunded+base_total_online_refunded) AS Refund_Total,
FROM mage_sales_order AS o
WHERE o.created_at > “2018-01-01”
AND
value NOT IN (Select customer_email
FROM mage_sales_order
WHERE WHERE o.created_at < “2018-10-01”)
Trying to remove orders that have been purchased in the last week, however gets stuck on the WHERE AND, And not sure! Thank you for any help!

I think you want to remove email id who ordered < '2018-01-01' so it would be below query
SELECT customer_email, count(*) AS Order_Count,
MAX(created_at) as Last_Order_Date,
SUM(base_total_paid) AS Total_Lifetime_Sales,
SUM(base_total_offline_refunded+base_total_online_refunded) AS Refund_Total
FROM mage_sales_order AS o
WHERE o.created_at > '2018-01-01' AND
customer_email NOT IN (Select customer_email
FROM mage_sales_order
WHERE o.created_at < '2018-10-01'
)
group by customer_email

You need a group by. The answer to your question is:
SELECT customer_email, count(*) AS Order_Count,
MAX(created_at) as Last_Order_Date,
SUM(base_total_paid) AS Total_Lifetime_Sales,
SUM(base_total_offline_refunded+base_total_online_refunded) AS Refund_Total
FROM mage_sales_order AS o
WHERE o.created_at < CURRENT_DATE - INTERVAL '1 week'
GROUP BY customer_email;
If you want to filter customers who haven't made a recent order:
SELECT customer_email, count(*) AS Order_Count,
MAX(created_at) as Last_Order_Date,
SUM(base_total_paid) AS Total_Lifetime_Sales,
SUM(base_total_offline_refunded+base_total_online_refunded) AS Refund_Total
FROM mage_sales_order AS o
GROUP BY customer_email
HAVING MAX(o.created_at) < CURRENT_DATE - INTERVAL '1 week'
Note that date/time functions differ by database, so the exact syntax might differ depending on what database you are using.

Related

MYSQL select sum by months including with null values

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;

How to SUM amounts across multiple tables with GROUP BY and ORDER BY?

I'm trying to reduce these queries to one so it's not three separate queries. Is there a better way to do this other than what I have? I'm also trying to sum all the totals together IE (invoiced_total + refund_total + credit_memo_total). The tables have no relation other than the customer, but I'm not looking to group by customer, just date. Any help would be much appreciated.
SELECT
SUM(qbi.amount) AS invoiced_total,
DATE_FORMAT(qbi.line_item_date, '%Y-%m-01') AS date
FROM
invoices as qbi
WHERE
qbi.`line_item_date` BETWEEN '2018-12-01' AND '2019-12-31'
GROUP BY
DATE_FORMAT(qbi.`line_item_date`, '%Y-%m-01')
ORDER BY
DATE_FORMAT(qbi.`line_item_date`, '%Y-%m-01');
SELECT
SUM(amount) AS refund_total,
DATE_FORMAT(refund_date, '%Y-%m-01') AS refund_date
FROM
refunds
WHERE
refund_date BETWEEN '2018-12-01' AND '2019-12-31'
GROUP BY
DATE_FORMAT(refund_date, '%Y-%m-01')
ORDER BY
DATE_FORMAT(refund_date, '%Y-%m-01');
SELECT
SUM(amount) AS credit_memo_total,
DATE_FORMAT(credit_memo_date, '%Y-%m-01') AS credit_memo_date
FROM
credit_memos
WHERE
credit_memo_date BETWEEN '2018-12-01' AND '2019-12-31'
GROUP BY
DATE_FORMAT(credit_memo_date, '%Y-%m-01')
ORDER BY
DATE_FORMAT(credit_memo_date, '%Y-%m-01');
If you want to join these queries you must also use a 4th query which will return all the distinct months from the 3 tables just in case there is a month missing in any of them.This is why you should use left joins for the tables:
SELECT d.date, i.invoiced_total, r.refund_total, c.credit_memo_total,
COALESCE(invoiced_total, 0) + COALESCE(refund_total, 0) + COALESCE(credit_memo_total, 0) AS total
FROM (
SELECT DATE_FORMAT(qbi.`line_item_date`, '%Y-%m-01') AS date FROM invoices UNION
SELECT DATE_FORMAT(refund_date, '%Y-%m-01') FROM refunds UNION
SELECT DATE_FORMAT(credit_memo_date, '%Y-%m-01') FROM credit_memos
) AS d
LEFT JOIN (
SELECT
SUM(qbi.amount) AS invoiced_total,
DATE_FORMAT(qbi.line_item_date, '%Y-%m-01') AS date
FROM
invoices as qbi
WHERE
qbi.`line_item_date` BETWEEN '2018-12-01' AND '2019-12-31'
GROUP BY
DATE_FORMAT(qbi.`line_item_date`, '%Y-%m-01')
) i ON i.date = d.date
LEFT JOIN (
SELECT
SUM(amount) AS refund_total,
DATE_FORMAT(refund_date, '%Y-%m-01') AS refund_date
FROM
refunds
WHERE
refund_date BETWEEN '2018-12-01' AND '2019-12-31'
GROUP BY
DATE_FORMAT(refund_date, '%Y-%m-01')
) r ON r.date = d.date
LEFT JOIN (
SELECT
SUM(amount) AS credit_memo_total,
DATE_FORMAT(credit_memo_date, '%Y-%m-01') AS credit_memo_date
FROM
credit_memos
WHERE
credit_memo_date BETWEEN '2018-12-01' AND '2019-12-31'
GROUP BY
DATE_FORMAT(credit_memo_date, '%Y-%m-01')
) c ON c.date = d.date
WHERE d.date BETWEEN '2018-12-01' AND '2019-12-31'
ORDER BY d.date
You would typically join the three queries. Assuming that all monthes are available in three tables, you could do:
SELECT
i.invoice_month my_month,
i.invoiced_total,
r.refund_total,
c.credit_total,
i.invoiced_total + r.refund_total + c.credit_total amount_total
FROM (
SELECT
SUM(amount) AS invoiced_total,
DATE_FORMAT(line_item_date, '%Y-%m-01') AS invoice_month
FROM invoices
WHERE line_item_date BETWEEN '2018-12-01' AND '2019-12-31'
GROUP BY invoice_month
) i
INNER JOIN (
SELECT
SUM(amount) AS refund_total,
DATE_FORMAT(refund_date, '%Y-%m-01') AS refund_month
FROM refunds
WHERE refund_date BETWEEN '2018-12-01' AND '2019-12-31'
GROUP BY refund_month
) r
INNER JOIN (
SELECT
SUM(amount) AS credit_total,
DATE_FORMAT(credit_memo_date, '%Y-%m-01') AS credit_month
FROM credit_memos
WHERE credit_memo_date BETWEEN '2018-12-01' AND '2019-12-31'
GROUP BY credit_memo_month
) c
ORDER BY i.invoice_month
Side note: in MySQL you can use column aliases in the GROUP BY clause (and in the ORDER BY clause): this helps shortening the query.

Query Help Between Date Range, but Not Recent

I'm know this can be written as a single SQL statement, but I just don't know how to do it. I have two separate queries. Ont that pulls all orders from a specific period of last year
SELECT * FROM `order` WHERE date_added BETWEEN '2014-10-01' AND '2014-11-01';
and one that pulls from the last month
SELECT * FROM `order` WHERE date_added BETWEEN DATE_SUB( now(), INTERVAL 1 MONTH) AND Now() ORDER BY date_added ASC
What I want to do is now join the two so that I only get the customer_id of orders that were placed inside of the date range last year (query 1), but haven't placed an order in the last month (query 2).
I know there is a way to set this up as a join, but my knowledge on sql join's is not very limited. Thanks for any help.
http://sqlfiddle.com/#!9/35ed0/1
SELECT * FROM `order`
WHERE date_added BETWEEN '2014-10-01' AND '2014-11-01'
AND customer_id NOT IN (
SELECT DISTINCT customer_id FROM `order`
WHERE date_added BETWEEN DATE_SUB( now(), INTERVAL 1 MONTH) AND Now())
UPDATE If you need only 1 records per customer_id, here is an example . It is not very best from performance perspective. But it returns only last (according to the date_added column) order per customer.
SELECT t.*,
if(#fltr=customer_id, 0, 1) fltr,
#fltr:=customer_id
FROM (SELECT *
FROM `order`
WHERE date_added BETWEEN '2014-10-01' AND '2014-11-01'
AND customer_id NOT IN (
SELECT DISTINCT customer_id FROM `order`
WHERE date_added BETWEEN DATE_SUB( now(), INTERVAL 1 MONTH) AND Now())
ORDER BY customer_id, date_added DESC
) t
HAVING (fltr=1);
I usually use a correlated not exists predicate for this as I feel that it corresponds well with the intent of the question:
SELECT *
FROM `order` o1
WHERE date_added BETWEEN '2014-10-01' AND '2014-11-01'
AND NOT EXISTS (
SELECT 1
FROM `order` o2
WHERE date_added BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()
AND o1.customer_id = o2.customer_id
);
I like to approach these questions using group by and having. You are looking for customer ids, so:
select o.customer_id
from orders o
group by o.customer_id
having sum(date_added BETWEEN '2014-10-01' AND '2014-11-01') > 0 and
sum(date_added BETWEEN DATE_SUB( now(), INTERVAL 1 MONTH) AND Now()) = 0;

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';

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.