I have 2 tables that I would like join where the contactid is unique and has the highest allowance.
EMPLOYEE
Employee ID
contactid
employerid
1
555444333
25435566
2
555444333
84235621
3
234232144
57353457
EMPLOYEEDETAILS
Employee ID
Annual Allowance
1
£10000
2
£1000
3
£2000
I would like to achieve below where I want to show the EmployeeID with the highest allowance for the unique contactid.
EmployeeID
contactid
Annual Allowance
1
555444333
£10000
3
234232144
£2000
I have tried the SQL code below but it's not giving me the unique contactid with the highest allowance.
SELECT EMPLOYEE.employeeid, EMPLOYEE.contactid, MAX(EMPLOYEEDETAILS.annualallowance)
from
cxm_employee EMPLOYEE
JOIN
cxm_employeedetails EMPLOYEEDETAILS ON EMPLOYEE.employeeid = EMPLOYEEDETAILS.employeeid
group by EMPLOYEE.employeeid,EMPLOYEE.employeecontactid
Where am I going wrong?
I want to show the EmployeeID with the highest allowance for the unique contactid.
Your code does not work because it only brings the details of the current employee, letting along other employees that have the same contactid.
I think it is easier to do with window functions:
select *
from (
select e.*, d.annualallowance,
rank() over(partition by e.contactid order by d.annualallowance desc) rn
from employee e
inner join employeedetails d on d.employeeid = e.employeeid
) t
where rn = 1
rank() ranks employees having the same contact by descending annual allowance ; we can then use this information for filtering.
In pre-8.0 versions of MySQL, where window functions are not supported, an alternative uses a correlated subquery to retrieve the top allowance per contact; we can then use this information to filter the dataset :
select e.*, d.annualallowance
from employee e
inner join employeedetails d on d.employeeid = e.employeeid
where d.annualallowance = (
select max(d1.annualallowance)
from employee e1
inner join employeedetails d1 on d1.employeeid = e1.employeeid
where e1.contactid = e.contactid
)
Demo on DB Fiddle
Related
"employee" Table
emp_id
empName
1
ABC
2
xyx
"client" Table:
id
emp_id
clientName
1
1
a
2
1
b
3
1
c
4
2
d
"collection" Table
id
emp_id
Amount
1
2
1000
2
1
2000
3
1
1000
4
1
1200
I want to aggregate values from the three tables input tables here reported as samples. For each employee I need to find
the total collection amount for that employee (as a sum)
the clients that are involved with the corresponding employee (as a comma-separated value)
Here follows my current query.
MyQuery:
SELECT emp_id,
empName,
GROUP_CONCAT(client.clientName ORDER BY client.id SEPARATOR '') AS clientName,
SUM(collection.Amount)
FROM employee
LEFT JOIN client
ON clent.emp_id = employee.emp_id
LEFT JOIN collection
ON collection.emp_id = employee.emp_id
GROUP BY employee.emp_id;
The problem of this query is that I'm getting wrong values of sums and clients when an employee is associated to multiple of them.
Current Output:
emp_id
empName
clientName
TotalCollection
1
ABC
a,b,c,c,b,a,a,b,c
8400
2
xyz
d,d
1000
Expected Output:
emp_id
empName
clientName
TotalCollection
1
ABC
a , b , c
4200
2
xyz
d
1000
How can I solve this problem?
There are some typos in your query:
the separator inside the GROUP_CONCAT function should be a comma instead of a space, given your current output, though comma is default value, so you can really omit that clause.
each alias in your select requires the table where it comes from, as long as those field names are used in more than one tables among the ones you're joining on
your GROUP BY clause should at least contain every field that is not aggregated inside the SELECT clause in order to have a potentially correct output.
The overall conceptual problem in your query is that the join combines every row of the "employee" table with every row of the "client" table (resulting in multiple rows and higher sum of amounts during the aggregation). One way for getting out of the rabbit hole is a first aggregation on the "client" table (to have one row for each "emp_id" value), then join back with the other tables.
SELECT emp.emp_id,
emp.empName,
cl.clientName,
SUM(coll.Amount)
FROM employee emp
LEFT JOIN (SELECT emp_id,
GROUP_CONCAT(client.clientName
ORDER BY client.id) AS clientName
FROM client
GROUP BY emp_id) cl
ON cl.emp_id = emp.emp_id
LEFT JOIN (SELECT emp_id, Amount FROM collection) coll
ON coll.emp_id = emp.emp_id
GROUP BY emp.emp_id,
emp.empName,
cl.clientName
Check the demo here.
Regardless of my comment, here is a query for your desired output:
SELECT
a.emp_id,
a.empName,
a.clientName,
SUM(col.Amount) AS totalCollection
FROM (SELECT e.emp_id,
e.`empName`,
GROUP_CONCAT(DISTINCT c.clientName ORDER BY c.id ) AS clientName
FROM employee e
LEFT JOIN `client` c
ON c.emp_id = e.emp_id
GROUP BY e.`emp_id`) a
LEFT JOIN collection col
ON col.emp_id = a.emp_id
GROUP BY col.emp_id;
When having multiple joins, you should be careful about the relations and the number of results(rows) that your query generates. You might as well have multiple records in output than your desired ones.
Hope this helps
SELECT emp_id,
empName,
GROUP_CONCAT(client.clientName ORDER BY client.id SEPARATOR '') AS clientName,
C .Amount
FROM employee
LEFT JOIN client
ON clent.emp_id = employee.emp_id
LEFT JOIN (select collection.emp_id , sum(collection.Amount ) as Amount from collection group by collection.emp_id) C
ON C.emp_id = employee.emp_id
GROUP BY employee.emp_id;
it works for me now
select
d.DepartmentId,
d.Name,
d.GroupName,
eph.Rate * 40 * 52 * count(edh.EmployeeId) as AnnualPay
from
HumanResources.Department d,
HumanResources.EmployeePayHistory eph,
HumanResources.Employee e,
HumanResources.EmployeeDepartmentHistory edh
where
e.CurrentFlag = 'True' and
edh.DepartmentID = d.DepartmentID and
edh.EmployeeID = eph.EmployeeID and
e.EmployeeID = eph.EmployeeID
group by
d.departmentID;
The goal is to write a report to display the departmentid, name, groupname, the total annual pay for all employees who work in that department and the number of employees who work in that department.
To calculate the annual pay, multiply each of the employees’ pay rate by 40 hours for 52 weeks in the year.
Only include departments that spend more than half a million dollars on their total annual pay for all employees.
All employees should be current (use currentflag).
Sort the report by the total annual pay of employees in descending order.
The Tables are included, I can't figure out how to group by each department...Database
If I understood what you are looking for, this should work:
SELECT
d.DepartmentId,
d.Name,
d.GroupName,
SUM(eph.Rate * 40 * 52) as AnnualPay,
Count(edh.EmployeeId) as EmployeeCount
from HumanResources.Department d
JOIN HumanResources.EmployeeDepartmentHistory edh
ON edh.DepartmentID = d.DepartmentID
JOIN HumanResources.EmployeePayHistory eph
ON edh.EmployeeID = eph.EmployeeID
JOIN HumanResources.Employee e
ON e.EmployeeID = eph.EmployeeID
WHERE e.CurrentFlag = 'True'
GROUP BY d.departmentID,d.Name,d.GroupName
HAVING AnnualPay > 500000
ORDER BY AnnualPay DESC;
Please try the following...
SELECT DepartmentId AS DepartmentId,
DepartmentName AS DepartmentName,
DepartmentGroup AS DepartmentGroup,
SUM( expectedAnnualPay ) AS TotalExpectedAnnualPay,
COUNT( DepartmentId ) AS EmployeeCount
(
SELECT Department.DepartmentId AS DepartmentId,
Name AS DepartmentName,
GroupName AS DepartmentGroup
Rate *
40 *
52 AS expectedAnnualPay,
EmployeeID AS EmployeeID
FROM HumanResources.Department HRDepartment
JOIN HumanResources.EmployeeDepartmentHistory HREmployeeDepartmentHistory ON HREmployeeDepartmentHistory.DepartmentID = HRDepartment.DepartmentID
JOIN HumanResources.Employee HREmployee ON HREmployee.EmployeeID = HREmployeeDepartmentHistory.EmployeeID
JOIN HumanResources.EmployeeDepartmentHistory HREmployeeDepartmentHistory ON HREmployee.EmployeeID = HREmployeePayHistory.EmployeeID
WHERE HREmployee.CurrentFlag = 'True'
) departmentEmployee
GROUP BY DepartmentId
HAVING TotalExpectedAnnualPay > 500000
ORDER BY TotalExpectedAnnualPay DESC;
You appear to be asking for a list of the total expected annual pay amount for each department where that value is greater than $500,000.00 on the assumption that all current employees within that Department will remain with that Department for one year at the current Rate and that no Employees will be added during that time.
I approached this problem by starting with the following query (which I gave the alias of departmentEmployeeLevel)...
SELECT Department.DepartmentId AS DepartmentId,
Name AS DepartmentName,
GroupName AS DepartmentGroup
Rate *
40 *
52 AS expectedAnnualPay,
EmployeeID AS EmployeeID
FROM HumanResources.Department HRDepartment
JOIN HumanResources.EmployeeDepartmentHistory HREmployeeDepartmentHistory ON HREmployeeDepartmentHistory.DepartmentID = HRDepartment.DepartmentID
JOIN HumanResources.Employee HREmployee ON HREmployee.EmployeeID = HREmployeeDepartmentHistory.EmployeeID
JOIN HumanResources.EmployeeDepartmentHistory HREmployeeDepartmentHistory ON HREmployee.EmployeeID = HREmployeePayHistory.EmployeeID
WHERE HREmployee.CurrentFlag = 'True'
This subquery returns the DepartmentId, Department Name and GroupName of each department along with the EmployeeID of each current Employee and their computed expected annual pay.
The main query uses the results of the subquery to aggregate / group together the results by each Department and to calculate for each Department the total of the expected annual pay and the count of employees. It then uses HAVING to refine the list to only those departments whose expected annual pay cost is greater than $500,000.00 and sorts the remaining records by that field.
If you have any questions or comments, then please feel free to post a Comment accordingly.
In mySql I have 3 table name emp, emp_cat and emp_cat_relation. Employee Id from emp table and employee category id from emp_cat relate in emp_cat_relation table.
How I can pick last joined employee (1 or 2 row as I want) name and join date from each category using single sql query.
Date field in emp table
Use the LIMIT & ORDER BY Functions
SELECT *
FROM emp e
INNER JOIN emp_cat_relation ecr ON e.employee_id = ecr.employee_id
INNER JOIN emp_cat ec ON ecr.employee_category_id = ec..employee_category_id
ORDER BY e.date
LIMIT 2;
I just recently started learning how to write SQL queries, and I have a lot to learn and a lot of questions, mainly regarding defining conditions for an SQL query. I have 3 tables (with fields listed below):
Employee:
EmployeeID, Name, DoB, StartDate
Salary:
SalaryID, DataPaid, AmountPaid, EmployeeID
Address:
AddressID, Address, City, EmployeeID
Now I would like to know how to:
1. Count the number of employees that live in the city of London.
My attempt:
SELECT COUNT(City) AS EmployeeID FROM Address
WHERE City='London';
2. Add up the 'AmountPaid' values for all employees from the city of London.
My attempt:
SELECT SUM(AmountPaid) AS TotalPaid FROM Salary
WHERE City='London';
3. Display data for all employees that started in 2012 (have a 'Start Date' containing 2012). Not sure where to begin with this!
4. Delete all records where the employee 'Name' field is empty/null.
My attempt:
DELETE FROM Employee
WHERE Name=NULL;
Am I doing something wrong with my attempts? Any help would be appreciated.
THANK YOU!
In SQL Server (T-SQL), you cannot test a value for NULL using '='. It must be as follows:
Delete From Employee Where Name IS NULL
Also i would check for empty names:
DELETE FROM Employee where Name IS NULL OR Name=''
As for the point 3:
SELECT * FROM Employee WHERE Year(StartDate)=2012
As for the point 2, the table Salary does not have an City column. You need to join with Employee table like this:
SELECT SUM(AmountPaid) AS TotalPaid FROM Salary SA inner join Employee Em on Em.EmployeeID=SA.EmployeeID WHERE Em.City='London';
Smells a bit like homework. Anyway:
(1) count of employees in the city of London
First statement seems correct to me, isn't it? But the alias confused me a bit as it says EmployeeID but returned value is the count of employees.
(2) total amount paid for employees in the city of London
This wouldn't work with your statement because table Salary has no field City. You'll need a join here:
select sum(AmountPaid) as TotalPaid
from Salary s
join Address a on s.EmployeeID = a.EmployeeID
where a.City = 'London'
(3) employees started in 2012
Here you can use YEAR function to extract the year out of the date:
select *
from Employee
where Year(StartDate) = 2012
(4) delete unnamed employees
Taken from the solution of #ericpap (for the sake of completeness):
delete from Employee
where Name is NULL
or Name = ''
I would do it like this - it includes a test whereby you make tables and data to help you see how it works;
I assume a employee has only one address, but recieves multiple payments and while it may not be necessary to join from the employee tables in your example - it shows how the relationships between employees and the other tables work, which may help you understand the relational model better.
--Make the Tables
CREATE TABLE dbo.Employee
(
EmployeeID BIGINT PRIMARY KEY NOT NULL,
Name VARCHAR(50),
DoB DATE,
StartDate DATE
)
CREATE TABLE dbo.Salary
(
SalaryID BIGINT PRIMARY KEY NOT NULL,
DatePaid DATE, -- I think you mean DatePaid and not DataPaid
AmountPaid MONEY,
EmployeeID BIGINT
)
CREATE TABLE dbo.Address
(
AddressID BIGINT PRIMARY KEY NOT NULL,
[Address] VARCHAR(max),
City VARCHAR(200),
EmployeeID BIGINT
)
-- Put in some Test Data
INSERT INTO dbo.Employee (EmployeeID,Name, DoB, StartDate)
VALUES (1,'Bill Gates','19551028','20121014'),
(2,'Larry Ellison','19440817','20140101')
INSERT INTO dbo.Address (AddressID,[Address], City, EmployeeID)
VALUES (1,'15 Microsoft House','New York',1),
(2,'23 Oracle Flats','London',2)
INSERT INTO dbo.Salary(SalaryID, DatePaid, AmountPaid, EmployeeID)
VALUES (1,Getdate(),5000.53,1),
(2,'20140201',10000.23,2),
(3,'20140301',10000.23,2)
-- Queries;
--Count the number of employees that live in the city of London.
SELECT COUNT(Distinct E.EmployeeID) as Count_London
FROM dbo.Employee E
INNER JOIN dbo.[Address] A
ON E.EmployeeID = A.EmployeeID
WHERE A.City = 'London'
-- Result = 1
-- 2. Add up the 'AmountPaid' values for all employees from the city of London
--Total Amount
SELECT Sum(S.AmountPaid) as TotalPaid
FROM dbo.Employee E
INNER JOIN dbo.[Address] A
ON E.EmployeeID = A.EmployeeID
LEFT JOIN dbo.Salary S
ON E.EmployeeID = S.EmployeeID
WHERE A.City = 'London'
-- Result = 20000.46 (2 x 10000.23)
--split by employee;
SELECT E.EmployeeID,E.Name,Sum(S.AmountPaid) as TotalPaid
FROM dbo.Employee E
INNER JOIN dbo.[Address] A
ON E.EmployeeID = A.EmployeeID
LEFT JOIN dbo.Salary S
ON E.EmployeeID = S.EmployeeID
WHERE A.City = 'London'
GROUP BY E.EmployeeID, E.Name
--3. Display data for all employees that started in 2012
SELECT *
FROM dbo.Employee E
INNER JOIN dbo.[Address] A
ON E.EmployeeID = A.EmployeeID
LEFT JOIN dbo.Salary S
ON E.EmployeeID = S.EmployeeID
WHERE StartDate >= '20120101' AND StartDate < '20130101'
-- result = all bill gates fields
-- 4. Delete all records where the employee 'Name' field is empty/null.
DELETE FROM dbo.Employee WHERE EmployeeID IS NULL
you might want to delete where the employeeID is null from all the tables if it is possible to have records in there
This wasn't addressed in the other answers:
Count the number of employees that live in the city of London
Your attempt below will get you the right answer only if there is a different employee per row.
SELECT COUNT(City) AS EmployeeID FROM Address
WHERE City='London';
If your Address table looks like it does below, using the query you wrote, you would get 3 employees (but we can see from the table there are only 2 distinct EmployeeID's so thus only 2 employees).
AddressID, Address, City, EmployeeID
1, 1 Main St, London, 1
2, 2 Main St, London, 2
3, 3 Main St, London, 1
What you should do is count the number of distinct EmployeeID's. Each of these EmployeeID's identifies a unique employee. Thus your query should look like this:
SELECT COUNT(DISTINCT EmployeeID) AS EmployeeID FROM Address
WHERE City='London';
That will get you the correct answer every time regardless of what your table looks like.
Suppose that we have following tables:
company company_has_employee employee
-------------------------------------------------------------
id company_id id
companzy_name employee_id emplyee_name
How to create SQL Query, which retrieves any two employees, who works for the same company and what is this company?
Assuming juergen d's joins of the table are correct, I will modify the query to
select top 2 company_name, e.employee_name
from compyny c
join company_has_employee ce on ce.company_id = c.id
join employee e on e.id = cs.employee_id
group by company_name
having count(e.id) > 1
This will always return the top 2 employees
juergen d's original query will always return the first and last employees based on their ID.
If you want two employees chosen randomly, then you can try this:
select top 2 company_name, e.employee_name
from compyny c
join company_has_employee ce on ce.company_id = c.id
join employee e on e.id = cs.employee_id
group by company_name
having count(e.id) > 1
order by RAND((e.ID)*DATEPART(millisecond, GETDATE()))
The last order by clause will change the order of records randomly and you will always get the top 2 of a random order...which means 2 random employees will be selected each time the query is run.
select company_name,
min(e.employee_name) as emp1,
max(e.employee_name) as emp2
from compyny c
join company_has_employee ce on ce.company_id = c.id
join employee e on e.id = cs.employee_id
group by company_name
having count(e.id) > 1