Sum of multiple union select showing every result and total - sql

My SQL shows the count of records in multiple tables
SELECT 'S_MH_DSC_Abandoned' Table_N ,COUNT(*) Count FROM S_MH_DSC_Abandoned
UNION SELECT 'S_MH_DSC_ExclAbandoned' Table_N, COUNT(*) Count FROM S_MH_DSC_ExclAbandoned
UNION SELECT 'S_MH_Private_All' Table_N, COUNT(*) Count FROM S_MH_Private_All
I want to show this plus the total of the values in the last column as above.
I have tried
Select 'Sum Total' Table_N, sum(a) as Total from
(
SELECT 'S_MH_DSC_Abandoned',COUNT(*) a FROM S_MH_DSC_Abandoned
UNION SELECT 'S_MH_DSC_ExclAbandoned', COUNT(*) a FROM S_MH_DSC_ExclAbandoned
UNION SELECT 'S_MH_Private_All', COUNT(*) a FROM S_MH_Private_All
)
But only get the total without the other values.
How can I get both the working counts and the total?
This is using QGIS flavour of SQL - https://sqlite.org/lang.html

I don't use SQLite.
However, reviewing its documentation, it looks as if it doesn't know ROLLUP (which comes handy in such a case):
SQL> with temp (job, sumsal) as
2 (select 'Clerk', sum(sal) from emp where job = 'CLERK' union all
3 select 'Mgr' , sum(sal) from emp where job = 'MANAGER' union all
4 select 'Sale' , sum(sal) from emp where job = 'SALESMAN'
5 )
6 select job, sum(sumsal) sumsal
7 from temp
8 group by rollup (job);
JOB SUMSAL
----- ----------
Clerk 4150
Mgr 8275
Sale 5600
18025
SQL>
Therefore, simulate it with a union:
SQL> with temp (job, sumsal) as
2 (select 'Clerk', sum(sal) from emp where job = 'CLERK' union all
3 select 'Mgr' , sum(sal) from emp where job = 'MANAGER' union all
4 select 'Sale' , sum(sal) from emp where job = 'SALESMAN'
5 )
6 select job, sumsal
7 from temp
8 union
9 select 'Total', sum(sumsal)
10 from temp;
JOB SUMSAL
----- ----------
Clerk 4150
Mgr 8275
Sale 5600
Total 18025
SQL>
Using your query:
with temp (tname, cnt) as
(SELECT 'S_MH_DSC_Abandoned' , COUNT(*) FROM S_MH_DSC_Abandoned union all
SELECT 'S_MH_DSC_ExclAbandoned', COUNT(*) FROM S_MH_DSC_ExclAbandoned union all
SELECT 'S_MH_Private_All' , COUNT(*) FROM S_MH_Private_All
)
select tname, cnt
from temp
union
select 'Total', sum(cnt)
from temp;

Related

Write a query to display departno and no of employee which departno have max employee.?

Write a query to display departno and no of employee which departno have max employee.?
Here I tried out following query:
select deptno, count(*) as no_of_emp
from emp
group by deptno
order by no_of_emp;
but I was getting as
Deptno no_of_emp
30 6
20 4
10 4
But I just need first row not all. Is it possible to display only first record in oracle sql?
You may use ROWNUM
select * from
(
select deptno, count(*) as no_of_emp
from emp
group by deptno
order by no_of_emp desc
) where rownum = 1;
Or in 12c and above, FETCH..FIRST
select deptno, count(*) as no_of_emp
from emp
group by deptno
order by no_of_emp desc fetch first 1 ROWS ONLY
As an alternative you might use max(count(*)) over (order by ...) analytic function with descending count option :
with emp( empno,ename,deptno ) as
(
select 7839,'KING',10 from dual union all
select 7698,'BLAKE',30 from dual union all
select 7782,'CLARK',10 from dual union all
select 7566,'JONES',20 from dual union all
select 7788,'SCOTT',20 from dual union all
select 7902,'FORD',20 from dual union all
select 7369,'SMITH',20 from dual union all
select 7499,'ALLEN',30 from dual union all
select 7521,'WARD',30 from dual union all
select 7654,'MARTIN',30 from dual union all
select 7844,'TURNER',30 from dual union all
select 7876,'ADAMS',20 from dual union all
select 7900,'JAMES',30 from dual union all
select 7934,'MILLER',10 from dual
)
select deptno, no_of_emp
from
(
select deptno, count(*) as no_of_emp,
max(count(*)) over (order by count(*) desc) as max_populated
from emp
group by deptno
order by no_of_emp
)
where max_populated = no_of_emp;
DEPTNO NO_OF_EMP
------ ---------
30 6
Rextester Demo
Although what you are trying to achieve is can be done by other sql queries changing yo ur query as below will work:
SELECT * from (select deptno, count(*) as no_of_emp
from emp
group by deptno
order by no_of_emp desc) where rownum<=1
;
other query is as follows:
select deptno, count(*) as no_of_emp
from emp
group by deptno
having count(*)=(select max(count(*)) as no_of_emp
from emp
group by deptno)
order by no_of_emp desc;

Write a Query to show Id, Name and No. of department?

I am trying to write a Query to show Id, Name and No. of department in given Table which are referring more than one department.
ID Name Department
-- ---- ----------
1 Sam HR
1 Sam FINANCE
2 Ron PAYROLL
3 Kia HR
3 Kia IT
Result :
ID Name Department
-- ---- ----------
1 Sam 2
3 Kia 2
I tried using group by id and using count(*), but query is giving error.
How can I do this?
Without seeing your query, a blind guess is that you wrongly wrote the GROUP BY clause (if you used it) and forgot to include the HAVING clause.
Anyway, something like this might be what you're looking for:
SQL> with test (id, name, department) as
2 (select 1, 'sam', 'hr' from dual union
3 select 1, 'sam', 'finance' from dual union
4 select 2, 'ron', 'payroll' from dual union
5 select 3, 'kia', 'hr' from dual union
6 select 3, 'kia', 'it' from dual
7 )
8 select id, name, count(*)
9 from test
10 group by id, name
11 having count(*) > 1
12 order by id;
ID NAM COUNT(*)
---------- --- ----------
1 sam 2
3 kia 2
SQL>
You were right about using count(). You need to group by other columns though and only count unique departments then filter on the number in having clause.
select id, name, count(distinct department) as no_of_department
from table
group by id, name
having count(distinct department) > 1
This can also be done using analytic functions like below:
select *
from (
select id, name, count(distinct department) over (partition by id, name) as no_of_department
from table
) t
where no_of_department > 1
You can use window function with subquery :
select distinct id, name, Noofdepartment
from (select t.*, count(*) over (partition by id,name) Noofdepartment
from table t
) t
where Noofdepartment > 1;
However, you can also use group by clause:
select id, name, count(*) as Noofdepartment
from table t
group by id, name
having count(*) > 1;

Find the employee with max salary in his department

Table structure is as below
id dept salary
1 30 2000
2 20 5500
3 30 6700
4 30 8900
5 30 9900
6 10 1120
7 20 8900
8 10 2400
9 30 2600
10 10 2999
I need the output to have two columns:
Id and Salary
Id should be unique and salary should have the max salary
Although data structure is a bit strange, the query below will give the desired result:
create table #tmp(
id numeric(10,0),
dept int,
salary numeric(10,0))
insert #tmp select 1, 30, 2000
insert #tmp select 2, 20, 5500
insert #tmp select 3, 30, 6700
insert #tmp select 4, 30, 8900
insert #tmp select 5, 30, 9900
insert #tmp select 6, 10, 1120
insert #tmp select 7, 20, 8900
insert #tmp select 8, 10, 2400
insert #tmp select 9, 30, 2600
insert #tmp select 10, 10, 2999
select * from #tmp order by dept
id dept salary
------------ ----------- ------------
6 10 1120
8 10 2400
10 10 2999
2 20 5500
7 20 8900
1 30 2000
9 30 2600
3 30 6700
4 30 8900
5 30 9900
select id, salary
from #tmp t1, (select dept=dept, salaryMax=max(salary) from #tmp group by dept) t2
where t1.dept = t2.dept
and t1.salary = t2.salaryMax
id salary
------------ ------------
7 8900
10 2999
5 9900
SELECT ID,Salary FROM TABLE_NAME WHERE SALARY =(SELECT MAX(SALARY) FROM TABLE_NAME)
SELECT a.Id, a.Salary
FROM table a
WHERE a.Salary = (SELECT MAX(Salary) FROM table
WHERE Id = a.Id)
select * from (select * from dep order by salary desc, dep, id) t
group by t.dep
Use NOT EXISTS to return an epmloyee if no other within same department has a higher salary.
select * from table t1
where not exists (select 1 from table t2
where t2.dept = t1.dept
and t2.salary > t1.salary)
Core SQL-99, will work with both Oracle and Sybase!
Alternative solution:
select * from table
where (dept, salary) = (select dept, max(salary)
from table
group by dept)
Using the following feature outside Core SQL-2003: F641, "Row and table constructors". (Don't know what Sybase and Oracle supports here...)
Using single scan:
WITH SALARIES AS (
SELECT 1 ID, 30 DEPT, 2000 SALARY FROM DUAL UNION ALL
SELECT 2 ID, 20 DEPT, 5500 SALARY FROM DUAL UNION ALL
SELECT 3 ID, 30 DEPT, 6700 SALARY FROM DUAL UNION ALL
SELECT 4 ID, 30 DEPT, 8900 SALARY FROM DUAL UNION ALL
SELECT 5 ID, 30 DEPT, 9900 SALARY FROM DUAL UNION ALL
SELECT 6 ID, 10 DEPT, 1120 SALARY FROM DUAL UNION ALL
SELECT 7 ID, 20 DEPT, 8900 SALARY FROM DUAL UNION ALL
SELECT 8 ID, 10 DEPT, 2400 SALARY FROM DUAL UNION ALL
SELECT 9 ID, 30 DEPT, 2600 SALARY FROM DUAL UNION ALL
SELECT 10 ID, 10 DEPT, 2999 SALARY FROM DUAL
)
SELECT
MAX(ID) KEEP (DENSE_RANK LAST ORDER BY SALARY) ID,
MAX(SALARY) SALARY
FROM
SALARIES
GROUP BY
DEPT;
All the below three queries worked :
select t.dept, t.salary
from
(select dept,max(salary) as m_sal from tempdb..test
group by dept)x, tempdb..test t
where x.dept = t.dept
and x.m_sal = t.salary
select dept, id, salary as m_sal
from tempdb..test t1
where salary = (select max(salary) from tempdb..test t2 where t2.dept = t1.dept)
select t1.dept,t1.salary from tempdb..test t1
inner join
(select dept,max(salary) as m_sal from tempdb..test
group by dept)x on
t1.salary=x.m_sal and
t1.dept=x.dept

Aggregate and concatenate strings without duplication

I want to aggregate strings and concatenate them. This is example of what I am using
SELECT deptno, LISTAGG(ename, ',') WITHIN GROUP (ORDER BY ename) AS employees
FROM emp
GROUP BY deptno;
DEPTNO EMPLOYEES
---------- --------------------------------------------------
10 CLARK, CLARK,KING,MILLER, MILLER
20 ADAMS, ADAMS, ADAMS, FORD,JONES,SCOTT,SMITH
30 ALLEN,BLAKE,JAMES,MARTIN,MARTIN,TURNER,WARD
3 rows selected.
But I want results without duplication in concatenated strings.
Desired results:
DEPTNO EMPLOYEES
---------- --------------------------------------------------
10 CLARK,KING,MILLER
20 SMITH,FORD,ADAMS,SCOTT,JONES
30 ALLEN,BLAKE,MARTIN,TURNER,JAMES,WARD
3 rows selected.
EDIT: so in example below there are some "Employeer names with comma". It is using the proposed answer with regular expression:
with emp as (
select 10 as deptno, 'clark,1' as ename from dual
union all
select 10, 'clark,1' from dual
union all
select 10, 'clark,1' from dual
union all
select 10, 'bob' from dual
union all
select 10, 'bob' from dual
union all
select 10, 'don' from dual
union all
select 20, 'tim,2' from dual
union all
select 20, 'tim,2' from dual
union all
select 20, 'tim,2' from dual
union all
select 20, 'jack' from dual
union all
select 20, 'mark' from dual
)
SELECT e.deptno, --LISTAGG(e.ename, ',') WITHIN GROUP (ORDER BY e.ename) AS employees,
RTRIM(REGEXP_REPLACE(listagg (e.ename, ',')
WITHIN GROUP (ORDER BY e.ename),
'([^,]+)(,\1)+', '\1'),
',') AS employees
FROM emp e
GROUP BY e.deptno;
The results of this query are not correct:
Replace
FROM emp
with
FROM (SELECT DISTINCT deptno, ename FROM emp)
(From a non-Oracle user, but it should work)
You can use REGEX:
SELECT deptno,
rtrim( regexp_replace( (Listagg(ename,',') within GROUP (ORDER BY ename) OVER ()), '([^-]*)(-\1)+($|-)', '\1\3'), '-') within GROUP (ORDER BY ename) AS employees
FROM emp
GROUP BY deptno;
Here's a method using crossjoin
SELECT DISTINCT deptno,
b.enames
FROM emp a
cross join (SELECT Listagg(ename, '-')
within GROUP (ORDER BY ename) enames
FROM (SELECT DISTINCT enam ename
FROM emp)) b
Let me know if they work

How to count across all levels in PIVOT query?

How can I calculate count for all the levels in PIVOT query? E.g. this counts across ename and job, but how to calculate count for all job levels, not just for CLERK, SALESMAN and MANAGER?
with pivot_data as (
select ename, job
from scott.emp
)
select * from pivot_data
pivot (count(*) for job in('CLERK', 'SALESMAN', 'MANAGER'));
To include all jobs without listing them explicitly in the IN clause of the PIVOT, besides dynamic sql, you can use PIVOT XML and rewrite the query as follows:
-- sample of data
with t1(col) as(
select 'CLERK' from dual union all
select 'SALESMAN' from dual union all
select 'MANAGER' from dual
)
select col_xml
from t1
pivot xml(
count(*) for col in(select col from t1)
)
XML Result:
COL_XML
--------------------------------------------------------------------------------
<PivotSet><item><column name = "COL">CLERK</column><column name = "COUNT(*)">1</
column></item><item><column name = "COL">MANAGER</column><column name = "COUNT(*
)">1</column></item><item><column name = "COL">SALESMAN</column><column name = "
COUNT(*)">1</column></item></PivotSet>
But then, to get the friendly representation of data you will have to explicitly extract the values:
SQL> with t1(col) as(
2 select 'CLERK' from dual union all
3 select 'SALESMAN' from dual union all
4 select 'MANAGER' from dual
5 )
6 select extractvalue(col_xml,'/PivotSet/item[1]/column[2]') col_1
7 , extractvalue(col_xml,'/PivotSet/item[2]/column[2]') col_2
8 , extractvalue(col_xml,'/PivotSet/item[3]/column[2]') col_3
9 from ( select col_xml
10 from t1
11 pivot xml(
12 count(*) for col in(select col from t1)
13 )
14 )
15 ;
Result:
COL_1 COL_2 COL_3
-----------------
1 1 1
SQLFiddle Demo