This is my query:
SELECT count(*) as total, dp.name,dp.id,dp.description, dp.avatar
FROM `doctors` d
right join departments dp on d.department_id = dp.id
group by d.department_id
I have to tables: doctors and departments. I want to extract the total number of doctors from each department. This query works fine, it returns me all of the deparments, which have a doctors, but not which does not have. Somehow I want to show all of the departements and a total, which represents the doctors whose belong to a department. How can i do that ?
This is the doctor table:
and this is the departments table
You can give this a try:
SELECT
(SELECT count(*) FROM doctors d WHERE d.department_id = dp.id) AS total,
dp.*
FROM departments AS dp
And if you want to use JOIN then try this:
SELECT
COUNT(d.department_id) AS total,
dp.*
FROM departments AS dp
LEFT JOIN doctors AS d ON dp.id = d.department_id
GROUP BY dp.id
SELECT (SELECT count(*) FROM doctors AS d WHERE d.id = dp.id) as total, dp.name,dp.id,dp.description, dp.avatar
FROM departments dp
there are multiple ways of doing this ofcourse, I would do it like this
i dont think you need to join you just need a count of all the doctors and you dont do anything with the rest of the information
In my couple of decades working with SQL I've never used right joins. I've always found the LEFT join easier to read. I also try and return the columns in order of the highest to lowest level of detail and finish with sum's and counts. It reads a lot better.
Try this:
SELECT dp.id,dp.name,dp.description, dp.avatar,count(*) as total
FROM departments dp
LEFT JOIN doctors d
on d.department_id = dp.id
GROUP BY dp.id,dp.name,dp.description, dp.avatar
You must always group by every column within your select clause except those that are an aggregation (e.g. sum,count) or a constant.
Related
I want to get the each count of data by combining two tables in MySQL. This is the scenario I have following tables. emp_tab(name, dept_id ) and dept_tab(dept_id, dept_name). I want to write a query to show the number of employees in each department with the department name.
tried code:
SELECT dept_tab.dept_name, number
FROM emp_tab
INNER JOIN dept_tab ON emp_tab.dept_id=dept_tab.dept_id;
My try is not successful. Can you please show me how can I solve this. I am beginner to MySQL
Two things:
You need to use a group by and count function
Your join was joining an invalid table
SELECT dept_tab.dept_name, COUNT(*) as number
FROM emp_tab
INNER JOIN dept_tab ON emp_tab.dept_id=dept_tab.dept_id
GROUP BY dept_tab.dept_name
You can use JOIN and GROUP BY by dept_name to count number of employees.
In your question, what is Customerstable? I assume that is dept_tab?
SELECT
d.dept_name,
COUNT(d.id) AS cnt
FROM
dept_tab d
LEFT JOIN empt_tab e
ON e.dept_id = d.dept_id
GROUP BY d.dept_name ;
I hope someone can help me with this problem, I been trying different combinations but can't seems to get the correct result.
First of all, I have 3 tables, category, department, and master, master has the FK. I want to get sum of total time for each department and sum of total time for category group by department so that I can see which department has how much time for that category, all should be group by department and in the correct order?
I can get the result but not coming out right, here is my code...
SELECT a.department, time_spent , COUNT(DISTINCT (a.department)), sum_quarantine FROM
(SELECT d.department, SUM(time_spent) as time_spent
FROM master as m
INNER JOIN department as d ON d.dept_id = m.dept_id GROUP BY d.department) AS a,
(SELECT d.department, c.category, SUM(time_spent) as sum_quarantine
FROM master as m
INNER JOIN category as c ON c.cat_id = m.cat_id
INNER JOIN department as d ON d.dept_id = m.dept_id
WHERE category = 'Quarantine' GROUP BY d.department) as b
GROUP BY b.department
What you want can be done without sub-query, making use of a CASE WHEN in a SUM, so that it only sums what you are interested in ('Quarantine'):
SELECT d.department,
SUM(CASE c.category
WHEN 'Quarantine' THEN time_spent
END) as sum_quarantine,
SUM(time_spent) time_spent,
COUNT(DISTINCT (c.category)) category_count
FROM master as m
INNER JOIN category as c ON c.cat_id = m.cat_id
INNER JOIN department as d ON d.dept_id = m.dept_id
GROUP BY d.department
ORDER BY 1
Here is fiddle.
Note that I added a count as well, since there was one in your attempt. But yours would always return 1, so I am not sure what you were looking for. I have added the number of categories linked to the department.
Also you did not specify the order you want, but it is easy to adapt the ORDER BY clause. The above query orders results by department, but if for instance you want to order by the second column in descending order, then do:
...
ORDER BY 2 DESC
If your results includes NULL values, and you prefer to have zeroes instead, then make use of the COALESCE function. For example:
COALESCE(SUM(time_spent), 0) time_spent,
I am trying to figure out this question on a practice page online with the following tables:
Question:
For all cases in which the same customer rated the same product
more than once, and in some point in time gave it a lower rating
than before, return the customer name, the name of the product,
and the lowest star rating that was given.
I cant seem to figure out why this isnt correct - would anyone be able to help?
Here is what I have so far (without sample data):
SELECT
Customer.customer_name,
Product.product_name,
MIN(Rating.rating_stars)
FROM Rating
JOIN Product ON Rating.prod_id = Product.prod_id
JOIN Customer ON Rating.cust_id = Customer.prod_id
GROUP BY Customer.customer_name, Product.product_name
HAVING COUNT(Product.prod_id) > 1
This query will return the minimum rating stars of a product that has been reviewed more than once by the same customer, with any of the newer ratings lower than an older rating:
SELECT
r1.prod_id,
r1.cust_id,
MIN(r1.rating_star) AS min_rating
FROM
rating r1 INNER JOIN rating r2
ON r1.prod_id=r2.prod_id
AND r1.cust_id=r2.cust_id
AND r1.rating_date>r2.rating_date
AND r1.rating_star<r2.rating_star
GROUP BY
r1.prod_id,
r1.cust_id
you can then join this query with products and customers table:
SELECT
customer.customer_name,
product.product_name,
m.min_rating
FROM (
SELECT
r1.prod_id,
r1.cust_id,
MIN(r1.rating_star) AS min_rating
FROM
rating r1 INNER JOIN rating r2
ON r1.prod_id=r2.prod_id
AND r1.cust_id=r2.cust_id
AND r1.rating_date>r2.rating_date
AND r1.rating_star<r2.rating_star
GROUP BY
r1.prod_id,
r1.cust_id) m
INNER JOIN customer on m.cust_id = customer.cust_id
INNER JOIN product ON m.product_id = product.product_id
Just a few points:
You cant specify the tables in the FROM clause the sane way you specify attributes in the SELECT. You can only have a single table in the FROM, and one more for each Join you use.
SELECT a, b, c FROM a; <----------fine
SELECT a, b, c FROM a, b; <----not fine
SELECT a, b, c FROM a JOIN b; <---fine
When it comes to the tables in the FROM/JOIN, you dont use "AS" to give them an alias, just the table name followed by the alias.
FROM atable a JOIN btable b; <--This assigns alias a to "atable" and b to "btable".
You also have to specify the common attribute that the tables are going to be joined on:
customer JOIN rating ON customer.cust_id = rating.cust_id;
As for the rest you can probably work out the correct WHERE clauses to use once you have the syntax down.
I'm using 4 tables
CUSTOMER
CUSTOMER_ORDER
CUST_ORDER_LINE
CUST_ADDRESS
I used Inner joins to link the tables. CUSTOMER is linked to CUSTOMER_ORDER and CUST_ADDRESS by customer_ID, and CUSTOMER_ORDER_LINE is linked to CUSTOMER_ORDER by order_ID. Order_ID does not appear in the CUSTOMER or CUST_ADDRESS tables.
When I run the query below, I get every shipping address on record for that particular customer and order number.
For example, a distributor has 25 possible shipping addresses, but they only ship one order to one shipping address at a time. My query is bringing back one order number 25 times for every address. Any advice would be wonderful. Thank you.
SELECT DISTINCT TOP (100) PERCENT dbo.CUSTOMER_ORDER.ID,
dbo.CUSTOMER.NAME,
dbo.CUST_ORDER_LINE.PART_ID,
dbo.CUST_ORDER_LINE.ORDER_QTY,
dbo.CUSTOMER_ORDER.STATUS,
dbo.CUSTOMER_ORDER.SHIPTO_ID,
dbo.CUST_ADDRESS.NAME AS Expr1
FROM dbo.CUSTOMER
INNER JOIN dbo.CUSTOMER_ORDER
ON dbo.CUSTOMER.ID = dbo.CUSTOMER_ORDER.CUSTOMER_ID
INNER JOIN dbo.CUST_ORDER_LINE
ON dbo.CUSTOMER_ORDER.ID = dbo.CUST_ORDER_LINE.CUST_ORDER_ID
INNER JOIN dbo.CUST_ADDRESS
ON dbo.CUSTOMER.ID = dbo.CUST_ADDRESS.CUSTOMER_ID
WHERE (dbo.CUSTOMER_ORDER.ORDER_DATE > '1/1/2014')
AND (dbo.CUSTOMER_ORDER.ID NOT LIKE 'RMA%')
GROUP BY dbo.CUSTOMER_ORDER.ID,
dbo.CUSTOMER.NAME,
dbo.CUST_ORDER_LINE.PART_ID,
dbo.CUST_ORDER_LINE.ORDER_QTY,
dbo.CUSTOMER_ORDER.STATUS,
dbo.CUSTOMER_ORDER.SHIPTO_ID,
dbo.CUST_ADDRESS.NAME
ORDER BY dbo.CUSTOMER_ORDER.ID
As a shot in the dark it seems your query should be something like this.
SELECT
co.ID,
c.NAME,
col.PART_ID,
col.ORDER_QTY,
co.STATUS,
co.SHIPTO_ID,
ca.NAME AS Expr1
FROM dbo.CUSTOMER c
INNER JOIN dbo.CUSTOMER_ORDER co ON c.ID = co.CUSTOMER_ID
INNER JOIN dbo.CUST_ORDER_LINE col ON co.ID = col.CUST_ORDER_ID
INNER JOIN dbo.CUST_ADDRESS ca ON co.SHIPTO_ID = ca.CUSTOMER_ID --this is now joining to the order table.
WHERE co.ORDER_DATE > '2014-01-01'
AND co.ID NOT LIKE 'RMA%'
GROUP BY co.ID,
c.NAME,
col.PART_ID,
col.ORDER_QTY,
co.STATUS,
co.SHIPTO_ID,
ca.NAME
ORDER BY co.ID
Notice how using aliases makes this look a lot cleaner. I also changed up the string date to use the generally accepted format. This will work regardless of your DATEFORMAT setting.
OK,
I have a table with people (id, name, address, etc.). Which has a one to many relationship with a table employees (id, person_id, salary, department_id, etc.). And the employees all belong to (many to one relationship) different departments (id, title, location, year_id) which are year-specific.
I want to write a query to find the employees who worked in 2013 and exclude those who continue to work for the company in 2014. Basically I want those who worked for the company last year but don't anymore. I made a feeble attempt below.
SELECT * FROM people
JOIN employees ON people.id=employees.person_id
RIGHT JOIN departments ON employees.department_id=departments.id
AND departments.year_id='2013'
WHERE departments.year_id<>'2014'
Any help would be appreciated.
You can use not exists check for those employees who discontinued work in 2014
SELECT * FROM people
JOIN employees e ON people.id=e.person_id
RIGHT JOIN departments ON e.department_id=departments.id
WHERE departments.year_id='2013'
AND NOT EXISTS
(SELECT 1
FROM departments
JOIN employees ee ON ee.department_id=departments.id
WHERE departments.year_id = '2014'
AND e.id=ee.id
)
Or not in() solution but its not recommended due to a dependent sub query
SELECT * FROM people
JOIN employees e ON people.id=e.person_id
RIGHT JOIN departments ON e.department_id=departments.id
WHERE departments.year_id='2013'
AND e.id NOT IN
(SELECT ee.id
FROM departments
JOIN employees ee ON ee.department_id=departments.id
WHERE departments.year_id = '2014'
)
I'm unsure as to why you have a one to many on people to employees or how this functionality is applied within your system, but if I understand it correctly, this should work.
M Khalid Junaid's answer will likely work however I despise using sub-queries as they do not tend to scale well. The below should work while returning only 1 row per employee (no groups) in addition it only has 1 left join and no sub-queries.
SELECT * FROM people
JOIN employees ON people.id=employees.person_id
JOIN departments as dept_start ON employees.department_id=departments.id && departments.year_id = 2013
LEFT JOIN departments as dept_end ON employees.department_id=departments.id && departments.year_id = 2014
WHERE dept_start.id IS NOT NULL && dept_end.id IS NULL