Order by clause with union in SQL select query - sql

Is there a way to order the union of two select all statements based on table column values.
My sample code is:
SELECT * FROM emp WHERE mgr='7839'
UNION
SELECT * FROM emp WHERE NOT EXISTS (SELECT * FROM emp WHERE mgr='7839')
AND empno='7839'
order by ename;
This code is showing error as:invalid identifier 'ENAME'.
I am not using specific columns in select statement instead of * since there are more than 10 columns in the table and the code looks so big.
But ename is a column in emp.

will you consider small change in your query.
SELECT * FROM
(SELECT * FROM emp WHERE mgr='7839'
UNION
SELECT * FROM emp WHERE NOT EXISTS (SELECT * FROM emp WHERE mgr='7839')
AND empno='7839') AA
order by AA.ename;

Why would use use union for this? Just do:
SELECT e.*
FROM emp e
WHERE e.mgr = '7839' OR
(NOT EXISTS (SELECT 1 FROM emp e2 WHERE e2.mgr = '7839') AND
empno = '7839'
)
ORDER BY ename;

Related

Use Output of Oracle SQL Function in WHERE condition of SQL query

I wrote a Oracle SQL Function that will return EMP IDs in the following format.
Query: select CUSFNC_GETEMPID('HIGH-RATED') from dual;
Output: ('1436','1444','1234')
I want to use this Output in SQL Query as follows:
SELECT ID, NAME, SAL
FROM EMP
WHERE ID IN CUSFNC_GETEMPID('HIGH-RATED')
I am expecting this query returns records with IDs equal to values mentioned in the above query.
But it is not working as expected.
How to achieve this by modifying output of function or any other way?
You could use a join instead of a IN clause
SELECT ID, NAME, SAL
FROM EMP
inner join (
select CUSFNC_GETEMPID('HIGH-RATED') hrated from dual;
) t on t.hrated = emp.id
and could be that your emp.id is a number so you should convert to char
SELECT ID, NAME, SAL
FROM EMP
inner join (
select CUSFNC_GETEMPID('HIGH-RATED') hrated from dual;
) t on t.hrated = to_char(emp.id)
You can use a PIPELINED TABLE FUNCTION, like this:
CREATE FUNCTION CUSFNC_GETEMPID(param1 varchar2) RETURN DBMSOUTPUT_LINESARRAY PIPELINED AS
BEGIN
FOR a_row IN
(
-- YOUR SQL WHICH RETURNS ROWS WITH ID VALUES HERE...
SELECT id
FROM
(
SELECT '1' id, 'HIGH-RATED' col FROM dual UNION
SELECT '2' id, 'HIGH-RATED' col FROM dual UNION
SELECT '3' id, 'LOW-RATED' col FROM dual
)
WHERE col = param1 -- FILTER BASED ON INPUT PARAM...
)
LOOP
PIPE ROW(a_row.id); -- PUT THE ID COLUMN HERE...
END LOOP;
END;
/
And then call it in your SQL like this:
SELECT ID, NAME, SAL
FROM EMP
WHERE ID IN (SELECT column_value FROM TABLE(CUSFNC_GETEMPID('HIGH-RATED')))
SELECT ID, NAME, SAL
FROM EMP
WHERE ID IN (SELECT CUSFNC_GETEMPID('HIGH-RATED')AS ID FROM DUAL)

how to get second highest salary department wise without using analytical functions?

Suppose we have 3 employees in each department.we have total 3 departments . Below is the sample source table
Emp deptno salary
A 10 1000
B 10 2000
C 10 3000
D 20 7000
E 20 9000
F 20 8000
G 30 17000
H 30 15000
I 30 30000
Output
B 10 2000
F 20 8000
G 30 17000
With using analytic function dense_rank we can achive the second highest salary dept wise.
Can we achieve this without using ANY analytic function ???
Is Max() is also analytic function ??
It is a pain, but you can do it. The following query gets the second highest salary:
select t.deptno, max(t.salary) as maxs
from table t
where t.salary < (select max(salary)
from table t2
where t2.deptno = t.deptno
)
group by t.deptno;
You can then use this to get the employee:
select t.*
from table t join
(select t.deptno, max(t.salary) as maxs
from table t
where t.salary < (select max(salary)
from table t2
where t2.deptno = t.deptno
)
group by t.deptno
) tt
on t.deptno = tt.deptno and t.salary = tt.maxs;
Create table and insert dummy data
CREATE TABLE #Employee
(
Id Int,
Name NVARCHAR(10),
Sal int,
deptId int
)
INSERT INTO #Employee VALUES
(1, 'Ashish',1000,1),
(2,'Gayle',3000,1),
(3, 'Salman',2000,2),
(4,'Prem',44000,2)
Query to get result
;WITH cteRowNum AS (
SELECT *,
DENSE_RANK() OVER(PARTITION BY deptId ORDER BY Sal DESC) AS RowNum
FROM #Employee
)
SELECT *
FROM cteRowNum
WHERE RowNum = 2;
This will give you 2nd highest salary in each department:
SELECT a.Emp, a.deptno, a.salary
FROM Emp a
WHERE 1 = (SELECT COUNT(DISTINCT salary)
FROM Emp b
WHERE b.salary > a.salary AND a.deptno = b.deptno)
group by a.deptno
Solution using Correlated Subquery:
SELECT * FROM emp e1 WHERE 2 = (SELECT COUNT(DISTINCT sal)
FROM emp e2
WHERE e1.sal <= e2.sal
AND e1.deptno = e2.deptno
);
Quite straightforward and declarative, but slow
select
t1.*
from
#tmp t1
inner join #tmp h1 on h1.dept = t1.dept and h1.emp <> t1.emp
left outer join #tmp h2 on h2.dept = h1.dept and h2.salary > h1.salary
left outer join #tmp t2 on t1.dept = t2.dept and t2.salary > t1.salary and t2.emp <> h1.emp
where
t2.emp is null and h2.emp is null
You can find 2nd highest salary something like this:
select max(a.Salary),a.Deptno from Employee a join (select MAX(salary) salary
from Employee group by Deptno) b on a.Salary < b.salary group by a.Deptno
And no MAX() is not an analytic function.
Reference
On MySQL this how you can get second highest salary, given table name is salaries:
By Nested Queries: (where you can change offset 0/1/2 for first, second and third place respectively)
select
*
from
salaries as t1
where
t1.salary = (select
salary
from
salaries
where
salaries.deptno = t1.deptno ORDER by salary desc limit 1 offset 1);
or might be by creating rank: (where you can change rank= 1/2/3 for first, second and third place respectively)
SET #prev_value = NULL;
SET #rank_count = 0;
select * from
(SELECT
s.*,
CASE
WHEN #prev_value = deptno THEN #rank_count := #rank_count + 1
WHEN #prev_value := deptno THEN #rank_count := 1
ELSE #rank_count := 1
END as rank
FROM salaries s
ORDER BY deptno, salary desc) as t
having t.rank = 2;
SQL Query:
select TOP 2 max(salary),Emp from EMployee where deptno='your_detpno'
Very simple logic.
Please try:
SELECT dept as dd, ( SELECT ee.salary FROM `employees` as ee WHERE ee.dept=dd
ORDER BY ee.salary DESC LIMIT 1,1 ) as sndHigh
FROM `employees`
WHERE 1
GROUP BY dept
select min(salary),deptno from
(SELECT distinct top 2 salary,deptno from table ORDER BY salary DESC)
as a
group by deptno
CREATE TABLE Employee
([Name] varchar(1), [Dept] varchar(1), [Salary] int)
;
INSERT INTO Employee
([Name], [Dept], [Salary])
VALUES
('a', 'M', 20),
('b', 'M', 25),
('c', 'M', 30),
('d', 'C', 44),
('e', 'C', 45),
('f', 'C', 46),
('g', 'H', 20)

How to select alternative rows from table in sql?

In table there is a column named status which can have either 1 or 2.
Now I want to select pattern like this
First Row 1
Second Row 2
Third Row 1
Fourth Row 2
......
For even rows
select * from emp where rowid%2 = 0;
For odd rows
select * from emp where rowid%2 != 0;
MS SQL:
select t1.*, (RN % 2)+1 as [STATUS] from
(
select t.*, ROW_NUMBER() OVER (ORDER BY <ORDER COLUMN NAME HERE>) as RN
) t1
Oracle:
SELECT * from
( SELECT a1.*,rank() over (partition BY status order by rownum) RNK FROM TABLE1 a1
)
ORDER BY rnk,status
Sqlfiddle:
try this
select * from (select table.* ,rownum k from table) where mod(k,2)<>0;
Try This:
SELECT e1.* FROM Employee e1
INNER JOIN
(
Select e2.*, ROW_NUMBER() OVER (ORDER BY <Column Names>) AS RN FROM Employee e2
)E2
ON e1.eid=e2.eid
where e2.RN%2=0
TO Get ODD records use following:
SELECT e1.* FROM Employee e1 INNER JOIN
( Select e2.*, ROW_NUMBER() OVER (ORDER BY ) AS RN FROM Employee e2 )E2 ON e1.eid=e2.eid where e2.RN%2=1

Top 10 results on rows obtained by UNION

I am using MSSQL 2005 for a query, say:
SELECT * from Emp UNION ALL SELECT * from Emp2;
And I want to limit the final result to 10 rows.
IF I had only the Emp table, I would say
SELECT TOP 10 * from Emp;
But since I have 2 tables now, I can't say SELECT TOP * on any of them, neither I can use LIMIT 10 in the end.
Do you have any suggestion?
SELECT TOP 10 * FROM
(SELECT * from Emp UNION ALL SELECT * from Emp2) a
However, I would suggest maybe you order the results so that you don't just get top 10 results from first union result. So something like this maybe:
SELECT TOP 10 * FROM
(SELECT * from Emp UNION ALL SELECT * from Emp2) a
ORDER BY a.lastName
try this:
SELECT TOP 10 *
FROM (
SELECT *
FROM Emp
UNION ALL
SELECT *
FROM Emp2
) derivedTable
try this:
SELECT top 10 * from (
SELECT * from Emp UNION ALL SELECT * from Emp2) a
Make the UNIONed query a subquery, and SELECT the TOP 10 rows from that:
SELECT TOP 10 * FROM (
SELECT * FROM Emp
UNION ALL
SELECT * FROM Emp2
) unioned

Join two sql queries side by side with no column common

I need to join the results of two queries horizontally.
Consider a query below which will return two rows:
Select *
from Salary
where sal > 10000
The result of the query above should be joined side by side with the result of the query below which will again return two rows.Or I need to just concatenate the two result sets:
Select 'xyz' from dual
union
Select 'abc' from dual
Please suggest how this can be done as I tried to do this with the query below but it returns a cartesian product:
Select *
from (Select *
from salary
where sal > 10000) TEMP1,
(Select 'xyz' from dual
union
Select 'abc' from dual) TEMP2
You can do that by joining on rownum like this:
SELECT *
FROM
(SELECT view_name, rownum AS r FROM all_views WHERE rownum <=10)
FULL OUTER JOIN (SELECT table_name, rownum AS r FROM all_tables WHERE rownum <=10) USING (r)
In your case this would look like (untested):
Select * from
(Select salary.*, rownum AS r from salary where sal>10000) TEMP1
FULL OUTER JOIN
(SELECT temp2.*, rownum r FROM
(Select 'xyz' from dual
union
Select 'abc' from dual) TEMP2)
USING (r)
you can introduce an artificial join column:
SELECT *
FROM (SELECT s.*, ROWNUM ID FROM Salary s WHERE sal > 10000) q1
JOIN (SELECT 'xyz' col1, 1 ID
FROM dual
UNION
SELECT 'abc' col1, 2 ID FROM dual) q2 ON q1.id = q2.id
Thank you very much for your help.
But what I need is a bit complicated. I have updated the previous query to be somewhat like below instead of simple query that I posted before (SELECT * FROM Salary WHERE sal > 10000):
SELECT name, sal, address
FROM (SELECT e1.name, s1.sal, s1.grade, s2.address FROM Emp e1, salary s1,
(Select empcode, address FROM Address WHERE empcode LIKE 'NY%') s2
WHERE e1.hiredate =201001
AND s1.sal>10000)
I know the above query does not make much of a relevance. However, this is similar to what I need actually. I am not posting the original one as that is very complicated but if this can be done for this query, then I will be able to replicate the same on the original one as well.
Thank you,
Sharon