Order by result of subquery in PostgreSQL - sql

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

Related

On Statement Self Join

I am having trouble wrapping my head around the on statement when doing a self-join. Let's say we have the following table:
employeeid
name
managerid
salary
1
Mike
3
35000
2
Rob
1
45000
3
Todd
NULL
25000
4
Ben
1
55000
5
Sam
1
65000
I want to perform a self join to return the employee name and their manager's name.
When I perform the following self join I get an incorrect result:
SELECT E.name as Employee,M.name as Manager
FROM tblEmployees E
LEFT JOIN tblEmployees M
ON E.Employeeid=M.managerid
However, when I reverse the columns on the on statement using the query below:
SELECT E.name as Employee,M.name as Manager
FROM tblEmployees E
LEFT JOIN tblEmployees M
ON E.managerid=M.Employeeid
I get the correct answer.
Why? How do I know which columns to select in an on statement?
Here's my explanation:
The table you have is structured with each row representing an employee in the company.
You are interested in determining who is each employee's manager.
You are able to find that by joining the table on itself where the lookup values are the manager ids (managerid) and the reference column are the employee ids (employeeid).
The first query is wrong because the employeeid column is being used for the lookup values and the managerid column is being used for reference.
To get the manager of each employee you need to look use the managerid column as the lookup column and the employeeid column as the reference column.
Hope that's not too confusing!

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

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

What does 1 and 2 with HAVING clause mean in SQL query in Oracle?

I created an employee table having attributes : deptno and salary in Oracle DBMS.
I executed this query :
SELECT deptno, SUM(salary)
FROM emp
GROUP BY deptno
HAVING 1 > 2 ;
I thought that 1 and 2 are referring to the columns "deptno" and "SUM(salary)" in the SELECT statement.
So I put a record where "deptno" > "SUM(salary)" in the table as follows:
deptno salary
1001 5000
1002 1000
The output is "No rows found"
I was expecting the second row as output.
Kindly explain the reason.
1 and 2 is a number. 1 > 2 always returns false. HAVING 1 > 2 means that no matter how many rows in your database, it will always return no rows. It is like you are running while(false) { ... }.
You can use 1 or 2 in ORDER BY to specified which column number to order by. (http://docs.oracle.com/javadb/10.6.2.1/ref/rrefsqlj13658.html), but not with HAVING.
On side note, because you can use column number in ORDER BY, you shouldn't use it. It is not a good practice. Let say that you adding and remove how many column you select. The position of the field you want to order will be adjust. It is better for you to specified it by its name or by its alias. It is more readable as well for other developer to read your code.
Here 1 & 2 are referred as integers rather than column names. Hence it always gives false values. What you want to do can be done by
Select deptno,sum(salary)
From emp
Group by deptno
Having deptno>sum(salary);

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.

MS Access VBA: Combine 2 SQL statements with a LEFT JOIN

Hi all and thanks in advance for your help!
I am trying to use a JOIN to combine a fitlered SQL statement with a table in order to populate a combobox (makes sense?)
Here is the main SQL query:
MainSQLquery = "SELECT QuotationID, QuoteDate, EmployeeID FROM TestTable1"
I want to write a statement to use this with another table like so:
SELECT EmployeeID, EmployeeName
FROM MainSQLquery LEFT JOIN EmployeeTable
GROUP BY EmployeeID
But I can't get it right. I get a "Syntax error in FROM clause" even with something as simple as:
ComboSQL = "SELECT EmployeeID FROM " & MainSQLQuery
Me.Combo2.RowSource = ComboSQL
Do you guys know any way to do this?
*******BACKGROUND**********
For those of you who wants to see the bigger picture, I have a subform showing a list of quotations and based on a dynamic SQL statement, it is filetered with a WHERE clause based on different inputs and it looks like this when displayed:
QuoteID Quote date Employee ID
1 10/13 1
2 10/13 2
3 10/13 2
4 09/18 1
5 08/10 2
6 07/16 3
7 06/27 3
On the main form, I have comboboxes that I use to filter this subform, which works perfectly. But I also need my comboboxes to be filtered the same way as the subform content and without having any duplicate (that's the only thing I can't do right now).
So far I use the same filtered SQL query for the subform and all the comboboxes, so instead of having a neat Employee combobox that looks like this (with the example above):
1
2
3
I get that instead (same as the subform):
1
2
2
1
2
3
3
My idea is to have a main SQL query for the subform, and another SQLquery based on the main one for the comboboxes, something like that:
SELECT EmployeeID, EmployeeName
FROM MainSQLquery LEFT JOIN EmployeeTable
GROUP BY EmployeeID
if I could get this working, the filter would still be built in the mainSQL and I could group the EmployeeID field without problem.
I guess it should be fairly simple, but I can't get it right, there is something I don't know about using an SAL as source of another.
(I wish I could post pictures or a database sample, but a paranoid guy got my previous post deleted because of that, so it will have to do with text only, sorry about that)
When you have a JOIN you should have an ON to let the database know how to relate the tables:
SELECT EmployeeID, EmployeeName
FROM (
SELECT QuotationID, QuoteDate, EmployeeID
FROM TestTable1
) AS MainSQLquery LEFT JOIN EmployeeTable
ON MainSQLquery.EmployeeID = EmployeeTable.ID
GROUP BY EmployeeID
The LEFT JOIN gets all records from the table on the left of the join -- MainSQLquery -- and only the records from the right table -- EmployeeTable -- that match. If no matches are found in the right table, a NULL value is returned.
Given this example:
TestTable1
QuotationID | QuoteDate | EmployeeID
--------------------------------------------
1 10/1/2014 1
2 10/8/2014 2
3 10/5/2014 3
4 10/10/2014 1
5 10/20/2014 5
EmployeeTable
ID | EmployeeName
----------------------
1 Jeremy Smith
2 Pam Engles
3 Achim Flemmish
4 Sandra Hayes
This would be the result of the above query:
Result
EmployeeID | EmployeeName
--------------------------------
1 Jeremy Smith
2 Pam Engles
3 Achim Flemmish
5 NULL