Count of one of the columns - sql

Let's say I have the dataset that looks like:
col1 col2 col3
a 2 20
a 3 12
a 4 34
b 2 44
c 3 23
c 5 13
....
What I want is a count of col1.
Output:
col1 col2 col3 count
a 2 20 3
a 3 12 3
a 4 34 3
b 2 44 1
c 3 23 2
c 5 13 2
.......
I know I can do by:
with cte as (
select col1, count(*) count
from tab1)
select a.col1,a.col2,a.col3,cte.count
from tab1
join cte on a.col1=cte.col1
But is there any other I can do that without cross apply or cte?
Also, assuming there are more than 3 letters in col1, so I couldn't use sum function either:
SUM(CASE WHEN ItemID = 'a' THEN 1 ELSE 0 END) AS count_a

If you're using SQL Server 2008+, you can use COUNT() OVER():
SELECT *,
COUNT(*) OVER(PARTITION BY col1)
FROM tab1
ONLINE DEMO

Related

How to convert rows into columns in oracle into particular set of columns?

I have a table in which there are 2 columns. I want to convert the rows into sets of 4 columns.
For example, the table I have:
Column1
Column2
1
N
2
N
3
N
4
N
5
N
I want to transpose them as:
Column1
Columnn2
Column3
Column4
1
2
3
4
5
N
N
N
N
N
How can I do this in Oracle?
Thanks for the help!
Here's one option; read comments within code.
SQL> with
2 test (col1, col2) as
3 -- sample data
4 (select 1, 'N' from dual union all
5 select 2, 'N' from dual union all
6 select 3, 'N' from dual union all
7 select 4, 'N' from dual union all
8 select 5, 'N' from dual
9 ),
10 temp as
11 -- union of two columns will produce a single-column "table"
12 (select to_char(col1) col from test union all
13 select col2 from test
14 ),
15 temp2 as
16 -- ordinal numbers for each row
17 (select col,
18 row_number() over (order by null) rn
19 from temp
20 ),
21 temp3 as
22 -- a little bit of calculation so that you'd be able to create groups of 4 columns
23 (select col,
24 mod(rn, 4) rn,
25 ceil(rn / 4) grp
26 from temp2
27 )
28 -- final query
29 select max(case when rn = 1 then col end) col1,
30 max(case when rn = 2 then col end) col2,
31 max(case when rn = 3 then col end) col3,
32 max(case when rn = 0 then col end) col4
33 from temp3
34 group by grp;
COL1 COL2 COL3 COL4
----- ----- ----- -----
1 2 3 4
5 N N N
N N
SQL>

PostgreSQL unnest(array_agg(x))

Lets say we have a table 1
1 2 3
a x 10
a y 20
b z 50
As result of the select we want to get the following:
1 2 3
a x 30
a y 30
b z 50
At least the sum of the lines where column 1 is equal. I do the following select and it is working. But the select looks ugly, is there a smarter solution?
SELECT 1, UNNEST(ARRAY_AGG(2)), SUM(3) FROM table1
GROUP BY (1)
You can do a window sum instead:
select col1, col2, sum(col3) over(partition by col1) col3
from mytable

SQL Group by fixed list of values

If I have two columns:
col1 col2 amount
1 2 15
2 3 12
1 3 10
3 1 4
3 2 3
And I perform a group by col1,col2 then I get a row for each combination (present) in the data.
My problem though is, that I dont always have all combinations, but I would want to return a row of each combination still. So if there isn't a combination. for example 2 -> 1 then I would want its value to be 0.
Can I somehow specify the "levels" of the group by?
I'm using SQL Oracle.
and the outcome I would want is:
1 -> 2 15
1 -> 3 10
2 -> 1 0
2 -> 3 12
3 -> 1 4
3 -> 2 3
With their respective amount, and 0 if they dont exist, or null works. ( I have a filter to exclude where col1 and col2 are same)
Generate all the rows using cross join and then filter for the ones you want:
select c1.col1, c2.col2, coalesce(t.amount, 0)
from (select 1 as co1l from dual union all
select 2 as co1l from dual union all
select 3 as co1l from dual
) c1 cross join
(select 1 as co12 from dual union all
select 2 as co12 from dual union all
select 3 as co12 from dual
) c2 left join
t
on t.col1 = c1.col1 and t.col2 = c2.col2
where c1.col1 <> c2.col2;

Count records in query in groups based on column value

Let's suppose a have a very simple query in SQL
SELECT Col1,Col2 From Table1
and it gives me result:
Col1 Col2
A 5
A 7
A 2
B 1
B 1
B 4
B 0
C 4
C 1
C 2
I want to count rows in groups made by Col1 and in order made by Col2. If values in Col2 for some rows in group are equal then they should have different numbers, as shown in example
So I want to have
Col1 Col2 Nr
A 5 2
A 7 3
A 2 1
B 0 1
B 1 2
B 1 3
B 4 4
C 4 3
C 1 1
C 2 2
Any ideas how to make it?
If your database supports window functions, use ROW_NUMBER
select col1,col2,row_number() over(partition by col1 order by col2) as nr
from tablename
If your database doesn't support window functions, use
select col1,col2,
(select count(*)+1 from tablename t1 where t1.col1=t.col1 and t1.col2<t.col2) as nr
from tablename t
You can use the row_number window function:
SELECT col1,
col2,
ROW_NUMBER() OVER (PARTITION BY col1 ORDER BY col2 ASC) AS Nr
FROM table1
ORDER BY 1, 2, 3

Query without Union operator SQL

TABLE X
col1,col2
1 , 2
1 , 7
1 , 4
1 , 8
2 , 3
2 , 1
2 , 2
3 , 1
3 , 8
3 , 9
3 , 4
4 , 5
4 , 3
4 , 2
4 , 8
4 , 4
I want to retrieve the col1 values that contains in the col2 the values 2 and 4
in this case it will retrieve the values 1 and 4
How can i accomplish this without using the UNION ALL operator ?
The query that i am using is
select distinct col1
from X as A
where col1 = (
select col1 from (
select distinct col1
from X as B
where A.col1 = B.col1 and col2 = 2
union ALL
select distinct col1
from X as C
where A.col1 = C.col1 and col2 = 4
) D
group by col1
having count(col1) > 1
)
It is returning the correct result but i guess is to performance expensive.
Can anyone give me ideas about how to achieve the same result but without unions ?
This problem is called Relational Division, here is one way to do so:
SELECT col1
FROM tablex
WHERE col2 IN (2, 4)
GROUP BY col1
HAVING COUNT(DISTINCT col2) >=2
The HAVING COUNT(col2) >=2 will ensure that the selected col1 must have both the two values 2 and 4 at least.
SQL Fiddle Demo
I think the best performance will come from inner joining the table with itself:
SELECT DISTINCT X1.col1
FROM X X1 INNER JOIN X X2 ON X1.col1=X2.col1
WHERE X1.col2=2 AND X2.col2=4