How to get order by with inner query - sql

I am new to sql, can any one please help me with getting ordered data from the internal query
select
*
from emp
where id
(select order from department where name = 'testing' order by order asc).
I am getting order data from the inner query and with the id's I get I should get the result from the emp table to be in the same order of inner query. Can anyone help me with this. TIA.

If it's reasonable to re-write your query as a join:
select e.*
from emp e
inner join department d
on e.id = d.order
where d.name = 'testing'
order by d.order asc
Where this would change your results is if there are multiple rows in department with the same order value matching one or more rows in emp - in which case this query will return multiple rows, whereas the original would not. But if such a condition doesn't apply, then this is the query I'd recommend.

Damien's answer is quite cool and perfect. but if you still want to go with subquery then try this
select *
from emp
where id in (select order from department where name = 'testing' order by order asc)
order by id asc
May this help you

This will give the right number of rows in case there more than 1 match between emp.id and department.order
select * from emp e
where exists
(select 1 from department d where d.name = 'testing'
and e.id = d.order1) -- order is a reserved word in several sql languages
order by id
It seems there is something funny going on between your tables. Would would department contain any information about emp(I assume it is employee table) ?

There is no guarantee that there is an actual temporary table with the inner query and that it is sorted and processed in a certain way. However, you can sort the outer query by emp.id.
select * from emp where id in
(select order from department where name = 'testing')
order by id asc

select e.* from emp as e, department d where e.id=d.order and d.name='testing' order by d.order

Related

Not able to Fetch data, Using where clause to the result of union clause

I Need to fetch data form two tables from the result i get from union clause and to the result i have one more where clause added
select * from (select a.empid,a.department from EMPLOYEE a
union
select b.empid,b.empname from employeedetails b) t where a.empid=1;
I am getting this error.
a is not defined in the outer query. t is:
where t.empid = 1;
This UNION won't do what you want because you are mixing different columns.
In your case the result of your query will be 2 rows where in the 1st row you will have the employee's id and the department and in the 2nd row the employee's id and name.
What you need is a join:
select e.empid, e.department, d.empname
from EMPLOYEE e inner join employeedetails d
on d.empid = e.empid
where e.empid = 1

Get Limited Records For Sub Query Each Result

I am trying to query some data from SQL Server 2012 using sub query. I am trying to get first 3 records for each Id returned by Sub Query but I am not getting the idea how to do so for now I write this query:
Select * from Student Where TeacherId in (Select TeacherId from Teacher)
I am not sure if this is achievable by using such query or do I have to write a function or any thing else ?
Any Suggestions would be great and sorry for my bad explanation skills.
You should join the Teacher to Student table, and then use an analytic function to get the first there records for each teacher:
SELECT *
FROM
(
SELECT
s.*, t.TeacherId, t.TeacherName,
ROW_NUMBER() OVER (PARTITION BY t.TeacherId ORDER BY some_col) rn
FROM Teacher t
INNER JOIN Student s
ON t.TeacherId = s.TeacherId
) t
WHERE rn = 3;
I assume that there is a column in one of the two tables some_col which you want to use for ordering. It does not make much sense to speak of the first three records without also defining some ordering.
I guess you want the top 3 rows for each ids, not top 3 rows for entire result set
WITH CTE AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY t.TeacherId ORDER BY ?) Seq
FROM Student s
INNER JOIN Teacher t ON t.TeacherId = s.TeacherId
)
SELECT * FROM CTE
WHERE Seq between 1 AND 3
? placeholder requires column_name to generate the sequence_number to get the result with boundary of 1 to 3 .

history gives me too many subquery results

I appreciate your help, I hope I'm able to provide adequate information.
I need to roll back owners associated with quite a few entries in our asset table (one owner got applied to a lot of systems). I have a history table with the information I need, and an employee table that gets wedged in there because for some reason the history table stores names rather than employee_id's.
Source data:
asset_table has asset_id, employee_id, asset_tag
employee_table has employee_id, name
history_table has asset_id, old_name, new_name
update asset_table
set employee_id = (select employee_id
from employee_table
where name like (select old_name
from history_table
where asset_table.asset_id=history_table.asset_id
and new_name like 'tobe replaced'))
However, the subquery turns up more than one result per line.
What am I missing to limit that subquery results?
MSSQL server 2012
I guess you need someone who was the last in history:
update at set
employee_id = e.employee_id
from asset_table at
cross apply
(
select top (1)
h.old_name
from history_table h
where at.asset_id = h.asset_id
and h.new_name = 'tobe replaced'
order by h.<date or id or something> desc
) h
inner join employee_table e
on e.name = h.old_name
TOP 1 will fix "more than one result" problem.
Note, LIKE without % works exactly the same way as =.
You can write update statement is as below by using JOIN instead of sub query, Provide table structure and data for more correct query:
update at set at.employee_id = et.employee_id
from asset_table at
inner join history_table ht on at.asset_id = ht.asset_id
and ht.new_name like '%tobe replaced%'
inner join employee_table et on et.name = ht.old_name
and et.employee_id = at.employee_id

How to get the value of max() group when in subquery?

So i woud like to find the department name or department id(dpmid) for the group that has the max average of age among the other group and this is my query:
select
MAX(avg_age) as 'Max average age' FROM (
SELECT
AVG(userage) AS avg_age FROM user_data GROUP BY
(select dpmid from department_branch where
(select dpmbid from user_department_branch where
user_data.userid = user_department_branch.userid)=department_branch.dpmbid)
) AS query1
this code show only the max value of average age and when i try to show the name of the group it will show the wrong group name.
So, How to show the name of max group that has subquery from another table???
You may try this..
select MAX(avg_age) as max_avg, SUBSTRING_INDEX(MAX(avg_age_dep),'##',-1) as max_age_dep from
(
SELECT
AVG(userage) as avg_age, CONCAT( AVG(userage), CONCAT('##' ,department_name)) as avg_age_dep
FROM user_data
inner join user_department_branch
on user_data.userid = user_department_branch.userid
inner join department_branch
on department_branch.dpmbid = user_department_branch.dpmbid
inner join department
on department.dpmid = department_branch.dpmid
group by department_branch.dpmid
) tab_avg_age_by_dep
;
I've done some change on ipothesys that the department name is placed in a "department" anagraphical table.. so, as it needed put in join a table in plus, then I changed your query, eventually if the department name is placed (but I don't thing so) in the branch_department table you can add the field and its treatment to your query
update
In adjunct to as said, if you wanto to avoid identical average cases you can furtherly make univocal the averages by appending a rownum id in this way:
select MAX(avg_age) as max_avg, SUBSTRING_INDEX(MAX(avg_age_dep),'##',-1) as max_age_dep from
(
SELECT
AVG(userage) as avg_age, CONCAT( AVG(userage), CONCAT('##', CONCAT( #rownum:=#rownum+1, CONCAT('##' ,department_name)))) as avg_age_dep
FROM user_data
inner join user_department_branch
on user_data.userid = user_department_branch.userid
inner join department_branch
on department_branch.dpmbid = user_department_branch.dpmbid
inner join department
on department.dpmid = department_branch.dpmid
,(SELECT #rownum:=0) r
group by department_branch.dpmid
) tab_avg_age_by_dep
;
I took a shot at what I think you are looking for. The following will give you the department branch with the highest average age. I assumed the department_branch table had a department_name field. You may need an additional join to get the department.
SELECT db.department_name, udb.dpmid, AVG(userage) as `Average age`
FROM user_data as ud
JOIN user_department_branch as udb
ON udb.userid = ud.userid
JOIN department_branch as db
ON db.dpmbid = udb.dpmbid
GROUP BY udb.dpmid
ORDER BY `Average age` DESC
LIMIT 1

Select specific columns from two tables

Suppose I have two tables tblEmployee and tblEmpSalary. I need to write a SQL statement to get a list of all employees, their name and salary, who receive the highest salary in each department.
Sample table data is here:
You could use ranking functions in this case:
WITH ranked AS (
SELECT
e.*,
s.monSalary,
rnk = RANK() OVER (PARTITION BY e.strDepartment ORDER BY s.monSalary DESC)
FROM tblEmplopyee e
INNER JOIN tblEmpSalary s ON e.intEmployeeID = s.intEmployeeID
)
SELECT
intEmploeeID,
strEmpName,
strDepartment,
monSalary
FROM ranked
WHERE rnk = 1
The RANK() function will do if you only need those who's got the topmost salary. With RANK(), the query may return more than employee per department if they have the same salary.
Alternatively, you can use DENSE_RANK() instead of RANK(), with the same effect, but DENSE_RANK() would also allow you to get employees with top n salaries. (You would be able to specify that in the WHERE condition like this:
WHERE rnk <= n
)
If, however, you need exactly one employee per department, even if there are several of them matching the requirement, use ROW_NUMBER() instead of RANK(). But then you'll probably need to add another criterion to the ORDER BY clause of the ranking function, e.g. like this:
... ORDER BY s.monSalary DESC, e.strEmpName ASC)
In fact, ROW_NUMBER() would simply make your query employee-oriented rather than salary-oriented. With ROW_NUMBER(), you would be able to have your query return top n most-paid employees, using the same condition as with DENSE_RANK():
WHERE rnk <= n
You can read more about ranking functions in SQL Server on MSDN:
Ranking Functions (Transact-SQL)
SELECT e.strEmpName, s.monSalary
FROM tblEmployee e
JOIN tblEmpSalary s ON e.intEmployeeID = s.intEmployeeID
WHERE e.strDepartment + '-' + CAST(s.monSalary AS varchar(20)) IN (
SELECT e2.strDepartment + '-' + CAST(MAX(s2.monSalary) AS varchar(20))
FROM tblEmployee e2
JOIN tblEmpSalary s2 ON e2.intEmployeeID = s2.intEmployeeID
GROUP BY e2.strDepartment)
Disclaimer: I can't test this query right now, so it could have some small detail wrong.
SELECT a.d, a.m, b.strEmpName
FROM (
SELECT strDepartment d, MAX(monSalary) m
FROM (
SELECT *
FROM tblEmployee e
LEFT JOIN tblEmpSalary s ON e.inEmployeeID = s.intEmployeeID
)
GROUP BY strDepartment
) a
LEFT JOIN (
SELECT *
FROM tblEmployee e
LEFT JOIN tblEmpSalary s ON e.inEmployeeID = s.intEmployeeID
) b ON a.d=b.strDepartment AND a.m=b.M
SELECT tblEmployee.strEmpName, max_salaries.strDepartment, max_salaries.salary
FROM (SELECT tblEmployee.strDepartment, MAX(monSalary)
FROM tblEmployee INNER JOIN tblEmpSalary
ON tblEmployee.intEmployeeID = tblEmpSalary.intEmployeeID
GROUP BY tblEmployee.strDepartment) max_salaries
INNER JOIN tblEmployee ON tblEmployee.strDepartment = max_salaries.strDepartment
INNER JOIN tblEmpSalary ON tblEmpSalary.monSalary = max_salaries.salary
AND tblEmpSalary.intEmployeeID = tblEmployee.intEmployeeID
In case of two or more employees with equal max salaries - this will return all of them for the specified department.