COUNT Changes with Join on another Table MySQL - mysql

I have the following Database Structure
Table Employee:
Name ENr
Name 1 1
Name 2 2
Name 3 3
...
Table Travel:
Employee Costs
Name 1 8000
Name 1 56000
Name 2 800
and so on.
Now I want to Select The Name of the employees, the Count of the Travels and the Average Costs, as well as the ENr
Thats my SQL Select so far:
SELECT employee, COUNT(travel.employee), AVG(costs) FROM travel GROUP BY employee
However, as soon as I try to connect with the employee Table to add the ENr, my count is simply wrong.
I tried to connect with simple:
SELECT ENr, Employee.. FROM travel, employee
And also with an INNER JOIN.
Hope somebody could help me out :)

Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
You need JOIN conditions:
SELECT e.name, e.eNR, COUNT(*), AVG(t.costs)
FROM employee e JOIN
travel t
ON e.name = t.name
GROUP BY e.name, e.eNR;
Additional comments:
When you have more than one table in a query, use table aliases and qualified column names.
Include all non-aggregated columns in the GROUP BY.
name is a lousy foreign key. Usually, you want foreign keys to be unique (names may not be unique). And numbers are more efficient for indexing purposes.

Related

Using join and group with sum

I am fairly new to MySQL and have this theoretical problem given to me. I am given these tables
customers
---------------
id
name
country
order_date
orders
---------------
id
order_number
order_type
customers_order_details
---------------
id
customer_id
order_id
price
A customer can have multiple different orders. I need to retrieve the customers with the largest total price spent, with the total price must be at least 100. Is my approach correct?
SELECT c.id, c.name AS customer_name, c.country , SUM(d.price) AS total_price
FROM customers c
JOIN customers_order_details d
ON c.id = d.customer_id
GROUP BY customer_name,
HAVING total_price >= 100
ORDER BY total_price DESC;
I ask due to not sure since I was told for GROUP BY that I needed to add all columns specified but feel that using the name is more than adequate
It looks almost correct.
Grouping by only customers.name isn't right though. Besides that this will throw an error on more tightly configured MySQL servers or newer versions or even DBMS from other vendors, what happens if there are two or more different customers with the same name, say some "John Smith"s? They're all aggregated in the same group giving false figures!
The safest bet is just to group by all columns not being an argument to an aggregation function. That would be customers.id, customers.name and customers.country in this case. In some DBMS you can also group by just a tuple of columns all the columns not given to an aggregation function are dependent of. If customers.id is declared as primary key, that would fulfill that rule and you could just group by it. But I'm not really sure if MySQL does implement that shortcut or in which versions or configurations. So you should better go with all the columns here.
Side note: The schema design is a little weird. Why are the order details directly linked to customers and not the orders themselves are linked to the customers? As it is now an order can have multiple details belonging to different customers. That may be right in your use case, but it's not the usual thing you would expect. Maybe you should revise that.
Your code looks quite fine. I would jus recommend aggregating by the primary key of the customer table rather than by the name:
SELECT c.id, c.name AS customer_name, c.country , SUM(d.price) AS total_price
FROM customers c
JOIN customers_order_details d ON c.id = d.customer_id
GROUP BY c.id
HAVING SUM(d.price) >= 100
ORDER BY total_price DESC;
This makes the code a valid aggregation query; all non-aggregated columns in the select clause are functionally dependent on the column in the group by clause.
As a side note: using column aliases in the HAVING clause is a MySQL extension to the SQL standard. You can use that feature, or phrase the HAVING clause in pure ANSI SQL, repeating the aggregate expression.

Trying to get a row count in a subquery

I have two tables, one is departments and the other is employees. The department id is a foreign key in the employees table. The employee table has a name and a flag saying if the person is part-time. I can have zero or more employees in a department. I'm trying to figure out out to get a list of all departments where a department has at least one employee and if it does have at least one employee, that all the employees are part time. I think this has to be some kind of subquery to get this. Here's what I have so far:
SELECT dept.name
,dept.id
,employee.deptid
,count(employee.is_parttime)
FROM employee
,dept
WHERE dept.id = employee.deptid
AND employee.is_parttime = 1
GROUP BY employee.is_parttime
I would really appreciate any help at this point.
You must join (properly) the tables and group by department with a condition in the HAVING clause:
select d.name, d.id, count(e.id) total
from dept d inner join employee e
on d.id = e.deptid
group by d.name, d.id
having total = sum(e.is_parttime)
The inner join returns only departments with at least 1 employee.
The column is_parttime (I guess) is a flag with values 0 or 1 so by summing it the result is the number of employees that are part time in the department and this number is compared to the total number of employees of the department.
As a preliminary aside, I recommend expressing joins with the JOIN keyword, and segregating join conditions from filter conditions. Doing so would make the original query look like so:
select dept.name, dept.id, employee.deptid, count(employee.is_parttime)
from employee
join dept on dept.id = employee.deptid
where employee.is_parttime = 1
group by employee.is_parttime
It doesn't make much practical difference for inner joins, but it does make the structure of the data and the logic of the query a bit clearer. On the other hand, it does make a difference for outer joins, and there is value in consistency.
As for the actual question, yes, one can rewrite the original query using a subquery or an inline view to produce the requested result. (An "inline view" is technically what one should call an embedded query used as a table in the FROM clause, but some people lump these in with subqueries.)
Example using a subquery
select dept.name, dept.id
from dept
where dept.id in (
select deptid
from employee
group by deptid
having count(*) == sum(is_parttime)
)
Example using an inline view
select dept.name, dept.id
from dept
join (
select deptid
from employee
group by deptid
having count(*) == sum(is_parttime)
) pt_dept
on dept.id = pt_dept.deptid
In each case, the subquery / inline view does most of the work. It aggregates employees by department, then filters the groups (HAVING clause) to select only those in which the part-time employee count is the same as the total count. Naturally, departments without any employees will not be represented. If a list of department IDs would suffice for a list of departments, then that's actually all you need. To get the department names too, however, you need to combine that with data from the dept table, as demonstrated in the two example queries.

SQL Print the name of all Employees together with the name of their supervisor

I'm trying to learn SQL and have this question: print the name of all employees together with the name of their supervisor.
Here is my Employees table:
Table Employee
How do I use a SELECT command in new query to get the result out? I tried with a self join.
Ty
Max (SQL NOOB)
Try the below
SELECT t1.EmployeeName AS Manager, t2.EmployeeID as EmployeeName
FROM Employee t1
LEFT JOIN Employee t2 ON t1.ManagerID=t2.EmployeeID
An inner join should do it. Here's the syntax, but you'll have to apply it to your database:
SELECT c.name, o.name
FROM cats c
INNER JOIN owners o
ON c.owner_id = o.id
"cats c" basically means "Cats table, which I'm nicknaming c." "owners o" basically means "Owners table, which I'm nicknaming o." In your select, you tell it which fields you want by their name, and which table their in: [table nickname].[fieldname]. The ON is where you specify a common field from each table, which tells it how to join the two tables together. In the case of this example, we're saying that we want the owner who's id is equal to the owner id field of the cats table. The owner_id field is a foreign key of the owners table.
I know answers like this are frustrating when you're learning, but the truth is you'll learn better if you have to figure a bit out for yourself, and I can't do your homework for you (I mean that nicely..)

SQl query Multiple select statments in the same table under different conditions

So I have 3 tables that I want to perform some queries on but during that process I end up returning back to a table I already performed some functions on and it.
I first get the essn from one dependent table and search the employee table for a ssn matching it then i got the superssn and compare to the mgrssn in another table. The last step is to go back into the employee table and find the name of the person who has the same ssn of mgrssn.
The issue here is that once i get the matching superssn I can't access the other rows.
select lname, fname from
(select mgrssn from department) as d,
(select superssn, lname,fname,ssn from
(select essn from dependent where dependent_name ='joy') as de,
(select ssn,lname,fname,superssn from employee) as e
where essn =ssn) as s
where s.ssn = mgrssn
Should I look into doing joins instead?
You don't need the subqueries. Your query is a bit hard to follow (you don't have table aliases for all the columns), but I think this is what you are trying to do:
select lname, fname
from department d join
employee e
on e.ssn = d.mgrssn join
dependent dep
on dep.essn = e.ssn
where dep.dependent_name ='joy';
Simple rule: Never use commas in the from clause. Always use explicit join syntax.

Creating an SQL View With Calculations From Multiple Tables

So I have two tables that I need information from. I have a
ballot_table(vote CHAR(30), username CHAR(30)) that has the name of the candidate each username voted for. I also have another table with a list of the candidates. I need someway to return the list of candidates with the corresponding amount of times there name appears in ballot_table in the same query. Thanks!
This is a horrible design but here is how you do it:
select count(*) as votes, vote as [candidate]
from ballot_table
where ucase(vote) in (select ucase(item) from table_with_list_of_candidates)
group by ucase(vote)
a better design would have the list of candidates table include a key and then just have the key in the ballot_table with a varchar for a write in (if needed).
You can do this with an Outer Join and a Group By. I'm assuming the field name in the candidate table is Name.
Select c.Name, Count(Distinct b.UserName) Votes
From ballot_table b
Right Join candidate c On c.Name = b.Vote
Group By c.Name
This would only return the total votes for the candidates you have in your Candidate table. Any other "write-in" vote wouldn't be included.