I have a select statement that returns two columns: office names and total per office:
select o.OfficeName, c.Total
from Offices o
left join
( select OfficeID, count(*) Total
from Customers c
group by OfficeID
) c on o.OfficeID = c.OfficeID
where o.ClusterID = 29
How can I get the row that has max total?
"Customers" table has an "OfficeID" colummn. For a given "ClusterID", I select all offices within the cluster identified by cluster id (e.g. 29) and count the customers belongin to those offices.
There are a number of approaches:
SELECT OfficeName, Total
FROM ( SELECT o.OfficeName, c.Total, MAX(Total) OVER() [MaxTotal]
FROM Offices o
LEFT JOIN
( SELECT OfficeID, COUNT(*) Total
FROM Customers
GROUP BY OfficeID
) c
ON o.OfficeID = c.OfficeID
WHERE o.ClusterID = 29
) c
WHERE Total = MaxTotal
OR
WITH CTE AS
( SELECT o.OfficeName, c.Total
FROM Offices o
LEFT JOIN
( SELECT OfficeID, COUNT(*) Total
FROM Customers
GROUP BY OfficeID
) c
ON o.OfficeID = c.OfficeID
WHERE o.ClusterID = 29
)
SELECT *
FROM CTE
WHERE Total = (SELECT MAX(Total) FROM CTE)
OR
SELECT TOP 1 o.OfficeName, c.Total
FROM Offices o
LEFT JOIN
( SELECT OfficeID, COUNT(*) Total
FROM Customers
GROUP BY OfficeID
) c
ON o.OfficeID = c.OfficeID
WHERE o.ClusterID = 29
ORDER BY Total DESC
Although using TOP 1 may not be what you are after, with the other methods if there are 2 offices with the same number of customers they will both be returned, whereas TOP 1 will only return 1 of these (probably in order of office name). If you only ever want 1 record, then this is the best method
SELECT TOP 1 o.OfficeName, c.Total
FROM Offices o
LEFT JOIN
(SELECT OfficeID, count(*) Total
FROM Customers c
GROUP BY OfficeID
) c ON o.OfficeID = c.OfficeID
WHERE o.ClusterID = 29
ORDER BY c.Total DESC
WITH TIES offers a cleaner way to get all offices sharing the top count:
with a as (
select o.OfficeID,Total=COUNT(*)
from Offices o
inner join Customers c on c.OfficeID=o.OfficeID
group by o.OfficeID
)
select top 1 WITH TIES t.OfficeName, a.Total
from a
inner join Offices t on t.OfficeID=a.OfficeID
where t.ClusterID=29
order by a.Total desc
Related
So far I have this query:
SELECT
c.id AS company_id,
c.company_name,
COUNT(*) AS employee_count
FROM
ct_companies c
INNER JOIN ct_employees e ON c.id = e.company_id
GROUP BY
c.domain,
c.postcode,
c.company_name
HAVING
(
employee_count >= 1
AND employee_count <= 5
)
ORDER BY
employee_count DESC
Now, this works great, it selects companies who have at least 1 employee but no more than 5 and shows me the employee count.
But what I want to be able to do, is select every employee within a company, but only where that company has between 1 and 5 employees like above.
So something like
SELECT e.id FROM ct_employees e WHERE (employee_count >= 1 AND employee_count <= 5)
You could try
SELECT e.id,
d.employee_count
FROM ct_employees e
INNER JOIN (SELECT c.id AS company_id,
COUNT(*) AS employee_count
FROM ct_companies c
INNER JOIN ct_employees e1
ON c.id = e1.company_id
GROUP BY c.domain,
c.postcode,
c.id
HAVING COUNT(*) >= 1
AND COUNT(*) <= 5) d
ON d.company_id = e.company_id
ORDER BY employee_count DESC
I have reports table that aggregates data each product quantity each day.
SELECT r.year, r.month, c.id, c.client_name, p.product_name, cc.country_name, sum(r.quantity) units FROM
client c
join report r on c.id = r.client_id
join product p on r.product_id = p.id
join country cc on r.country_id = c.id
WHERE r.year = year(now())
group by r.year, r.month, c.id, p.product_name, cc.country_name
I'm trying to figure out how group units sum by month, client, product and country where query shows sum for top 5 countries and rest is sum from bottom countries. Something like this:
case
when sum(r.quantity) = 'Top 1' then cc.country_name
when sum(r.quantity) = Top 2' then cc.country_name
.....
when sum(r.quantity) = 'Top 2' then cc.country_name
else 'Other'
How can I do this?
Many thanks in advance
you can try this. Here i sort the result from most quantity to less and add a row number. so the first 6 are the top.
please try it, but i cant tested.
SELECT
#nr := ( #nr +1) AS nr,
IF ( #nr < 7, CONCAT('Top ',#nr), 'other' ) AS top,
r.* FROM (
SELECT r.year, r.month, c.id, c.client_name, p.product_name, cc.country_name, sum(r.quantity) units
FROM CLIENT c
JOIN report r ON c.id = r.client_id
JOIN product p ON r.product_id = p.id
JOIN country cc ON r.country_id = c.id
WHERE r.year = YEAR(now())
GROUP BY r.year, r.month, c.id, p.product_name, cc.country_name
ORDER BY sum(r.quantity) DESC
) AS r
CROSS JOIN ( SELECT #nr:=0 ) AS params;
I am creating an online shop where people can upload lessons.
My tables structure for this is
products - (contains basic lesson information)
p_tags - id|productid|tag - (contains all tags related to a product)
p_subjects - id|subjectid|productid - (contains all subjects related to a product)
p_years - id|yearid|productid - (contains all years related to a product)
p_types - id|typeid|productid - (contains all subjects related to a product)
subjects - id|name - (contains all subjects links to p_subjects)
resourcetypes - id|name - (contains all product types links to p_types)
years - id|name - (contains all years links to p_years)
What I am trying to do is write a query that can generate a relevance score based on user search criteria. This is what I have so far:
SELECT
IFNull(a.matchedTags,0) AS matchedtags,
a.title,
IFNull(b.matchedSubjects,0) AS matchedsubjects,
IFNull(c.matchedYears,0) AS matchedyears,
IFNull(d.matchedTypes,0) AS matchedtypes
FROM
(
SELECT
z.*,
COUNT(*) AS matchedTags
FROM products z
INNER JOIN p_tags pt ON pt.productid = z.id
WHERE
pt.tag IN('foo','test')
GROUP BY z.id
HAVING COUNT( * ) > 0
) as a
LEFT JOIN (
SELECT
y.*,
COUNT(*) AS matchedSubjects
FROM products y
WHERE
3 IN (SELECT subjectid FROM p_subjects m WHERE m.productid = y.id)
GROUP BY y.id
HAVING COUNT( * ) > 0
) as b ON b.id=a.id
LEFT JOIN (
SELECT
x.*,
COUNT(*) AS matchedYears
FROM products x
WHERE
1 IN (SELECT yearid FROM p_years n WHERE n.productid = x.id)
GROUP BY x.id
HAVING COUNT( * ) > 0
) as c ON c.id=b.id
LEFT JOIN (
SELECT
w.*,
COUNT(*) AS matchedTypes
FROM products w
WHERE
1 IN (SELECT id FROM p_types o WHERE o.productid = w.id)
GROUP BY w.id
HAVING COUNT( * ) > 0
) as d ON d.id=c.id
The query runs fine but will only match a product if the previous criteria is met. I.e if a product has a tag 'foo' then it will then gain a value for number of subjects matched as well. If the product does not contain a tag it will return 0 for all following JOINS.
I'm guessing I'm using the wrong kind of join and have looked into OUTER JOIN using LEFT AND RIGHT then UNION but don't know how to slip this into this code and whether it would work anyway.
Thanks in advance
What an idiot!! I was joining the joins on top of each other so it was only adding to the criteria above. I have changed it now and working sweeet!!
SELECT
g.title,
g.id,
IFNull(a.matchedTags,0) AS matchedtags,
IFNull(b.matchedSubjects,0) AS matchedsubjects,
IFNull(c.matchedYears,0) AS matchedyears,
IFNull(d.matchedTypes,0) AS matchedtypes
FROM
(SELECT id,title FROM products) as g
LEFT JOIN (
SELECT
z.*,
COUNT(*) AS matchedTags
FROM products z
INNER JOIN p_tags pt ON pt.productid = z.id
WHERE
pt.tag IN('test')
GROUP BY z.id
) as a on a.id=g.id
LEFT JOIN (
SELECT
y.*,
COUNT(*) AS matchedSubjects
FROM products y
WHERE
5 IN (SELECT subjectid FROM p_subjects m WHERE m.productid = y.id)
GROUP BY y.id
) as b ON b.id=g.id
LEFT JOIN (
SELECT
x.*,
COUNT(*) AS matchedYears
FROM products x
WHERE
1 IN (SELECT yearid FROM p_years n WHERE n.productid = x.id)
GROUP BY x.id
) as c ON c.id=g.id
LEFT JOIN (
SELECT
w.*,
COUNT(*) AS matchedTypes
FROM products w
WHERE
1 IN (SELECT id FROM p_types o WHERE o.productid = w.id)
GROUP BY w.id
) as d ON d.id=g.id
I'm using MySQL database server. My query is:
Count how many customers that they just have 1 order and how many customers that they have more than 1 orders.
This is my SQL query:
SELECT
COUNT((SELECT
customer_code
FROM
customer AS c
LEFT JOIN
order_info AS oi ON (c.customer_code = oi.customer_code)
GROUP BY customer_code
HAVING COUNT(id_order) = 1)) AS New_customers
How can I get this result.
You are grouping by customer_code before counting, I think this will group the rows together thus effectively removing all orders from the resultset. HAVING will always use the result set as the 'data feed'.
SELECT
COUNT(DISTINCT customer_code)
FROM
customer AS c
LEFT JOIN order_info AS oi ON (c.customer_code = oi.customer_code)
HAVING COUNT(id_order) = 1
OR a lot simpler (but perhaps not more efficient)
SELECT
COUNT(customer_code)
FROM
customer AS c
WHERE (
SELECT
COUNT(*)
FROM `order_info`
WHERE
`customer_code` = `c`.`customer_code`
) = 1
To get the number of customers with more than one order, simply change the = into > where appropiate.
SELECT
count(customer_code)
FROM
customer AS c
LEFT JOIN
order_info AS oi ON (c.customer_code = oi.customer_code)
GROUP BY customer_code
HAVING COUNT(id_order) = 1
For customers having 1 order
SELECT count(customer_code) FROM customer AS c
INNER JOIN order_info AS oi ON (c.customer_code = oi.customer_code)
GROUP BY customer_code HAVING COUNT(id_order) = 1))
For customers having MORE THAn 1 order
SELECT count(customer_code) FROM customer AS c
INNER JOIN order_info AS oi ON (c.customer_code = oi.customer_code)
GROUP BY customer_code HAVING COUNT(id_order) > 1))
Try this
SELECT
count(*)
FROM
customer AS c
LEFT JOIN
order_info AS oi ON c.customer_code = oi.customer_code
HAVING COUNT(id_order) = 1
try this:
SELECT * FROM ( select c.customer_code, count(*) total FROM customer c
LEFT JOIN
order_info AS oi ON (c.customer_code = oi.customer_code)
GROUP BY customer_code) test
CASE total
WHEN 1 THEN SELECT total one_order FROM test;
ELSE
SELECT total more_order FROM test
The intersect keyword is not available in mysql. I want to know how to implement the following in mysql db. My tables are:
customer(cid,city,name,state)
orders(cid,oid,date)
product(pid,price,productname)
lineitem(lid,pid,oid,totalquantity,totalprice)
I want the products bought by all the customers of a particular city 'X'. i.e. every customer in city 'x' should have bought the product. I managed to select the oid's and the pid's of customers living in that particular city. Now I should select the pid's which is present in all the oid's.
Example.
Oid Pid
2400 1
2400 2
2401 3
2401 1
2402 1
2403 1
2403 3
The answer from the above input should be 1 because it is present in all oid's. The query which I used to get the oid's and pid's:
select t.oid,l.pid
from lineitem l
join (select o.oid,c1.cid
from orders o
join (select c.cid
from customer c
where c.city='X') c1
where o.cid=c1.cid) t on l.oid=t.oid
Now I need to intersect all the oid's and get the result.The query should not be dependent on data.
Try:
select pid, count(*)
from (select t.oid, l.pid
from lineitem l
join (select o.oid, c1.cid
from orders o
join (select c.cid from customer c where c.city = 'X') c1
where o.cid = c1.cid) t
on l.oid = t.oid) x
group by pid
having count(*) = (select count(*)
from (select distinct oid
from lineitem l
join (select o.oid, c1.cid
from orders o
join (select c.cid
from customer c
where c.city = 'X') c1
where o.cid = c1.cid) t
on l.oid = t.oid) y) z
I think you can achieve what you want by using IN