SQL Server Counting - sql

I have the following query:
select col1, sum( col2 ), count( col3 )
from table1
group by col1
order by col1
which returns something like this
col1
dept1
dept2
dept3
col2
10
20
30
col3
2
3
4
Without a stored procedure, is it possible to get a total column below the results generated by the original query?
i.e.
col1
dept1
dept2
dept3
total
col2
10
20
30
60
col3
2
3
4
9

use ROLLUP:
;with Table1 as (
select 'dept1' as col1, 5 as col2,1 as col3
union all
select 'dept1', 5 as col2, 1 as col3
union all
select 'dept2',10,1
union all
select 'dept2',5,1
union all
select 'dept2',5,1
union all
select 'dept3',10,1
union all
select 'dept3',5,1
union all
select 'dept3',5,1
union all
select 'dept3',10,1
)
select COALESCE(col1,'total'), sum( col2 ), count( col3 )
from table1
group by col1
with rollup
order by COALESCE(col1,'ZZZZZ')
Results:
(No column name) (No column name) (No column name)
dept1 10 2
dept2 20 3
dept3 30 4
total 60 9

Have a look at the keyword WITH ROLLUP on your GROUP BY clause

yep:
select col1, sum(col2), count(col3)
from table1
group by col1
union all
select 'totals', sum(col2), count(1) from table1
order by col1

Related

Sql Query for Unique and Duplicates in oracle sql?

I need to display unique records in one column and duplicates in another column in Oracle?
COL1 COL2
1 10
1 10
2 20
3 30
3 30
unique in one set duplicate in one set
col1 col2 col1 col2
2 20 1 10
1 10
3 30
3 30
You can use the group by for both cases with the having clause:
Unique records
select *
from table as t
inner join (
select col1, col2, count(*) as times
from table
group by col1, col2
having count(*) = 1) as t2 ON t.col1 = t2.col2 and t.col2 = t2.col2
Duplicate records:
select *
from table as t
inner join (
select col1, col2, count(*) as times
from table
group by col1, col2
having count(*) > 1) as t2 ON t.col1 = t2.col1 and t.col2 = t2.col2
Would something like this do? See comments within code.
SQL> with
2 test (col1, col2) as
3 -- sample data
4 (select 1, 10 from dual union all
5 select 1, 10 from dual union all
6 select 2, 20 from dual union all
7 select 3, 30 from dual union all
8 select 3, 30 from dual
9 ),
10 uni as
11 -- unique values
12 (select col1, col2
13 from test
14 group by col1, col2
15 having count(*) = 1
16 ),
17 dup as
18 -- duplicate values
19 (select col1, col2
20 from test
21 group by col1, col2
22 having count(*) > 1
23 )
24 -- the final result
25 select u.col1 ucol1,
26 u.col2 ucol2,
27 d.col1 dcol1,
28 d.col2 dcol2
29 from uni u full outer join dup d on u.col1 = d.col1;
UCOL1 UCOL2 DCOL1 DCOL2
---------- ---------- ---------- ----------
1 10
3 30
2 20
SQL>
You can identify the duplicate values using window functions, and then filter each query. Then to get unique records:
select col1, col2
from (select t.*, count(*) over (partition by col1) as cnt
from t
) t
where cnt = 1;
To get duplicates:
select col1, col2
from (select t.*, count(*) over (partition by col1) as cnt
from t
) t
where cnt > 1;

SQL Order of execution when DISTINCT and AVG are present in the same SELECT statement

I'm using Oracle 11g. In what order will this SQL statement be "parsed"?
Assuming there are many duplicate values in col2:
SELECT DISTINCT col1, AVG(col2)
FROM table1
GROUP BY col1
Will it:
1. remove all the duplicate col1-col2 data combination, and then do an average on col2 on this reduced resultset, OR
2. do an aggregate average on col2 first, and then do a distinct on this resultset?
An exampe should be self-explanatory:
SQL> create table testDistinct (col1, col2) as(
2 select 1, 100 from dual union all
3 select 1, 10 from dual union all
4 select 1, 10 from dual union all
5 select 2, 50 from dual union all
6 select 3, 1 from dual union all
7 select 3, 100 from dual
8 );
Table created.
SQL> select col1, avg(col2)
2 from testDistinct
3 group by col1;
COL1 AVG(COL2)
---------- ----------
1 40
2 50
3 50,5
SQL> select DISTINCT col1, avg(col2)
2 from testDistinct
3 group by col1;
COL1 AVG(COL2)
---------- ----------
1 40
2 50
3 50,5
Applying the GROUP over the result of a DISTINCT gives:
SQL> select col1, avg(col2)
2 from (
3 select DISTINCT col1, col2
4 from testDistinct
5 )
6 group by col1;
COL1 AVG(COL2)
---------- ----------
1 55
2 50
3 50,5

how to get the maximum occurrence value from a table for a combination?

I have the following table;
column 1 column 2 column 3
1 2 X
1 2 X
1 2 Y
1 3 Z
1 3 X
I need to write an SQL query to get the output as;
1 2 X (because X is the maximum occurrence)
1 3 Z or X(because number of occurrence of Z or X is same)
How do i do this ?
I think i have a solution for you, try this script using the functions RANK(), ROW_NUMBER() & DENSE_RANK(), you choose the function that fits with your needs :
with temp as (
select 1 as col1, 2 AS col2, 'X' as col3 union all
select 1 as col1, 2 AS col2, 'Y' as col3 union all
select 1 as col1, 2 AS col2, 'X' as col3 union all
select 1 as col1, 3 AS col2, 'Z' as col3 union all
select 1 as col1, 3 AS col2, 'T' as col3 union all
select 1 as col1, 3 AS col2, 'Y' as col3 union all
select 1 as col1, 3 AS col2, 'Y' as col3 union all
select 1 as col1, 4 AS col2, 'Y' as col3 union all
select 1 as col1, 4 AS col2, 'W' as col3)
,temp2 AS (
select
col1
,col2
,col3
,COUNT(1) nb_occurence
,RANK() OVER(PARTITION BY col1,col2 ORDER BY COUNT(1) DESC) Ordre_RANK
,ROW_NUMBER() OVER(PARTITION BY col1,col2 ORDER BY COUNT(1) DESC) Ordre_ROW_NUMBER
,DENSE_RANK() OVER(PARTITION BY col1,col2 ORDER BY COUNT(1) DESC) Ordre_DENSE_RANK
from temp
GROUP BY
col1
,col2
,col3 )
SELECT *
FROM temp2
--WHERE Ordre_RANK = 1
--WHERE Ordre_ROW_NUMBER = 1
--WHERE Ordre_DENSE_RANK = 1
I hope this will help you.

Select records where all rows have same value in two columns

Here is my sample table
Col1 Col2
A 1
B 1
A 1
B 2
C 3
I want to be able to select distinct records where all rows have the same value in Col1 and Col2. So my answer should be
Col1 Col2
A 1
C 3
I tried
SELECT Col1, Col2 FROM Table GROUP BY Col1, Col2
This gives me
Col1 Col2
A 1
B 1
B 2
C 3
which is not the result I am looking for. Any tips would be appreciated.
Try this out:
SELECT col1, MAX(col2) aCol2 FROM t
GROUP BY col1
HAVING COUNT(DISTINCT col2) = 1
Output:
| COL1 | ACOL2 |
|------|-------|
| A | 1 |
| C | 3 |
Fiddle here.
Basically, this makes sure that amount the different values for col2 are unique for a given col1.
Try this:
SELECT * FROM MYTABLE
GROUP BY Col1, Col2
HAVING COUNT(*)>1
For example SQLFiddle here
you can try either of the below -
select col1, col2 from
(
select 'A' Col1 , 1 Col2
from dual
union all
select 'B' , 1
from dual
union all
select 'A' ,1
from dual
union all
select 'B' ,2
from dual
)
group by col1, col2
having count(*) >1;
OR
select col1, col2
from
(
select col1, col2, row_number() over (partition by col1, col2 order by col1, col2) cnt
from
(
select 'A' Col1 , 1 Col2
from dual
union all
select 'B' , 1
from dual
union all
select 'A' ,1
from dual
union all
select 'B' ,2
from dual
)
)
where cnt>1;

SQL Query Select first rank 1 row From Multiple ranks/Group

I have following data
Table1
id col1 col2 col3
----------------------------------
1 abc 01/01/2012 -
1 abc 01/01/2012 A
2 abc 01/01/2012 -
2 abc 01/02/2012 -
3 abc 01/02/2012 -
3 xyz 01/01/2012 -
4 abc 01/02/2012 -
4 xyz 01/01/2012 -
4 xyz 01/02/2012 -
following is order to evaluate -
if(col1 is false) then evaluate col2 if(col2 is false) then col3:
Col1 - xyz has first preference from all values in this column
col2 - min date
col3 - not '-' or min(col3)
I want to return only one row for each id, if col1 fails go to col2, if this fails then go to col3 condition.
From above table result should be
id col1 col2 col3
----------------------------------
1 abc 01/01/2012 A
2 abc 01/01/2012 -
3 xyz 01/01/2012 -
4 xyz 01/01/2012 -
I tried using dense rank but it didn't help. I'm not sure how to perform this logic using any available function or sql logic.
for col1 - if more than one row for same code or xyz code then fail
for col2 - if more than one row with same min date then fail
[use this only if col1 condition fails]
You can specify many conditions to order by in your analytic function
SELECT *
FROM (SELECT id,
col1,
col2,
col3,
dense_rank() over (partition by id
order by (case when col1 = 'xyz'
then 1
else 0
end) desc,
col2 asc,
col3 asc) rnk
FROM your_table)
WHERE rnk = 1
I'm assuming that you want dense_rank given that you used the dense_rank tag. You don't talk about how you want to handle ties or whether ties are even possible, so it's not clear from the question itself whether you want to use the rank, dense_rank, or row_number analytic functions. If you are only ever fetching the highest ranking row per id, rank and dense_rank will behave identically and will return multiple rows if there are ties for first place. row_number will always return a single row by arbitrarily breaking the tie. If you want to fetch rows other than the first row per id, then you'll need to think about ties and you'll get different behavior from rank and dense_rank. If two rows are tied for first, dense_rank will assign the third row a rnk of 2 while rank will assign it a rnk of 3.
This seems to work for the sample data you posted
SQL> ed
Wrote file afiedt.buf
1 with x as (
2 select 1 id, 'abc' col1, to_date('01/01/2012', 'MM/DD/YYYY') col2, null col3 from dual union all
3 select 1 id, 'abc' col1, to_date('01/01/2012', 'MM/DD/YYYY') col2, 'A' col3 from dual union all
4 select 2 id, 'abc' col1, to_date('01/01/2012', 'MM/DD/YYYY') col2, null col3 from dual union all
5 select 2 id, 'abc' col1, to_date('01/02/2012', 'MM/DD/YYYY') col2, null col3 from dual union all
6 select 3 id, 'abc' col1, to_date('01/02/2012', 'MM/DD/YYYY') col2, null col3 from dual union all
7 select 3 id, 'xyz' col1, to_date('01/01/2012', 'MM/DD/YYYY') col2, null col3 from dual union all
8 select 4 id, 'abc' col1, to_date('01/02/2012', 'MM/DD/YYYY') col2, null col3 from dual union all
9 select 4 id, 'xyz' col1, to_date('01/01/2012', 'MM/DD/YYYY') col2, null col3 from dual union all
10 select 4 id, 'xyz' col1, to_date('01/02/2012', 'MM/DD/YYYY') col2, null col3 from dual
11 )
12 SELECT *
13 FROM (SELECT id,
14 col1,
15 col2,
16 col3,
17 dense_rank() over (partition by id
18 order by (case when col1 = 'xyz'
19 then 1
20 else 0
21 end) desc,
22 col2 asc,
23 col3 asc) rnk
24 FROM x)
25* WHERE rnk = 1
SQL> /
ID COL COL2 C RNK
---------- --- --------- - ----------
1 abc 01-JAN-12 A 1
2 abc 01-JAN-12 1
3 xyz 01-JAN-12 1
4 xyz 01-JAN-12 1
with tmp(id, col1, col2, col3, col1b, col3b) as
(select distinct id, col1, col2, col3,
case when col1 = 'xyz' then '0' else '1' || col1 end,
case when col3 = '-' then '1' else '0' || col3 end
from Table1)
select t1.id, t1.col1, t1.col2, t1.col3
from tmp t1
left join tmp t2 on t1.id = t2.id
and t1.col1b > t2.col1b
left join tmp t3 on t1.id = t3.id
and t1.col1b = t3.col1b
and t1.col2 > t3.col2
left join tmp t4 on t1.id = t4.id
and t1.col1b = t4.col1b
and t1.col2 = t4.col2
and t1.col3b > t4.col3b
where t2.id is null
and t3.id is null
and t4.id is null