How to group by using multiple conditions - sql

I have the following table
Type SubType value
A 1 1
A 2 2
A 3 3
A 4 4
B 1 1
B 2 2
B 3 3
C 1 1
C 2 2
C 3 3
C 4 4
I want to group by all rows except where Type=A and the output should like below
Type Sum
A1 1
A2 2
A3 3
A4 4
B 6
C 10
Is it possible to group by few rows on one condition and others on a different condition?

Yes, you have to write an expression that creates the group definition:
Select case When Type = 'A' then type + ltrim(str(subtype, 9))
Else Type End Type, Sum(Value) Sum
From table
Group By case When Type = 'A' then type + ltrim(str(subtype, 9))
Else Type End

Yes, you can GROUP BY a CASE expression;
SELECT CASE WHEN type='A'
THEN type+CAST(subtype AS VARCHAR(MAX))
ELSE type END [Type],
SUM(value) [Sum]
FROM mytable
GROUP BY CASE WHEN type='A'
THEN type+CAST(subtype AS VARCHAR(MAX))
ELSE type END
ORDER BY [Type]
An SQLfiddle to test with.
In SQL Server 2012, you can use CONCAT without the cast, which simplifies the query somewhat.

Another option. Split the logic into the 2 cases:
SELECT Type + CAST(subtype AS VARCHAR(MAX)) AS Type,
SUM(Value) AS Sum
FROM mytable
WHERE Type = 'A'
GROUP BY Type, Subtype
UNION ALL
SELECT Type,
SUM(Value)
FROM mytable
WHERE Type <> 'A'
GROUP BY Type
ORDER BY Type ;
Tested at SQL-Fiddle (thnx to #Joachim Isakkson)

Related

Select table adding columns with data depending on duplicates in other column

Imagine this data.
Id
Type
1
A
1
B
1
B
2
A
3
B
I want to select table and ad two columns turning it to this. How can i do it? (In teradata)
Id
Type
Id with both A+B
Id with only A
1
A
1
0
1
B
1
0
1
B
1
0
2
A
0
1
3
B
0
0
I'm not familiar with teradata but in standard SQL next query should be working:
SELECT
T.*,
CASE WHEN Cnt = 2 THEN 1 ELSE 0 END AS BOTH_TYPES_PRESENT,
CASE WHEN Cnt = 1 AND Type = 'A' THEN 1 ELSE 0 END AS ONLY_A_PRESENT
FROM T
LEFT JOIN (
SELECT Id, COUNT(DISTINCT Type) Cnt FROM T WHERE Type IN ('A', 'B') GROUP BY Id
) CNT ON T.Id = CNT.Id;
SQL online editor

Keep multiple rows during PIVOT in Snowflake

I would like to transpose rows into columns in Snowflake.
Suppose I have the following table BASE
ID
value
type
1
100
'A'
1
200
'B'
1
300
'B'
2
400
'A'
The output should be as follows:
ID
A
B
1
100
200
1
100
300
2
400
NULL
Currently I am pivoting the table with
SELECT ID,
CASE WHEN TYPE = 'A' THEN VALUE ELSE NULL AS A,
CASE WHEN TYPE = 'B' THEN VALUE ELSE NULL AS B
FROM BASE
For now the GROUP BY statement is missing. Typically I would GROUP BY ID, but that does not account for keeping one row per each value on the same TYPE and ID.
Any ideas how to achieve this?
Cheers,
P
You can use conditional aggregation. You can use row_number() to get multiple rows:
SELECT ID,
MAX(CASE WHEN TYPE = 'A' THEN VALUE END) AS A,
MAX(CASE WHEN TYPE = 'B' THEN VALUE END) AS B
FROM (SELECT B.*,
ROW_NUMBER() OVER (PARTITION BY ID, TYPE ORDER BY VALUE) as seqnum
FROM BASE B
) B
GROUP BY ID, seqnum;
This would work, too:
select *
from base_table
pivot(sum(value) for type in ('A','B')) as p
order by id;

Oracle query group by type

I have an output from my query:
Item Type Qty
1 A 2
2 A 3
3 B 1
4 B 2
5 C 1
6 D 3
Type to be grouped: A, B
I need my output to look like this:(after sum the qty and group by)
Type Qty
A 5
B 3
OTHERS 4
when the Type is not defined, it will group in 'OTHERS'. Is this possible to be done using analytic function or do I need to create my own function for this?
Assuming your table / view name is x, this gives exactly the desired output:
SELECT CASE WHEN type IN ('A', 'B') THEN type ELSE 'OTHERS' END AS type,
SUM(qty) AS qty
FROM x
GROUP BY CASE WHEN type IN ('A', 'B') THEN type ELSE 'OTHERS' END
ORDER BY 1
select type,sum(qty) from (select decode(type,c,'OTHERS',d,'OTHERS') type,qty from your_table) group by type;
(or)
select type,sum(qty) from (select (case when type in ('A','B') then type else 'others' end) type,qty from your_table) group by type;

How to write sql query for this?

My table looks like this:
id staus
1 p
1 p
1 c
2 p
2 c
I need to produce counts of rows with the statuses of 'p' and 'c' for each id, so the result I expect should look like this:
id p c
1 2 1 <-- id 1 has two rows with 'p' and one row with 'c'
2 1 1 <-- id 2 has one row with 'p' and one row with 'c'
How can i achieve this?
You can do it like this:
SELECT
id
, SUM (CASE STATUS WHEN 'p' THEN 1 ELSE 0 END) as p
, SUM (CASE STATUS WHEN 'c' THEN 1 ELSE 0 END) as c
FROM my_table
GROUP BY id
When you have more than just a few fixed items like 'p' and 'c' to aggregate, pivoting may provide a better option.
Pivot solution. Works from sql-server 2008
declare #t table(id int, staus char(1))
insert #t values( 1,'p'),( 1,'p'),( 1,'c'),( 2,'p'),( 2,'c')
SELECT id, [p], [c]
from #t
PIVOT
(count([staus])
FOR staus
in([p],[c])
)AS p
Result:
id p c
1 2 1
2 1 1
It seems that you need to do a pivot of your table, there is a simple article that I used when i faced your same problem pivot table sql server

using case with aggregate function with select & group by clauses

I've the below table
ID TYPE
--- ----
1 P
1 W
2 P
3 W
4 W
4 X
5 P
6 null
I need a new table to be created like the one below
ID Count of Type Code
-- -------------- -------
1 2 null
2 1 P
3 1 W
4 2 null
5 1 P
6 0 null
1st col ---> ID
2nd col ---> count of "type" for an ID
3rd col ---> if count(type) = 1 then TYPE
else null
Kindly help me in writing an ORACLE SQL query
You could use a subquery with the max function to get a value for the code and then use that in a case statement to get the value in your final query only when the count=1.
select id, cnt, case when cnt=1 then maxtype else null end as code
from
(select id, count(*) as cnt, max(type) as maxtype
from t1
group by id) t2