Oracle SQL count and group by multiple fields - sql

I am able to get the data merging two tables to get the following table.
+------------+------+--------+--------+------------+------------+
| Group Name | Type | Manger | Status | ControlOne | ControlTwo |
+------------+------+--------+--------+------------+------------+
| Group A | 1 | 1 | finish | 2 | 2 |
| Group A | 2 | 1 | open | 0 | 2 |
| Group A | 1 | 1 | finish | 0 | 0 |
| Group A | 1 | 2 | finish | 2 | 0 |
| Group B | 1 | 1 | open | 2 | 0 |
| Group B | 1 | 2 | open | 2 | 2 |
| Group B | 2 | 2 | open | 0 | 2 |
| Group B | 2 | 1 | finish | 0 | 0 |
| Group B | 1 | 1 | open | 2 | 0 |
+------------+------+--------+--------+------------+------------+
Now I need to get the total counts based on GroupName/ Type and Manager to have the output for each group in the following format:
+------------+------+-------------------------------------------------+--------------------------------------------+------------------------------+----------------------------+
| Group Name | Type | Manager1Finish | Manager1Open | Manager2Finish | Manager2Open |
+------------+------+-------------------------------------------------+--------------------------------------------+------------------------------+----------------------------+
| Group A | 1 | 2(count of finish by Group A, manager1, type 1) | 0(count of open Manager1, Type 1, Group A) | 1(count of finish Manager 2) | 0(count of open manager 2) |
| Group A | 2 | 0 | 1 | 0 | 0 |
+------------+------+-------------------------------------------------+--------------------------------------------+------------------------------+----------------------------+
Could you please help to how to achieve this?

Try with CASE WHEN:
SELECT GroupName,
TYPE,
COUNT (CASE
WHEN Manager = 1
AND status = 'Finish'
THEN
1
END)
AS Manager1Finish,
COUNT (CASE
WHEN Manager = 1
AND status = 'Open'
THEN
1
END)
AS Manager1Open,
COUNT (CASE
WHEN Manager = 2
AND status = 'Finish'
THEN
1
END)
AS Manager2Finish,
COUNT (CASE
WHEN Manager = 2
AND status = 'Open'
THEN
2
END)
AS Manager2Open
FROM tablename
GROUP BY GroupName, TYPE

select [group], [type],
sum(case when manager=1 and status='finish' then 1 else 0 end) as m1finish,
sum(case when manager=1 and status='open' then 1 else 0 end) as m1open,
sum(...etc...)
from mytable
group by [group],[type]

Related

How to assign duplicate increment in SQL?

While going through SQL columns, if we find text match "NEW" in Calc column, update the incrementing a count starting with 1 in Results column.
It should look like this on the output:
The following uses an id column to resolve the order issue. Replace that with your corresponding expression. This also addresses the requirement to start the display sequence with 1 and also show 0 for the 'NEW' rows.
The SQL (updated):
SELECT logs.*
, CASE WHEN text = 'NEW' THEN 0
ELSE
COALESCE(SUM(CASE WHEN text = 'NEW' THEN 1 END) OVER (PARTITION BY xrank ORDER BY id)+1, 1)
END AS display
FROM logs
ORDER BY id
The result:
+----+-------+------+---------+
| id | xrank | text | display |
+----+-------+------+---------+
| 1 | 1 | A | 1 |
| 2 | 1 | B | 1 |
| 3 | 1 | C | 1 |
| 4 | 1 | NEW | 0 |
| 5 | 1 | D | 2 |
| 6 | 1 | Q | 2 |
| 7 | 1 | B | 2 |
| 8 | 1 | NEW | 0 |
| 9 | 1 | D | 3 |
| 10 | 1 | Z | 3 |
| 11 | 2 | A | 1 |
| 12 | 2 | B | 1 |
| 13 | 2 | C | 1 |
| 14 | 2 | NEW | 0 |
| 15 | 2 | D | 2 |
| 16 | 2 | Q | 2 |
| 17 | 2 | B | 2 |
| 18 | 2 | NEW | 0 |
| 19 | 2 | D | 3 |
| 20 | 2 | Z | 3 |
+----+-------+------+---------+
You need a column that specifies the ordering for the table. With that, just use a cumulative sum:
select t.*,
1 + sum(case when Calc = 'NEW' then 1 else 0 end) over (partition by Rank_Id order by Seq) as display
from t;

Create New Columns from Row Values then Group By

My current table looks like this:
+-------+------+
| Level | Team |
+-------+------+
| 1 | 1 |
| 2 | 1 |
| 2 | 1 |
| 3 | 2 |
| 3 | 2 |
| 3 | 2 |
+-------+------+
I want to group by level and know the count of level for both teams. I can easily get the count of a single team by using the following:
SELECT Level, Count(Team)
FROM table
WHERE Team = 1
GROUP BY Level
SORT BY Level;
+-------+-------------+
| Level | Team1_Count |
+-------+-------------+
| 1 | 1 |
| 2 | 2 |
| 3 | 0 |
+-------+-------------+
However, the end result I want is below:
+-------+-------------+-------------+
| Level | Team1_Count | Team2_Count |
+-------+-------------+-------------+
| 1 | 1 | 0 |
| 2 | 2 | 0 |
| 3 | 0 | 3 |
+-------+-------------+-------------+
Removing the WHERE clause gives the total per Level but does not split it into Teams. How do I make it so both of these new columns are created and show the counts per Level?
Try the following using case expression with sum. Here is the demo.
select
level,
sum(case when team = 1 then 1 else 0 end) as Team1_count,
sum(case when team = 2 then 1 else 0 end) as Team2_count
from table
group by
level
order by
level
output
| level | Team1_count | Team2_count |
| ----- | ----------- | ----------- |
| 1 | 1 | 0 |
| 2 | 2 | 0 |
| 3 | 0 | 3 |
if you are using postgreSQL then you can use filter with count as following
select
level,
count(*) filter (where team = 1) as Team1_count,
count(*) filter (where team = 2) as Team2_count
from tableA
group by
level
order by
level

SQL Count columns from other columns

I have this view generated after using LEFT JOIN over 2 tables (simplified example).
Tables:
T1: Id, ...other columns not used
+----+-----+
| Id | ... |
+----+-----+
| 1 | ... |
| 2 | ... |
+----+-----+
T2: Id, NewId (Foreign Key from T1), Status, ...other columns not used
+-----+-------+--------+-----+
| Id | NewId | Status | ... |
+-----+-------+--------+-----+
| 1 | 1 | 1 | ... |
| 2 | 1 | 2 | ... |
| 3 | 1 | 2 | ... |
| 4 | 1 | 3 | ... |
| 5 | 1 | 1 | ... |
| 6 | 1 | 1 | ... |
| 7 | 2 | 0 | ... |
| 8 | 2 | 2 | ... |
| 9 | 2 | 1 | ... |
| 10 | 2 | 2 | ... |
+-----+-------+--------+-----+
Current View:
SELECT
T1.Id,
T2.Status
FROM T1
LEFT JOIN T2 ON T1.Id = T2.NewId;
View: (I got till here)
+----+--------+
| Id | Status |
+----+--------+
| 1 | 1 |
| 1 | 2 |
| 1 | 2 |
| 1 | 3 |
| 1 | 1 |
| 1 | 1 |
| 2 | 0 |
| 2 | 2 |
| 2 | 1 |
| 2 | 2 |
+----+--------+
The required view needs to have separate columns for each status value (which are exactly 0, 1, 2 or 3). 0 & 1 are kept in the same column.
Required View: (But I need this)
+----+------------+----------+----------+
| Id | Status 0/1 | Status 2 | Status 3 |
+----+------------+----------+----------+
| 1 | 1 | 1 | 1 |
| 2 | 2 | 2 | 2 |
+----+------------+----------+----------+
I feel like I missing something basic. How can I get this view?
I don't think we need Rank() stuff, and it's a big query over 4 normalized tables (in practice), which is why I need an optimal solution. Subqueries work with inline SELECT queries, but they need JOINs as well. The production requirement has 10 columns for counts over 2 separate columns.
Use conditional aggregation:
select
id,
sum(case when status in (0, 1) then 1 else 0 end) status_0_1,
sum(case when status = 2 then 1 else 0 end) status_2
sum(case when status = 3 then 1 else 0 end) status_3
from mytable
group by id
In your orignal query, this should look like:
select
t1.id,
sum(case when t2.status in (0, 1) then 1 else 0 end) status_0_1,
sum(case when t2.status = 2 then 1 else 0 end) status_2
sum(case when t2.status = 3 then 1 else 0 end) status_3
from t1
left join t2 on t1.id = t2.newid
group by t1.id
Use aggregation:
select id,
sum(case when status in (0, 1) then 1 else 0 end) as status_01,
sum(case when status = 2 then 1 else 0 end) as status_2,
sum(case when status = 3 then 1 else 0 end) as status_3
from t
group by id;
You should be able to build this directly into your left join:
from a left join
b
on . . .
Can be the from clause. Or use your current query as a subquery or CTE.

Encapsulated Group by or conditional aggregation in Vertica DB

I have the following table in a Vertica DB:
+---------+-------+
| Readout | Event |
+---------+-------+
| 1 | A |
| 1 | B |
| 1 | A |
| 2 | B |
| 2 | A |
+---------+-------+
I would like to group each readout and count the frequency of the events, resulting in a table like this:
+---------+----------------+----------------+-----------------+
| Readout | Count(Readout) | Count(Event A) | Count (Event B) |
+---------+----------------+----------------+-----------------+
| 1 | 3 | 2 | 1 |
| 2 | 2 | 1 | 1 |
+---------+----------------+----------------+-----------------+
I am sure there is an easy GROUP BY command, but I can't wrap my head around it.
You want conditional aggregation:
select readout, count(*),
sum(case when event = 'A' then 1 else 0 end) as num_a,
sum(case when event = 'B' then 1 else 0 end) as num_b
from t
group by readout;

MySQL: Pivot + Counting

I need help with a SQL that will convert this table:
===================
| Id | FK | Status|
===================
| 1 | A | 100 |
| 2 | A | 101 |
| 3 | B | 100 |
| 4 | B | 101 |
| 5 | C | 100 |
| 6 | C | 101 |
| 7 | A | 102 |
| 8 | A | 102 |
| 9 | B | 102 |
| 10 | B | 102 |
===================
to this:
==========================================
| FK | Count 100 | Count 101 | Count 102 |
==========================================
| A | 1 | 1 | 2 |
| B | 1 | 1 | 2 |
| C | 1 | 1 | 0 |
==========================================
I can so simple counts, etc., but am struggling trying to pivot the table with the information derived. Any help is appreciated.
Use:
SELECT t.fk,
SUM(CASE WHEN t.status = 100 THEN 1 ELSE 0 END) AS count_100,
SUM(CASE WHEN t.status = 101 THEN 1 ELSE 0 END) AS count_101,
SUM(CASE WHEN t.status = 102 THEN 1 ELSE 0 END) AS count_102
FROM TABLE t
GROUP BY t.fk
use:
select * from
(select fk,fk as fk1,statusFK from #t
) as t
pivot
(COUNT(fk1) for statusFK IN ([100],[101],[102])
) AS pt
Just adding a shortcut to #OMG's answer.
You can eliminate CASE statement:
SELECT t.fk,
SUM(t.status = 100) AS count_100,
SUM(t.status = 101) AS count_101,
SUM(t.status = 102) AS count_102
FROM TABLE t
GROUP BY t.fk