MySQL: Get last 2 orders of users with conditions - mysql

I realized my first explanation was a bit off so I recollected my thoughts and rephrased my first question. I'd like to thank #Jitendra Sanghani and #StanislavL for providing the first answers.
Is it possible in MySQL to get the last 2 orders of users provided their last order made by them was on March 2016 and the 2nd to last was made on Dec 2015 (or any other older date)? This means if they made an order now but their previous one was January 2016 then they won't count (since we're looking at Dec 2015).
I currently have a sample orders table with fields id, fullname, and created.

you can write two queries and then have inner join on both like
select a.* from orders where orderdate > <> as a inner join (select b.orderdate from orders where orderdate <= <>)
in you case query will be
select a.* from orders where a.orderdate >= '2016-03-01' as a
inner join
(select b.orderdate from orders where orderdate <= '2015-12-31') as b
ON a. orderid = b.orderid
I think this should solve your problem.

select o.id,
sum(when case o.created>'2016-03-01' then 1 else 0 end) as current_count,
sum(when case o.created<='2016-03-01' then 1 else 0 end) as prev_count
from orders o
group by o.id
having current_count>0 and prev_count>0
corrected

Related

fetching values from database which are not from specific month

I am trying to fetch hotel id, hotel name and hotel type of hotels which has not taken any orders in the month of 'MAY 19' but i am not getting proper output what is wrong in my query?
select hotel_details.hotel_id,hotel_name,hotel_type
from hotel_details inner join orders on hotel_details.hotel_id=orders.hotel_id
where Month(order_date) between 1 and 4 or Month(order_date) between 6 and 12
order by hotel_id;
You can use the following, using NOT EXISTS to check if there is any order for the hotel in May 2019:
SELECT hotel_id, hotel_name, hotel_type
FROM hotel_details
WHERE NOT EXISTS (
SELECT 1
FROM orders
WHERE hotel_id = hotel_details.hotel_id
AND MONTH(order_date) = 5
AND YEAR(order_date) = 2019
)
The sub-query on EXISTS checks if the hotel_id is available in orders on May 2019. Using NOT in front of EXISTS filters all hotels which have no order in May 2019. The sub-query is connected to the outer part of the query with hotel_id = hotel_details.hotel_id.
Here's a standard, if somewhat old-fashioned approach...
(I've assumed a column name on the orders table, but you can change it to any non-nullable orders column, if it's wrong)
SELECT d.hotel_id
, d.hotel_name
, d.hotel_type
FROM hotel_details d
LEFT
JOIN orders o
ON d.hotel_id = o.hotel_id
AND d.order_date >= '2019-05-01'
AND d.order_date < '2019-06-01'
WHERE o.id IS NULL
ORDER
BY d.hotel_id;
For next time, see: Why should I provide an MCRE for what seems to me to be a very simple SQL query?
SELECT HOTEL_ID,HOTEL_NAME,HOTEL_TYPE FROM HOTEL_DETAILS
WHERE HOTEL_ID NOT IN
(SELECT HOTEL_ID FROM ORDERS
WHERE MONTH(ORDER_DATE) = 5)
ORDER BY HOTEL_ID ASC;
Here in the below sub query we are trying to obtain the HOTEL_ID(s) which have placed order in the month of May using the MONTH function. In outer query which receives a list of HOTEL_ID(s) which have an ordered in the month of may. Now the NOT IN condition omits the HOTEL_ID present in the list and displays the other HOTEL_ID which have not ordered in the month of May.
SELECT DISTINCT h.hotel_id,
h.hotel_name,
h.hotel_type
FROM hotel_details h
WHERE h.hotel_id NOT IN (SELECT od.hotel_id
FROM orders od
WHERE ( h.hotel_id = od.hotel_id
AND Month(order_date) = 05 )
GROUP BY h.hotel_id
ORDER BY h.hotel_id ASC);
Use Nested Queries:
SELECT hotel_id, hotel_name, hotel_type
FROM hotel_details
WHERE hotel_id NOT IN (
SELECT DISTINCT hotel_id
FROM orders
WHERE order_date BETWEEN '2019-05-01' AND '2019-05-31'
)
ORDER BY hotel_id;
Explanation :
In the Inner Query, we are selecting distinct hotel IDs from the order table with orders between May 1 and May 31.
Once we have list of hotel IDs, in the outer query we can display the required columns of the hotel table which have IDs not in the list.

Query to find the list of salesmen who had sales more than average sales for each year

I have a table (link of the table: https://docs.google.com/spreadsheets/d/11P_ElrtCXwE3NYAoP-auO7w-Et_zd6omn-v-zMdu8KA/edit?usp=sharing) from which I have to find the list of salesmen who had sales more than average sales for each year.
I have written a query below but it isn't working.
SELECT t1.salesman, t1.AVG(sale), t1.year
SUM(CASE WHEN t1.AVG(sale)>t2.AVG(sale) THEN 1 ELSE 0 END)>0
FROM Sales_temp as t1
LEFT JOIN
(SELECT t2.year, t2.AVG(sale)
FROM Sales_temp as t2
Group by t2.year)
ON t1.year = t2.year
Group by t1.salesman
Any help will be highly appreciable.
Try this:
SELECT salesman, sale, year
FROM Sales_temp
INNER JOIN
(
SELECT year ayear, AVG(sale) asale
FROM Sales_temp
GROUP BY year
) atbl
ON year = ayear AND sale > asale
ORDER BY year, salesman;
By giving your subquery columns alias names you can do without the alias names for the tables. This simplifies things a little. I changed your LEFT JOIN to INNER JOIN, as this will restrict your output to those records that can be joined, i. e. have sale>asale.
I also added the ORDER BY clause to improve the readability of the result.
Try this :
SELECT a.salesman, a.sale, a.year
FROM Sales_temp a
where a.sale > ( SELECT avg(b.sale)
FROM Sales_temp b
where b.year = a.year
group by b.year
)
For posterity's sake, if you are using MySQL version 8 or later, then we can use analytic functions here:
SELECT year, salesman, sale
FROM Sales_temp
WHERE sale > AVG(sale) OVER (PARTITION BY year);

SQL beginner practice problems

Given two tables, orders (order_id, date, $, customer_id) and customers (ID, name)
Here's my method but I'm not sure if it's working & I'd like to know if there's faster/better way of solving these problems:
1) find out number of customers who made at least one order on date 7/9/2018
Select count (distinct customer_id)
From
(
Select customer_id from orders a
Left join customer b
On a.customer_id = b.ID
Group by customer_id,date
Having date = 7/9/2018
) a
2) find out number of customers who did not make an order on 7/9/2018
Select count (customer_id) from customer where customer_id not in
(
Select customer_id from orders a
Left join customer b
On a.customer_id = b.ID
Group by customer_id,date
Having date = 7/9/2018
)
3) find the date with most sales between 7/1 and 7/30
select date, max($)
from (
Select sum($),date from orders a
Left join customer b
On a.customer_id = b.ID
Group by date
Having date between 7/1 and 7/30
)
Thanks,
For problem 1, a valid solution might look like this:
SELECT COUNT(DISTINCT customer_id) x
FROM orders
WHERE date = '2018-09-07'; -- or is that '2018-07-09' ??
For problem 2, a valid solution might look like this:
SELECT COUNT(*) x
FROM customer c
LEFT
JOIN orders o
ON o.customer_id = x.customer_id
AND o.date = '2018-07-09'
WHERE o.crder_id IS NULL;
Assuming there are no ties, a valid solution to problem 3 might look like this:
SELECT date
, COUNT(*) sales
FROM orders
WHERE date BETWEEN '2018-07-01' AND '2018-07-30'
GROUP
BY date
ORDER
BY sales DESC
LIMIT 1;
The default format for a date in MySQL is YYYY-MM-DD, although this can be customized. You have to put quotes around it, otherwise it's treated as an arithmetic expression.
And none of your queries need to join with the customer table. The customer ID is already in the orders table, and you're not returning any info about the customers (like the name or address), you're just counting them.
1) You don't need the subquery or grouping.
SELECT COUNT(DISTINCT customer_id)
FROM orders
WHERE date = '2018-07-09'
2) Again, you don't need GROUP BY in the subquery. There's also a better pattern than NOT IN to get the count of non-matching rows.
SELECT COUNT(*)
FROM customer AS c
LEFT JOIN order AS o on c.id = o.customer_id AND o.date = '2018-07-09'
WHERE o.id IS NULL
See Return row only if value doesn't exist for various patterns to do this.
3) You can't use MAX($) in the outer query because the inner query doesn't return a column with that name. But even if you fix that, it still won't work, because the date column won't necessarily come from the same row that has the maximum. See SQL select only rows with max value on a column for more explanation of this.
You don't need a subquery at all. Use a query that returns the total sales for each day, then use ORDER BY to get the highest one.
SELECT date, SUM($) AS total_sales
FROM orders
WHERE date BETWEEN '2018-07-01' AND '2017-07-30'
GROUP BY date
ORDER BY total_sales DESC
LIMIT 1
If "most sales" is supposed to mean "most number of sales", replace SUM($) with COUNT(*).

Sql query to add missing rows from another table

I have a table A (columns: id, year,month,amount) and table B( columns: id, year,month, amount=0).
Table A is the master table which have a same set of ids for each month for every year from 2011 to 2016.
In that some records are not present (like their is no record for 123456 id for 03 month and 2016 year and 468976 amountk), for that I want to add new record having id 123456, 03 in month and 2016 in year in table A and as it is a missing record amount will be 0.
The missing records are taken from table B which is having same set of ids from table A and for each id it is having every month for every year from 2011 to 2016, for each row amounts as 0.
Note:
1. In table A record s are not sorted and in table records are grouped by id, year and month.
2. If possible please make it normal sql queries instead of pl/sql. If not possible as I wanted please suggest your answer.
Thanks in advance........I hope you understsnd the problem statement.
You can generate the records using a cross join and some more logic:
select i.id, ym.year, ym.month
from (select distinct year, month from a) ym cross join
(select distinct id from b) i left join
a
on a.year = ym.year and a.month = ym.month and b.id = i.id
where a.id is null;
(I think I have the as and bs right. I'm not sure why two separate tables are mentioned in the question. It would seem that a is missing the records, so it is the only table needed. My best guess is that b is a subset of ids in a.)
Here is a version that does the insert:
insert into a(id, year, month)
select i.id, ym.year, ym.month
from (select distinct year, month from b) ym cross join
(select distinct id from b) i left join
b
on b.year = ym.year and b.month = ym.month and b.id = i.id
where b.id is null;

One-to-many query with subtoals and limits

Requirements: Select customers with 5 or more invoices totaling more than $3000 with transactions from Sept 2011 to current date.
DBMS: MySQL 5.6
Tables:
customers: customerID (...)
invoice: customerID,invoice_no,order_date,order_total (...)
I wrote several MySQL queries. The one that comes "closest" to working appears below. The problem with the results is twofold:
It looks at the total of all invoices per custopmer, not just those within the date range.
It pulls in some (but not all) records that are outside of the date range.
Here is the query:
#Customers with 5 or more invoices Totaling more than $3000 From Sept 2011 to current
SELECT distinct c2.customerID,c2.firstname,c2.lastname,c2.company,c2.address,c2.address2,c2.city,c2.state,c2.country,c2.phone,c2.email,SUM(c1.order_total)
FROM
customers c2 LEFT JOIN invoice c1
ON c2.customerID = c1.customerID
AND ((date(c1.order_date)) between '2011-09-01' and date(now()))
GROUP BY
c1.customerID
HAVING
COUNT(c1.invoice_no)>=7 and sum(c1.order_total) >=3000
Any help would be appreciated greatly.
Thanks.
This should do it:
select c.*, SUM(i.order_total) total, COUNT(*) order_count
FROM customers c
JOIN invoice i ON c.customerID = i.customerID
WHERE i.order_date >= '2011-09-01'
GROUP BY c.customerID
HAVING order_count >= 5 and total > 3000