SELECT DISTINCT(id_no), lastname,
(SELECT COUNT(purchasedate) num_of_purch
FROM sales JOIN Artist ON
sales.id = Artist.id_no
WHERE DATE_SUB(CURDATE(),INTERVAL 1
YEAR) <= purchasedate
) AS num_of_purch
FROM Artist
This query returns the all Artist's ID_no, and their last name and the total number of purchases, altho i want to specify which purchases were to which artist. Help in solving this would be greatly apprciated.
EDIT - DISTINCT(id_no) is redundant as it is a primary key.
This shows the number of sales for each artist_id:
SELECT artist.id_no, count(sales.id) as num_of_purch
FROM artist left join sales on sales.id = artist.id_no
WHERE DATE_SUB(CURDATE(), INTERVAL 1 YEAR) <= purchasedate
GROUP BY artist.id
To return also the last names, and all of the details:
SELECT art_tot.id_no, art_tot.lastname, art_tot.num_of_purch, sales.*
FROM (SELECT artist.id_no, artist.lastname, count(sales.id) as num_of_purch
FROM artist left join sales on sales.id = artist.id_no
WHERE DATE_SUB(CURDATE(), INTERVAL 1 YEAR) <= purchasedate
GOUP BY artist.id, artist.lastname) art_tot
left join sales on art_tot.id_no = sales.id
This should give you artist and number of purchases per artist
select a.id_no, a.lastname, count(s.purchasedate) num_of_purch
from artists a
join sales s on a.id_no = s.id
where date_sub(curdate(), interval 1 year) <= s.purchasedate
group by a.id_no, a.lastname
You should use a GROUP BY to get the count per artist.
And you should use an outer join to include artists who have no sales within the last year.
SELECT a.id_no, a.lastname, COUNT(s.purchasedate) AS num_of_purch
FROM Artist a
LEFT OUTER JOIN sales s ON s.id = a.id_no
AND s.purchasedate => CURDATE() - INTERVAL 1 YEAR
GROUP BY a.id_no;
PS: Using DISTINCT(id_no) is meaningless not only because id_no is already a unique key, but because DISTINCT always applies to all columns in the select list, even if you add parentheses to make it look like a function that applies only to one column.
Related
I am trying to identify shoppers who last placed an order on or before a specific date.
I want to do this so that I can identify stale accounts and unsubscribe them from mailings.
So far I have this query, but it seems to be retrieving accounts that have ordered more recently than the specified date - which is not what I want!
SELECT
s.id,s.first_name,s.last_name,s.email, latest_orders.last_order_date, au.verified, au.unh
FROM
(SELECT
shopper_id, MAX(order_date) AS last_order_date
FROM
order_list WHERE order_date <= ?
GROUP BY
shopper_id) AS latest_orders
INNER JOIN
shoppers s
ON
s.id = latest_orders.shopper_id
JOIN auth_users au ON au.shopper_id=s.id
WHERE s.mail_outs='Y' LIMIT 50
Use having:
SELECT shopper_id, MAX(order_date) AS last_order_date
FROM order_list
GROUP BY shopper_id
HAVING MAX(order_date) <= ?;
If you want all information about the shoppers, then join back to shoppers:
SELECT s.*, os.last_order_date
FROM shoppers s JOIN
(SELECT shopper_id, MAX(order_date) AS last_order_date
FROM order_list
GROUP BY shopper_id
HAVING MAX(order_date) <= ?
) os
ON os.shopper_id = s.id;
So I have a database like this:
product_table: (product_id, name),
date_table: (date_id, day, month, year),
sales_table: (sale_id, product_id, date_id, total_value)
I need to get the most sold product for every month that exists in the "date_table" with one query, the only way I was able to do was specifing the month and year in the query, but then i gotta do one query for each month which is not what I need.
Edit:
here is the query i have written:
SELECT p.name, d.month, d.year, SUM(s.total_value) as total
FROM sales_table s
INNER JOIN product_table p ON s.product_id = p.product_id
INNER JOIN date_table d ON s.date_id = d.date_id
WHERE d.month = "$month" AND d.year = "$year"
ORDER BY total DESC
LIMIT 1
As i said, i have to give the month and the year i want here, but i need the most sold product (with the use of sales value in sales_table not the row count of product table) for every month in just one query!
You can use row_number() with aggregation. Assuming that "most sold" refers to the count in the sales table:
select sd.*
from (select d.year, d.month, s.product_id, count(*) as cnt,
row_number() over (partition by d.year, d.month order by count(*) desc) as seqnum
from sales s join
dates d
on s.date_id = d.date_id
group by d.year, d.month
) sd
where seqnum = 1;
The following statement surprisingly works, but I'm not sure joining the same table 3 times is efficient. I had to disable ONLY_FULL_GROUP_BY in order for it to work.
There are 2 tables in play. One is the main table with Distributor information, the second is a table of purchases that contains the amount, date, and id of the associated Distributor in the main table (assoc).
There are 3 things I needed. Year to date sales, which SUMS the amount of a certain Distributor's sales from the current year. Last year sales, which does the same for the previous year. Then finally just get the latest purchase date and amount.
The user needs to be able to filter by these values (lys, ytd, etc...) so joining them as variables seems like the way to go. The DB size is about 7,000 records.
SELECT
d.*,
ytd_total,
lys_total,
last_amount,
last_purchase
FROM Distributor as d
LEFT JOIN (
SELECT
assoc, SUM(amount) ytd_total
FROM purchases
WHERE db = 1 AND purchase_date >= '{$year}-01-01'
GROUP BY assoc
) AS ytd
ON ytd.assoc = d.id
LEFT JOIN (
SELECT
assoc, SUM(amount) lys_total
FROM purchases
WHERE db = 1 AND purchase_date BETWEEN '{$lyear}-01-01' AND '{$lyear}-12-31'
GROUP BY assoc
) AS lys
ON lys.assoc = d.id
LEFT JOIN (
SELECT
assoc, amount last_amount, purchase_date last_purchase
FROM purchases
WHERE db = 1
GROUP BY assoc
) AS lst
ON lst.assoc = d.id
WHERE ........
You can do more work in each aggregation query. I think this is more whatyou want:
select d.*, pa.ytd_total, pa.lys_total, pa.last_purchase_date, p.amount
from distributor d left join
(select p.assoc,
sum(case when p.purchase_date >= '{$year}-01-01' then p.amount end) as ytd_total,
sum(case when p.purchase_date BETWEEN '{$lyear}-01-01' AND '{$lyear}-12-31' then p.amount end) as lys_total,
max(p.purchase_date) as last_purchase_date
from purchases p
where p.db = 1
group by p.assoc
) pa left join
purchases p
on pa.assoc = p.assoc and pa.last_purchase_date = p.purchase_date;
I try to obtain a list of all customers my company has not had any assignments for in the last year.
SELECT MAX(assignment_date), full_name
FROM assignments
CROSS JOIN customers
WHERE assignments.customer_id = customers.id
AND assignment_date < '2017-01-01' -- Dynamic value from backend
GROUP BY full_name
ORDER BY assignment_date DESC
This does not seem to work as intended however, since it only returns some customers we did have assignments for in that timeframe. How would I go about implementing such a feature?
Try this code:
SELECT MAX(assignment_date), full_name
FROM customers
where id not in (SELECT id FROM customers inner join assigments on customers.id = assignments.customer_id WHERE assignment_date > '2017-01-01' )
This will return all customers in your database and remove all of them who did have assigments in last year. You should get all customers without assigments before '2017-01-01' as a result
left join customers to assignments where assignments.customer_id IS NULL
and assignment_date greater than '2017-01-01' i.e.
SELECT MAX(assignment_date), full_name
FROM assignments
WHERE assignments.customer_id IN
(SELECT customers.id
FROM customers
LEFT JOIN assignments ON assignments.customer_id = customers.id
WHERE assignments.customer_id IS NULL
AND assignment_date > '2017-01-01')
GROUP BY full_name
ORDER BY assignment_date DESC
I would suggest left join, group by and having:
SELECT MAX(assignment_date), full_name
FROM customers c LEFT JOIN
assignments a
ON a.customer_id = c.id
GROUP BY c.full_name
HAVING MAX(a.assignment_date) < '2017-01-01' OR
MAX(a.assignment_date) IS NULL
ORDER BY MAX(assignment_date) DESC;
It seems you want to show all customers with their last assignment date, but you want to restrict that list to customers that had no assignment since 2017-01-01. This means the dates you will be showing will be null for those customers who had never had an assignment and a date before 2017-01-01 for the others.
So outer join the last dates to the customers and only keep the rows where that date is before 2017-01-01 or null:
select c.full_name, a.max_date
from customers c
left join
(
select customer_id, max(assignment_date) as max_date
from assignments
group by customer_id
) a on a.customer_id = c.customer_id
where a.max_date < date '2017-01-01'
or a.max_date is null
order by a.max_date desc;
I have the following scenario. i have three tables (users, sales, sales_details) Users to Sales is a 1 to 1 relationship and sales to sales_details is 1 to many.
I am running a query where I get all the sales for each user by joining all 3 tables without any issue.
Query looks something like this
SELECT s.month as month,u.name as name, s.year as year, s.date as date,sum(sd.qty) as qty,sum(sd.qty*sd.value) as value,s.id as id,sum(sd.stock) as stock,s.currency as currency,s.user as user
FROM sales as s
left join sales_details as sd on s.id = sd.Sales
inner join users as u on s.user = u.Id
group by s.Id
What I want to do now is add an extra field in my query which will be a subquery.
SELECT SUM(total) AS total_yearly
FROM (
SELECT sum(qty) as total
FROM sales
left join sales_details on sales.Id = sales_details.Sales
WHERE ((month <= MONTH(NOW()) and year = YEAR(NOW()))
or (month >= MONTH(Date_add(Now(),interval - 12 month)) and year = YEAR(Date_add(Now(),interval - 12 month))))
and User = **ID OF USER** ) as sub
This query on its own gives me the sales for the user for the past 12 months while the original query does it per month. I know that the result will be the same for each user but i need it for other calculations.
My problem is how I will join the 2 queries so that the subquery will read the user id from the original one.
Thanks in advance!
Group the second query by user, and then join it with the original query.
SELECT s.month as month,u.name as name, s.year as year, s.date as date,
sum(sd.qty) as qty,sum(sd.qty*sd.value) as value,s.id as id,
sum(sd.stock) as stock,s.currency as currency,s.user as user,
us.total
FROM sales as s
left join sales_details as sd on s.id = sd.Sales
inner join users as u on s.user = u.Id
inner join (
SELECT User, sum(qty) as total
FROM sales
left join sales_details on sales.Id = sales_details.Sales
WHERE ((month <= MONTH(NOW()) and year = YEAR(NOW()))
or (month >= MONTH(Date_add(Now(),interval - 12 month)) and year = YEAR(Date_add(Now(),interval - 12 month)))))
GROUP BY User) AS us ON s.user = us.user
group by s.Id