How to use Max while taking other values from another column? - sql

I am new in SQL and have problem picking the biggest value of a column for every manager_id and also other information in the same row.
Let me show the example - consider this table:
name
manager_id
sales
John
1
100
David
1
80
Selena
2
26
Leo
1
120
Frank
2
97
Sara
2
105
and the result I am expecting would be like this:
name
manager_id
top_sales
Leo
1
120
Sara
2
105
I tried using Max but the problem is that I must group it with manager_id and not being able to take name of the salesPerson.
select manager_id, max(sales) as top_sales
from table
group by manager_id ;
This is just an example and the actual query is very long and I am taking the information from different tables. I know that I can use the same table and join it again but the problem is as I mentioned this query is very long as I am extracting info from different tables with multiple conditions. And I don't want to make a temporary table to save it. It should be done in one single query and I actually did solve this but the query is super long due to the inner join that I used and made original table twice.
My question is that can I use Max and have the value in the name column or is there other method to solve this?
Appreciate all help

You can use row_number() with CTE to get the highest sales for each manager as below:
with MaxSales as (
select name, manager_id, sales,row_number() over (partition by manager_id order by sales desc) rownumber from table
)
select name , manager_id ,sales from MaxSales where rownumber=1

Related

Combining two mostly identical rows in SQL

I have a table that contains data like below:
Name
ID
Dept
Joe
1001
Accounting
Joe
1001
Marketing
Mary
1003
Administration
Mary
1009
Accounting
Each row is uniquely identified with a combo of Name and ID. I want the resulting table to combine rows that have same Name and ID and put their dept's together separated by a comma in alpha order. So the result would be:
Name
ID
Dept
Joe
1001
Accounting, Marketing
Mary
1003
Administration
Mary
1009
Accounting
I am not sure how to approach this. So far I have this, which doesn't really do what I need:
SELECT Name, ID, COUNT(*)
FROM employees
GROUP BY Name, ID
I know COUNT(*) is irrelevant here, but I am not sure what to do. Any help is appreciated! By the way, I am using PostgreSQL and I am new to the language.
Apparently there is an aggregate function for string concatenation with PostgreSQL. Find documentation here. Try the following:
SELECT Name, ID, string_agg(Dept, ', ' ORDER BY Dept ASC) AS Departments
FROM employees
GROUP BY Name, ID

Order by result of subquery in PostgreSQL

Assuming I have one table Employees with the columns id, name, salary and manager_id
and another table fields with the column field which can be any of the fields in the Employees table.
How can I sort the employees by the rows in the fields table?
For example: when fields contains the values 'salary', 'manager_id', the employees will be sorted by salary and then by manager_id.
I tried something like this but it didn't work:
SELECT * FROM employees ORDER BY (SELECT field FROM fields)
Edit: The original question was a simplified example of my goal.
I want that the employees will be sorted by their super manager id, then by the second super manager id...and in the end by their direct manager’s id.
Given the employees(id, name, salary, manager_id):
1 Alex 1000 NULL
2 Mor 2000 1
3 John 3000 NULL
4 Chris 4000 1
5 Michael 5000 4
6 Matt 6000 2
The query result will be:
1 Alex 1000 NULL
2 Mor 2000 1
6 Matt 6000 2
4 Chris 4000 1
5 Michael 5000 4
3 John 3000 NULL
You cannot do that in a single query.
First you have to query fields, then construct an SQL statement with the proper ORDER BY clause and run that.
Beware of SQL injection — use the format function to construct the query.
If you can tell us the error that it gives you it may help us helping you
what i think is that ' symbols are what making the issue so it will be as if you're writing:
SELECT * FROM employees ORDER BY 'salary', 'parent_id'
try replacing it with a blank character using Replace()
There is a way how this can be accomplished. But i strongly advice to change your design.
To support this you must add SEQ field in your Fields table to decide order of fields in Fields table. First field have SEQ 1, second 2 ...
SELECT
*
FROM
Employees E
ORDER BY
CASE
(SELECT
F.NAME
FROM
Fields F ORDER BY F.SEQ LIMIT 1)
WHEN 'salary' THEN E.salary
WHEN 'parent_id' THEN E.parent_id
ELSE 0 END
,
CASE
(SELECT
F.NAME
FROM
Fields F ORDER BY F.SEQ LIMIT 1 OFFSET 1)
WHEN 'salary' THEN E.salary
WHEN 'parent_id' THEN E.parent_id
ELSE 0 END
sample on sql fiddle to demonstrate. There are two tables FieldsA and FieldsB to make testing easier without need for delete from table Fields and new records to see if it is working.
http://sqlfiddle.com/#!15/64df6e/2/0

Excessive Case Statement Help - SQL Server

I'm supposed to answer this for class, and it's tricky (for me)
Write a SELECT query to output the name of all employees with the name of their supervisor. If the employee has no supervisor, the supervisor name column should contain the text 'No Supervisor'.
The primary key field in my db is the employeeid and they are provided with names, and each student also has a supervisorid
The table for this is shown below (sorry for the layout):
employeeid lastname firstname salary supervisorid
1 Stolz Ted 25000 NULL
2 Boswell Nancy 23000 1
3 Hargett Vincent 22000 1
4 Weekley Kevin 22000 3
5 Metts Geraldine 22000 2
6 McBride Jeffrey 21000 2
7 Xiong Jay 20000 3
I was wondering how I could go about this statement without using the case statement to apply each of the 7 students with:
when concat(firstname,' ',lastname)='Nancy Boswell' then 'Ted Stolz'
In larger tables this would simply be a HUGE statement, is there a better way to do it?
Thanks!
EDIT:
I've now tried this:
SELECT
EMP1.employeeid as 'employee',
EMP2.supervisorid as 'manager'
FROM
employee EMP1
LEFT OUTER JOIN
employee EMP2
ON
emp1.employeeid = emp2.supervisorid;
However, I am seeing duplicate fields, for some reason employee 2 and 3 are appearing twice, meaning there are 9 fields showing instead of 7.
Also, I need to display their names, not their id's does that mean I need to join the join that i've already done to the employee name ? How would I do this?
Thanks for the feedback guys!
You need to link the table with itself based on the supervisorId. This might be strange if you are new to SQL but it is very common to do. You tell with SQL to add the row of the supervisor to the row of the employee via its primary key.
SELECT
*
FROM
EMPLOYEES EMP1
LEFT OUTER JOIN
EMPLOYEES EMP2
ON
-- make link between tables here
Note that the above query is not 100% correct / complete, its an indication. The LEFT OUTER JOIN statement makes the employees without supervisor have null values for the supervisor, otherwise the whole record would be left out.

Alternative to GROUP BY to consolidate repeating values in single column

I'm using DB2 which apparently doesn't let you use the GROUP BY clause when it's returning more than one column. I have records that have repeating values for ID and name, for example:
EmpID | - name - | code
___________________________________
111111 | Williams | 1
---------------------------------
111111 | Williams | 2
----------------------------------
111112 | Davis | 3
---------------------------------
111113 | Gomez | 1
----------------------------------
111113 | Gomez | 3
----------------------------------
(Excuse my formatting) I need to get a single instance of each employee with a code (doesn't matter which code instance gets omitted as long as one shows up per employee).
Normally I could do:
SELECT * FROM employees GROUP BY EmpID;
DB2 doesn't let you do this for some reason. It says " The grouping is inconsistent." You can do:
SELECT EmpID from employees GROUP BY EmpID;
but if you introduce more return values then it gives you the error.
I tried looking into using a subquery and derived tables but I'm not sure how to compose it to select only one code value and exclude the records with a repeating employee value. If anyone has an answer or could point me to another thread that addresses this problem I would appreciate it very much.
It is required in most databases to GROUP BY each column in the SELECT list that is not in an aggregate function that is why you received an error message.
For your situation if it does not matter what code value is returned, then you can use an aggregate function and group by:
SELECT EmpID, name, MIN(code) code
FROM employees
GROUP BY EmpID, name;
See Demo
The group by is applied to both the EmpId and name, while the aggregate function is applied to the code column.
Note that due to that EmpID and name are functionally dependent on each other (as far as we can see from the sample you posted and the "repeating values" comment), the following two queries will return the same, identical results as the above query:
--- GROUP BY EmpID
------------------
SELECT EmpID, MIN(name) name, MIN(code) code
FROM employees
GROUP BY EmpID;
--- GROUP BY name
-----------------
SELECT MIN(EmpID) EmpID, name, MIN(code) code
FROM employees
GROUP BY name;

UPDATE query that fixes orphaned records

I have an Access database that has two tables that are related by PK/FK. Unfortunately, the database tables have allowed for duplicate/redundant records and has made the database a bit screwy. I am trying to figure out a SQL statement that will fix the problem.
To better explain the problem and goal, I have created example tables to use as reference:
alt text http://img38.imageshack.us/img38/9243/514201074110am.png
You'll notice there are two tables, a Student table and a TestScore table where StudentID is the PK/FK.
The Student table contains duplicate records for students John, Sally, Tommy, and Suzy. In other words the John's with StudentID's 1 and 5 are the same person, Sally 2 and 6 are the same person, and so on.
The TestScore table relates test scores with a student.
Ignoring how/why the Student table allowed duplicates, etc - The goal I'm trying to accomplish is to update the TestScore table so that it replaces the StudentID's that have been disabled with the corresponding enabled StudentID. So, all StudentID's = 1 (John) will be updated to 5; all StudentID's = 2 (Sally) will be updated to 6, and so on. Here's the resultant TestScore table that I'm shooting for (Notice there is no longer any reference to the disabled StudentID's 1-4):
alt text http://img163.imageshack.us/img163/1954/514201091121am.png
Can you think of a query (compatible with MS Access's JET Engine) that can accomplish this goal? Or, maybe, you can offer some tips/perspectives that will point me in the right direction.
Thanks.
The only way to do this is through a series of queries and temporary tables.
First, I would create the following Make Table query that you would use to create a mapping of the bad StudentID to correct StudentID.
Select S1.StudentId As NewStudentId, S2.StudentId As OldStudentId
Into zzStudentMap
From Student As S1
Inner Join Student As S2
On S2.Name = S1.Name
Where S1.Disabled = False
And S2.StudentId <> S1.StudentId
And S2.Disabled = True
Next, you would use that temporary table to update the TestScore table with the correct StudentID.
Update TestScore
Inner Join zzStudentMap
On zzStudentMap.OldStudentId = TestScore.StudentId
Set StudentId = zzStudentMap.NewStudentId
The most common technique to identify duplicates in a table is to group by the fields that represent duplicate records:
ID FIRST_NAME LAST_NAME
1 Brian Smith
3 George Smith
25 Brian Smith
In this case we want to remove one of the Brian Smith Records, or in your case, update the ID field so they both have the value of 25 or 1 (completely arbitrary which one to use).
SELECT min(id)
FROM example
GROUP BY first_name, last_name
Using min on ID will return:
ID FIRST_NAME LAST_NAME
1 Brian Smith
3 George Smith
If you use max you would get
ID FIRST_NAME LAST_NAME
25 Brian Smith
3 George Smith
I usually use this technique to delete the duplicates, not update them:
DELETE FROM example
WHERE ID NOT IN (SELECT MAX (ID)
FROM example
GROUP BY first_name, last_name)