I know that there are a lot of question like this:
SQL GROUP BY CASE statement with aggregate function
but I've tried doing:
with T as (select col1 , SUM(CASE WHEN col2 = 1 THEN col3 ELSE 0 END) AS Totale
from tabella
group by col1, col2)
select col1, Totale
from T
group by col1, Totale
but I'm getting
col1 | Totale
---------------
1 0
1 70
2 0
2 90
Instead of:
col1 | Totale
---------------
1 70
2 90
What's wrong with that?
UPDATE:
My bad, I try to keep it simple but I've overdone it.. What I've to do is:
with T as (select col1 , SUM(CASE WHEN col2 = 1 THEN col3 ELSE 0 END) AS TotaleA,
SUM(CASE WHEN col2 = 2 THEN col3 ELSE 0 END) AS TotaleB,
(...)
from tabella
group by col1, col2)
select col1, TotaleA, TotaleB
from T
group by col1, TotaleA, TotaleB
And the solution is to do without col2 in the grouping... I was afraid getting "invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause", but it's not.. Can I mark a comment as the correct answer?
You can also approach this problem by using a subquery:
SELECT
col1,
SUM(A) TotalA,
SUM(B) TotalB
FROM
(
select col1,
CASE WHEN col2 = 1 THEN col3 ELSE 0 END A,
CASE WHEN col2 = 2 THEN col3 ELSE 0 END B
from tabella
) t
GROUP BY Col1
Here is one idea. Not sure why you have this wrapped in a cte but why not make it simpler?
select col1
, SUM(col3) AS Totale
from tabella
where col2 = 1
group by col1
Related
I have table like this
id col1 col2
1 A 1
2 B 0
3 A 1
4 C 1
5 B 0
6 A 0
7 C 1
8 C 1
9 B 1
10 B 0
I need a query something like this
Values 1 0
A 2 1
B 1 3
C 3 0
In the above result the header shows the col2 distinct values (1,0) and rows names represents distinct values of col1. The values in the table shows the counts.
Any suggestion to get the result like this in postgresql?
You need conditional aggregation :
select col1,
sum(case when col2 = 1 then 1 else 0 end) as 1,
sum(case when col2 = 0 then 1 else 0 end) as 0
from table t
group by col1;
You could also use FILTER:
SELECT
col1,
COUNT(*) FILTER (WHERE col2 = 1) AS 1,
COUNT(*) FILTER (WHERE col2 = 0) AS 0,
FROM
foo
GROUP BY
col1;
Here are simpler ways to write this logic. The first is Postgres-specific:
select col1,
sum( (col2 = 1)::int ) as num_1,
sum( (col2 = 0)::int as num_0
from t
group by col1;
The second just uses arithmetic:
select col1,
sum( col2 ) as num_1,
sum( 1 - col2 ) as num_0
from t
group by col1;
I am trying to use MAX(case when col4='ABC' then col1 else 0 end) OVER (PARTITION BY col2 order by **col3**)
col1~col2~col3~col4
30 A B1 ABC
35 A A1 ABC
36 A NULL NULL
40 A X1 ABC
50 B M1 ABD
but I am getting the result as 40, but I want 35 as my result. It looks like
order by col3
is not getting applied before MAX aggregate. Is there any other way?
I can't write the row_number() in where clause, as we are trying to create columns and there are many columns and complicated logic around it.
Currently I am trying it in Teradata, but actually it will be implemented in HIVE.
This is too long for a comment. For this expression:
MAX(case when col4 = 'ABC' then col1 else 0 end) OVER (PARTITION BY col2 order by col3)
You should be getting:
col1~col2~col3~col4
30 A A1 ABC 30
40 A X1 ABC 40
50 B M1 ABD 0
If you want "30" for all, you might consider:
min(case when col4 = 'ABC' then col1 end) over ()
PARTITION BY will aggregate on distinct col2 values. Therefore, the MAX() value of the three col2 'A' values is 40.
If you want to return '35'. This is suggesting that A1 is the first row returned in the partition. First_Value() could be used to return the first row in the partition group.
FIRST_VALUE(CASE WHEN col4 = 'ABC' THEN col1
ELSE 0 END) OVER (PARTITION BY col2 order by col3)
EDIT: Have moved to window function in sub query to get correct row
Sample data (as table variable)
declare #t table(col1 int,col2 char(1),col3 char(2),col4 char(3))
insert #t values (30,'A','B1','ABC')
,(35,'A','A1','ABC')
,(36,'A',NULL,NULL)
,(40,'A','X1','ABC')
,(50,'B','M1','ABD')
Query using row_number() to get row to join to
select t.*, mx
from #t t
join (
select
col2,
case when col4='ABC' then col1 else 0 end as mx,
row_number() over (PARTITION BY col2 order by case when col3 is null then 1 else 0 end, col3) rn
from #t
) m on m.col2=t.col2 and rn=1
Result:
col1 col2 col3 col4 col2 mx
30 A B1 ABC A 35
35 A A1 ABC A 35
36 A NULL NULL A 35
40 A X1 ABC A 35
50 B M1 ABD B 0
I am working on some code, sample table shown below. Looking for aggregated output to some query
Sample Table
col1 col2
---- ----
val1 Fully
val1 Partial
val2 NoService
val2 Partial
val3 Fully
val3 NoService
val3 Fully
val3 Partial
val1 Fully
val2 NoService
Output expected
Col1 Fully Partial NoService Total
---- ----- ------- --------- -----
val1 2 1 0 3
val2 0 1 2 3
val3 2 1 1 4
Not sure how to do this in oracle? please some one help
Try This: It's not a dynamic solution though it will provide the result what you expect. If you have fixed values in val2 then it's the best one otherwise you have to choose dynamic way.
SELECT col1,
SUM(CASE WHEN col2 = 'Fully' THEN 1 ELSE 0 END) Fully,
SUM(CASE WHEN col2 = 'Partial' THEN 1 ELSE 0 END) Partial,
SUM(CASE WHEN col2 = 'NoService' THEN 1 ELSE 0 END) NoService,
COUNT(col2) total
FROM yourTable
GROUP BY col1
In Oracle, you can do this using pivot or aggregate function with CASE:
SELECT COL1,
COUNT(CASE when COL2 = 'FULLY' THEN 1 ELSE 0 END) AS FULLY,
COUNT(CASE when COL2 = 'PARTIAL' THEN 1 ELSE 0 END) AS PARTIAL
FROM TABLE_A A
LEFT JOIN TABLE_A B
on B.COL1 = A.COL1
GROUP BY COL1
Try this using pivot query function in oracle
select * from(select nvl(col1,'Total') col1,nvl(col2,'Total') col2,count(1) cnt from mytable group by CUBE(col1,col2))
pivot
(
sum(cnt)
for col2 IN
(
'Fully' AS "Fully",
'Partial' AS "Partial",
'NoService' AS "NoService",
'Total' As "Total"
)
)
here from above query i can get both column and row total.
use query as per your need.
TableA has the data as follows:
Col1 Col2 Col3
001 A 0
001 B 0
002 C 0
003 D 0
I want to see the count of records group by Col1 and Col2 where Col3 = 1
May be the query as follows:
Select Col1, Col3, Count(1)
From TableA
Group By Col1, Col2
Where Col3 = 1
Since there are no records with Col3 = 1 no records will be displayed, but I still want to display the values with count as 0.
For example the output is as follows:
Col1 Col2 CountOfRecords
001 A 0
001 B 0
002 C 0
003 D 0
Could you please help me to get output as shown above.
One approach would be to use conditional aggregation:
Select Col1, Col2, Count(case when Col3 = 1 then 1 end) as CountOfRecords
From TableA
Group By Col1, Col2
firstly you write wrong sql statement, you can not use Where clause after Group by clause.. you need to use before group by.. if you want to use filter after group by use Having clause..
second if there is no matching column for 'Col3 = 1' then you did not get any result.. for that you need to use case statement or sub queries.
otherwise do not use group by clause rather than use simple sql statement.
I have a SQL table like this
col1 col2 col3
1 0 1
1 1 1
0 1 1
1 0 0
0 0 0
I am expecting output as like this
col1 col2 col3 NewCol
1 0 1 SL,PL
1 1 1 SL,EL,PL
0 1 1 EL,PL
1 0 0 SL
0 0 0 NULL
The condition for this is if col1>0 then SL else ' ', if col2>0 EL else ' ', if col3>0 PL else ' '
I tried to use Concatenate many rows into a single text string? but didn't able to achieve the desired result properly
I have tried It is working fine with a message
Invalid length parameter passed to the LEFT or SUBSTRING function.
WITH CTE AS (
SELECT col1, col2, col3,
CASE WHEN col1 > 0 THEN 'SL,' ELSE '' END +
CASE WHEN col2 > 0 THEN 'EL,' ELSE '' END +
CASE WHEN col3 > 0 THEN 'PL,' ELSE '' END AS NewCol
FROM Employee
)
SELECT col1, col2, col3,
substring(NewCol, 1, len(NewCol) - 1) AS NewCol
FROM CTE
But again my last condition is not matching if all columns is 0 then I have to show NULL as per desired output.
Find the attach fiddle http://sqlfiddle.com/#!6/2bd6a/1
The issue with your code example is that when all columns are 0 then the length is 0 and the substring function will throw an error.
Use nullif to fix it: substring(NewCol, 1, len(nullif(NewCol,'')) - 1) AS NewCol
You could also change to appending the delimiter on the front and use STUFF.
STUFF('',1,1,'') will return NULL rather than an error.
WITH
Employee(col1, col2, col3) AS (
SELECT 1,1,1 UNION ALL
SELECT 0,0,0
),
CTE AS (
SELECT col1, col2, col3,
CASE WHEN col1 > 0 THEN ',SL' ELSE '' END +
CASE WHEN col2 > 0 THEN ',EL' ELSE '' END +
CASE WHEN col3 > 0 THEN ',PL' ELSE '' END AS NewCol
FROM Employee
)
SELECT col1,
col2,
col3,
STUFF(NewCol, 1, 1, '')
FROM CTE
Returns
+------+------+------+------------------+
| col1 | col2 | col3 | (No column name) |
+------+------+------+------------------+
| 1 | 1 | 1 | SL,EL,PL |
| 0 | 0 | 0 | NULL |
+------+------+------+------------------+
You have to check with NULLIF to do this trick
Two ways
SELECT col1, col2, col3,
nullif(CASE WHEN col1 = 1 THEN 'SL,' ELSE '' END +
CASE WHEN col2 = 1 THEN 'EL,' ELSE '' END +
CASE WHEN col3 = 1 THEN 'PL,' ELSE '' END,'') AS NewCol
FROM Employee
OR
SELECT
col1,
col2,
col3,
substring(nullif(NewCol,''), 1, len(NewCol) - 1) AS NewCol
FROM
CTE