This question already has answers here:
Count based on condition in SQL Server
(4 answers)
Closed 4 years ago.
Stuck in group by clause.
Col1 Col2
----------------
1 1
1 2
2 1
3 3
4 2
5 4
2 3
I want count of Col2 such that Col2 value is 1:
The output expected is:
Col1 Count(Col2)
---------------------
1 1
2 1
3 0
4 0
5 0
;with
d as (
select * from (values
(1, 1),
(1, 2),
(2, 1),
(3, 3),
(4, 2),
(5, 4),
(2, 3)) x (Col1, Col2)
)
select distinct d1.Col1, isnull(cnt, 0) cnt
from d d1
left join (
select Col1, COUNT(Col2) cnt
from d d1
where Col2=1
group by Col1, col2
) d2 on d1.Col1 = d2.Col1
order by 1,2
Output:
Col1 Cnt
1 1
2 1
3 0
4 0
5 0
You can use conditional aggregation:
select col1, sum(case when col2 = 1 then 1 else 0 end)
from t
group by col1;
Related
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>
I have the following table:
RowID Column1 Column2
1 3 2
2 5 2
3 2 9
4 5 NULL
5 8 NULL
6 9 3
7 1 NULL
I need first row of Column1 to Sum every time there is a NULL value in Column2. And it would continue the logic down the rows.
So, the result should look like:
RowID Column1 Column2
1 3 2
2 5 2
3 15 9
4 5 NULL
5 8 NULL
6 10 3
7 1 NULL
Notice Row 3 summed 2+5+8 =15 and Row 6 summed 9+1 =10. So, basically the row prior to Null value in Column2 summed the values in column1 until there was no more NULL values in column2. Then it resumed in row 6 where the next value was NULL.
This will do it. I have set up the data in a table variable for demo.
declare #t table(RowID int, C1 int, C2 int)
insert #t values (1, 3, 2)
,(2, 5, 2)
,(3, 2, 9)
,(4, 5, NULL)
,(5, 8, NULL)
,(6, 9, 3)
,(7, 1, NULL)
select RowID, sum(C1), max(C2)
from (
select RowID, C1, C2 from #t
union all
select T1.RowID, T2.C1, null
from #t t1
join #t t2 on t2.RowID>t1.RowID and t2.C2 is null
and not exists(
select * from #t t3
where t3.RowID>t1.RowID and t3.c2 is not null and t3.RowID<t2.RowID
)
where T1.C2 is not null
) q group by RowID
Result:
RowID C1 C2
1 3 2
2 5 2
3 15 9
4 5 NULL
5 8 NULL
6 10 3
7 1 NULL
I got it. You need to look at the rows in reverse order, assigning the NULL values to the value before them.
The idea is to assign a group to the rows to sum. This is the number of non-NULL values following the row. With this, you can then use a window function to aggregate:
select t.*,
(case when c2 is null then c1
else sum(c1) over (partition by grp)
end) as new_c1
from (select t.*, count(c2) over (order by rowid rows between 1 following and unbounded following) as grp
from t
) t
order by rowid;
Here is a db<>fiddle.
I want to select if one row where multiple columns are the same. For example:
col1 col2 col3 col4
a b 1 2
b b 1 2
a c 1 2
b b 1 3
a c 2 1
Condition: Select only if values of columns (col1, col2, col3) are different from other rows and value of col4 is max of rows which are the same.
For example expected Output is:
a b 1 2
b b 1 3
a c 1 2
a c 2 1
Yes possible, just use group by with max aggregation as
with tab(col1,col2,col3,col4) as
(
select 'a','b',1,2 union all
select 'b','b',1,2 union all
select 'a','c',1,2 union all
select 'b','b',1,3 union all
select 'a','c',2,1
)
select col1, col2, col3, max(col4) as col4
from tab
group by col1, col2, col3;
col1 col2 col3 col4
a b 1 2
a c 1 2
a c 2 1
b b 1 3
Rextester Demo
Mandatory NOT EXISTS solution... your condition written as a not exist query:
DECLARE #t TABLE (col1 varchar(100), col2 varchar(100), col3 int, col4 int);
INSERT INTO #t VALUES
('a', 'b', 1, 2),
('a', 'c', 1, 2),
('a', 'c', 2, 1),
('b', 'b', 1, 2),
('b', 'b', 1, 3);
SELECT *
FROM #t AS t
WHERE NOT EXISTS (
SELECT 1
FROM #t AS dup
WHERE dup.col1 = t.col1
AND dup.col2 = t.col2
AND dup.col3 = t.col3
AND dup.col4 > t.col4 -- outer row has smaller col4
)
Demo on DB Fiddle
I have a table that contains 3 columns as below:
col1 col2 col3
---- ---- ----
1 1 null
2 2 null
3 3 null
4 1 null
5 1 null
6 1 null
7 2 null
ETC
I need to update a third column in the same table as follows:
col1 col2 col3
---- ---- ----
1 1 1
2 2 1
3 3 1
4 1 2
5 1 3
6 1 4
7 2 4
The logic behind the update is that each time the 2nd column contains a 1 in it, the third has to increment. The first column is just a sequential integer column.
You can use the row_number analytical function to number the rows with col2 = 1 sequentially and then use a subquery to find to closest value with a lower col1 for the other rows.
So given a test table like this:
create table t (c1 int, c2 int, c3 int);
insert t (c1, c2) values
(1, 1),
(2, 2),
(3, 3),
(4, 1),
(5, 1),
(6, 1),
(7, 2);
A query like this:
;with cte as (
select t.c1, t.c2, x.c3
from t
left join (
select c1, c2, row_number() over (partition by c2 order by c1) c3
from t
where c2 = 1
) x on t.c1 = x.c1
)
update t
set t.c3 = coalesce(cte1.c3,(select max(cte2.c3) from cte cte2 where cte2.c1 < cte1.c1))
from cte cte1
where t.c1 = cte1.c1
Will give the following result:
c1 c2 c3
1 1 1
2 2 1
3 3 1
4 1 2
5 1 3
6 1 4
7 2 4
Another, possibly faster, way to do this would be:
update t1 set c3 = (select count(*) from t where c2 = 1 and c1 <= t1.c1) from t t1
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