I have this table:
id mgr_id sal
1 5 5000
2 5 6000
3 6 7000
4 6 8000
I expect this output:
id mgr_id sal MaX_sal
1 5 5000 6000
2 5 6000 6000
3 6 7000 8000
4 6 8000 8000
Based on mgr_id select max sal and print in front of id.
Thanks in advance.
Possible would be a subselect inside the select (although a bit slow as all subselects are):
select id, mgr_id, sal, (select max(sal) from mytable n2
where n2.mgr_id = mytable.mgr_id) as max_sal from mytable
Create a subtable grouping by mrg_id to get the max Sal per mrg_id and then left join it with the principal table on mrg_id -- Try this :
declare #table table (id int,mrg_id int,sal decimal(10,0))
insert into #table
select 1, 5, 5000 union all
select 2, 5, 6000 union all
select 3, 6, 7000 union all
select 4, 6, 8000
/***** change #table with your table name *****/
SELECT
t.id,
t.mrg_id,
t.sal,
t1.max_sal
FROM #table t
LEFT JOIN
(SELECT
mrg_id,
MAX(sal) max_sal
FROM #table
group by
mrg_id) t1
on t.mrg_id=t1.mrg_id
This would work even in SQL Server 6.5
SELECT id, mgr_id, sal,
(
SELECT MAX(sal)
FROM employees mgr
WHERE mgr.mgr_id = emp.mgr_id
) AS max_sal
FROM
employees emp
This works on SQL Server 2005:
WITH max_sals AS
(
SELECT mgr_id, MAX(sal) AS max_sal
FROM employees
GROUP BY mgr_id
)
SELECT emp.*, max_sals.max_sal
FROM
employees emp
LEFT JOIN max_sals
ON emp.mgr_id = max_sals.mgr_id
and this using partiton:
SELECT emp.*, MAX(emp.sal) OVER (PARTITION BY emp.mgr_id) AS max_sal
FROM employees emp
Sample data and table:
CREATE TABLE employees
(
id int,
mgr_id int,
sal int
)
INSERT INTO employees VALUES
(1,5,5000),
(2,5,6000),
(3,6,7000),
(4,6,8000)
With SQL Server 2012 simply use this query:
SELECT d.id, d.mgr_id, d.sal, MAX(sal) over(partition by mgr_id)
FROM #data d
You can use this query with SQL Server <2012:
SELECT d.id, d.mgr_id, d.sal, m.mx
FROM #data d
INNER JOIN (
SELECT mgr_id, mx = MAX(sal) FROM #data
GROUP BY mgr_id
) m
ON m.mgr_id = d.mgr_id;
Another option with SQL Server >= 2005:
SELECT d.id, d.mgr_id, d.sal, m.mx
FROM #data d
CROSS APPLY (SELECT mx = MAX(sal) FROM #data m WHERE m.mgr_id = d.mgr_id) m(mx)
Sample data:
Declare #data table([id] int, [mgr_id] int, [sal] int);
INSERT INTO #data([id], [mgr_id], [sal])
VALUES
(1, 5, 5000),
(2, 5, 6000),
(3, 6, 7000),
(4, 6, 8000)
;
Try Cross Apply,
SELECT id,
mgr_id,
sal,
Max_sal
FROM #your_table A
CROSS APPLY (SELECT Max(SAL) AS Max_sal
FROM #your_table B
WHERE B.mgr_id = A.mgr_id)cs
Related
How can I modify the CTE below to INSERT rows into a new table T.
Based on the output below for table T I should have 4 rows for employee_id =1, 1 row for employee_id=3 and
2 rows for employee_id=7
CREATE TABLE T
(seq_num integer GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
employee_id NUMBER(6));
CREATE TABLE employees (
employee_id NUMBER(6)
);
INSERT INTO employees
(employee_id)
VALUES (1);
INSERT INTO employees
(employee_id)
VALUES (3);
INSERT INTO employees
(employee_id)
VALUES (7);
with rws as (
select level rn
from dual
connect by level <= 5
), emps as (
select /*+
materialize */e.*,
round (
dbms_random.value(1,5) ) n
from employees e
)
select employee_id, count (*) rw_count
from rws
join emps e
on rn <= n
group by employee_id
Order by employee_id;
EMPLOYEE_ID RW_COUNT
1 4
3 1
7 2
Just don't use group by. It's almost untouched your query, I only added insert and removed aggregation:
insert into t (employee_id)
with rws as ( select level rn from dual connect by level <= 5 ),
emps as ( select e.*, round (dbms_random.value(1,5) ) n from employees e )
select employee_id
from rws
join emps e on rn <= n
order by employee_id;
dbfiddle
I have sample result set :
declare #Emp Table (Emp_Name VARCHAR(10),Dept_name VARCHAR(10),Subjects VARCHAR(10),Score VARCHAR(10))
Insert into #EMP(Emp_Name,Dept_name,Subjects,Score)VALUES ('MOHAN','LANGUAGES','English',35)
Insert into #EMP(Emp_Name,Dept_name,Subjects,Score)VALUES ('MOHAN','LANGUAGES','TELUGU',35)
Insert into #EMP(Emp_Name,Dept_name,Subjects,Score)VALUES ('MOHAN','SCIENCE','BIOLOGY',35)
Insert into #EMP(Emp_Name,Dept_name,Subjects,Score)VALUES ('MOHAN','SCIENCE','PHYSICS',35)
Insert into #EMP(Emp_Name,Dept_name,Subjects,Score)VALUES ('MOHAN','SOCIAL','ECONOMICS',35)
Insert into #EMP(Emp_Name,Dept_name,Subjects,Score)VALUES ('MOHAN','SOCIAL','CIVICS',35)
Insert into #EMP(Emp_Name,Dept_name,Subjects,Score)VALUES ('MOHAN','SOCIAL','ECONOMICS',35)
Sample Data :
Emp_Name Dept_name Subjects Score
MOHAN LANGUAGES English 35
MOHAN LANGUAGES TELUGU 35
MOHAN SCIENCE BIOLOGY 35
MOHAN SCIENCE PHYSICS 35
MOHAN SOCIAL ECONOMICS 35
MOHAN SOCIAL CIVICS 35
MOHAN SOCIAL ECONOMICS 35
Need to compare entire table data with each column data :
Select COUNT(*) ALL_COl FROM (
select Emp_Name,Dept_name,Subjects,Score from #Emp )T
Select Count(*) Without_Subject_Col FROM (
select DISTINCT Emp_Name,Dept_name,Score from #Emp)TT
Select count(*) Without_Dept_Col from (
select DISTINCT Emp_Name,Subjects,Score from #Emp )TTT
Select COUNT(*) Without_Dept_Subject_Col from (
select DISTINCT Emp_Name,Score from #Emp )TTTT
How can I get the output like this :
ALL_COL Without_Subject_Col Without_Dept_Col Without_Dept_Subject_Col
7 3 6 1
Suggest me the way how to achieve it
You could just OUTER APPLY the counts?
select top 1 a.ALL_COl,
aa.Without_Subject_Col,
aaa.Without_Dept_Col,
aaaa.Without_Dept_Subject_Col
from #EMP e
outer apply
(Select COUNT(*) ALL_COl FROM (
select Emp_Name,Dept_name,Subjects,Score from #Emp )T ) A
outer apply
(Select Count(*) Without_Subject_Col FROM (
select DISTINCT Emp_Name,Dept_name,Score from #Emp)TT ) AA
outer apply
(Select count(*) Without_Dept_Col from (
select DISTINCT Emp_Name,Subjects,Score from #Emp )TTT)AAA
outer apply
(Select COUNT(*) Without_Dept_Subject_Col from (
select DISTINCT Emp_Name,Score from #Emp )TTTT)AAAA
Just select the counts as sub-queries
SELECT
(
SELECT COUNT(*) FROM #Emp
) AS ALL_Col,
(
SELECT COUNT(*)
FROM (SELECT DISTINCT Emp_Name, Dept_name, Score FROM #Emp) q
) AS Without_Subject_Col,
(
SELECT COUNT(*)
FROM (SELECT DISTINCT Emp_Name, Subjects, Score FROM #Emp) q
) AS Without_Dept_Col,
(
SELECT COUNT(*)
FROM (SELECT DISTINCT Emp_Name, Score FROM #Emp) q
) AS Without_Dept_Subject_Col;
A test on rextester here
No idea why you want this but using count with distinct makes this pretty simple.
Select ALL_COL = COUNT(*)
, Without_Subject_Col = Count(DISTINCT Emp_Name + Dept_name + convert(varchar(5), Score))
, Without_Dept_Col = count(distinct Emp_Name + Subjects + convert(varchar(5), Score))
, Without_Dept_Subject_Col = count(distinct Emp_Name + convert(varchar(5), Score))
from #Emp
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;
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)
I tried
INSERT INTO my_test_one (rollno,name, sirname, Dept)
(select rollno_seq.nextval,'name1','sirname1', Dept
FROM my_test_one_backup
WHERE dept = 500
UNION ALL
select rollno_seq.nextval,'name1','sirname1', Dept
FROM my_test_one_backup
WHERE dept = 501 );
While doing this I am getting the error
Error report:
SQL Error: ORA-02287: sequence number not allowed here
02287. 00000 - "sequence number not allowed here"
Don't use a UNION but a single SELECT and OR in this case:
SELECT rollno_seq.nextval,'name1','sirname1', Dept
FROM my_test_one_backup
WHERE dept = 500 OR dept = 501
Try:
INSERT INTO my_test_one
(rollno, name, sirname, Dept)
SELECT rollno_seq.nextval,
name1,
sirname1,
dept
FROM (select 'name1' as name1,'sirname1' as sirname1, Dept
FROM my_test_one_backup
WHERE dept = 500
UNION ALL
select 'name1','sirname1', Dept
FROM my_test_one_backup
WHERE dept = 501 );
Edit: Better still, use an OR like CodeBrickie says or and IN statement.
WHERE dept IN (500, 501);
Edit2:
Currently you are selecting 'name1', 'sirname1' as literals so each row returned will insert the next sequence number, 'name1', 'sirname1' and whatever the value of DEPT column is.
If your table has columns called name1 and sirname1 then you'll need to remove the single quotes (and you wouldn't need the column alias either) e.g.:
INSERT INTO my_test_one
(rollno, name, sirname, Dept)
SELECT rollno_seq.nextval,
name1,
sirname1,
dept
FROM (select name1, sirname1, Dept
FROM my_test_one_backup
WHERE dept = 500
UNION ALL
select name1, sirname1, Dept
FROM my_test_one_backup
WHERE dept = 501 );
Or
INSERT INTO my_test_one
(rollno, name, sirname, Dept)
SELECT rollno_seq.nextval,
name1,
sirname1,
dept
FROM my_test_one_backup
WHERE dept IN (500, 501);
You can't use a sequence in unioned selects, so you'll need to put the union in a sub-query and the sequence in the outer query:
INSERT INTO my_test_one (rollno,name, sirname, Dept)
select rollno_seq.nextval, name1, sirname1, dept
from (SELECT 'name1' as name1,'sirname1' as sirname1, Dept
FROM my_test_one_backup
WHERE dept = 500
UNION ALL
SELECT 'name1','sirname1', Dept
FROM my_test_one_backup
WHERE dept = 501 );
You should also note that, in SQL, double quotes indicate an object name and single quotes denote a string, so 'name1' and 'sirname1' will be static strings, not column references.