Combining fields with GROUP BY ROLLUP - sql

I want to have a query that shows every contract made in my company and have it grouped by function.
My problem is that I have a lot of functions, for instance:
Partner
Seller
Manager
Captain
Etc.
I want to show 3 rows, one with all contracts from "Partners", other by all the "Interns" (everyone that isn't a partner), and last one with a Total of the two, achieved with the ROLLUP. But I can't seem to only show this 3 rows, my query turns everything that is not partner to be name "intern", but doesn't combine this cells, so I get this result:
+--------------+-------------+--------------+---------+
| Seller Type | Installed | Scheduled | Total |
+--------------+-------------+--------------+---------+
| Intern | 1 | 0 | 1 |
+--------------+-------------+--------------+---------+
| Intern | 3 | 0 | 3 |
+--------------+-------------+--------------+---------+
| Partner | 10 | 5 | 15 |
+--------------+-------------+--------------+---------+
| Intern | 19 | 10 | 29 |
+--------------+-------------+--------------+---------+
| Total | 33 | 15 | 48 |
+--------------+-------------+--------------+---------+
And my goal was to Group everyone that isn't a "partner" into the same row, and show it like this:
+--------------+-------------+--------------+---------+
| Seller Type | Installed | Scheduled | Total |
+--------------+-------------+--------------+---------+
| Partner | 10 | 5 | 15 |
+--------------+-------------+--------------+---------+
| Intern | 23 | 10 | 33 |
+--------------+-------------+--------------+---------+
| Total | 33 | 15 | 48 |
+--------------+-------------+--------------+---------+
My data for table CM3
+--------------+-------------+--------------+
| u_func | cm | name |
+--------------+-------------+--------------+
| Captain | 1 | Chris |
+--------------+-------------+--------------+
| Manager | 2 | Mary |
+--------------+-------------+--------------+
| Partner | 3 | Anthony |
+--------------+-------------+--------------+
| Seller | 4 | Hannah |
+--------------+-------------+--------------+
My data for table BO
+--------------+-------------+--------------+
| stamp | seller | sta |
+--------------+-------------+--------------+
| PO109832910 | 1 | Installed |
+--------------+-------------+--------------+
| PO389213201 | 2 | Installed |
+--------------+-------------+--------------+
| PO930821639 | 3 | Scheduled |
+--------------+-------------+--------------+
| PO987583213 | 4 | Scheduled |
+--------------+-------------+--------------+
My query is
SELECT CASE
WHEN GROUPING(CM3.u_func)=1 THEN 'TOTAL'
WHEN CM3.u_func <> 'Partner' THEN 'Intern'
END "Seller Type"
, COUNT(CASE
WHEN BO.stat = 'Installed' THEN 1
END) "Installed"
, COUNT(CASE
WHEN BO.stat = 'Scheduled' THEN 1
END) "Scheduled"
, COUNT(CASE
WHEN BO.stat IN ('Installed','Scheduled') THEN 1
END) "Total"
FROM BO
JOIN CM3 ON cm3.cm = BO.seller
GROUP BY ROLLUP(CM3.u_func)

You need your GROUP BY to mirror the logic in your SELECT statement (which also needs some adjustment):
SELECT CASE
WHEN GROUPING
(CASE
WHEN CM3.u_func = 'Partner' THEN CM3.u_func
ELSE 'Intern'
END) = 1 THEN 'TOTAL'
ELSE CASE
WHEN CM3.u_func = 'Partner' THEN CM3.u_func
ELSE 'Intern'
END
END "Seller Type"
, COUNT(CASE
WHEN BO.stat = 'Installed' THEN 1
END) "Installed"
, COUNT(CASE
WHEN BO.stat = 'Scheduled' THEN 1
END) "Scheduled"
, COUNT(CASE
WHEN BO.stat IN ('Installed','Scheduled') THEN 1
END) "Total"
FROM BO
JOIN CM3 ON cm3.cm = BO.seller
GROUP BY CASE
WHEN CM3.u_func = 'Partner' THEN CM3.u_func ELSE 'Intern'
END WITH ROLLUP

Related

Query to both group by a name in one column and show total for each grouped element

I have a table that looks something like this generic example.
+-------+--------------+------------+---------------+-----------+----------+
| id | name | amount | payment_type | year | period |
+-------+--------------+------------+---------------+-----------+----------+
| 1 | Bob | 20 | BACS | 2019 | 5 |
+-------+--------------+------------+---------------+-----------+----------+
| 2 | Jim | 40 | BACS | 2019 | 5 |
+-------+--------------+------------+---------------+-----------+----------+
| 3 | Bob | 60 | BACS | 2019 | 5 |
+-------+--------------+------------+---------------+-----------+----------+
| 4 | Jim | 20 | Voucher | 2019 | 5 |
+-------+--------------+------------+---------------+-----------+----------+
| 5 | Bob | 40 | BACS | 2019 | 5 |
+-------+--------------+------------+---------------+-----------+----------+
| 6 | Bob | 20 | Cheque | 2019 | 5 |
+-------+--------------+------------+---------------+-----------+----------+
| 7 | Jim | 20 | BACS | 2019 | 5 |
+-------+--------------+------------+---------------+-----------+----------+
| 8 | Bob | 20 | BACS | 2019 | 5 |
+-------+--------------+------------+---------------+-----------+----------+
| 9 | Bob | 20 | BACS | 2019 | 5 |
+-------+--------------+------------+---------------+-----------+----------+
| 10 | Dan | 20 | BACS | 2019 | 5 |
+-------+--------------+------------+---------------+-----------+----------+
| 11 | Dan | 20 | Voucher | 2019 | 5 |
+-------+--------------+------------+---------------+-----------+----------+
etc...
I would like to total up results of this table (Many more rows) and have a count of the total number of rows for each user, the total of the amount column for each user, and a total of each payment type for each user, narrowed down by year and period each time I run this query. (The year and period are user-select-able on a form.) So that I end up with a result set that looks something like this:
+-------+--------------+------------+---------------+-----------+----------+
| name | Total | BACS | Cheque | Voucher | Cost |
+-------+--------------+------------+---------------+-----------+----------+
| Bob | 6 | 5 | 1 | 0 | 180 |
+-------+--------------+------------+---------------+-----------+----------+
| Jim | 3 | 2 | 0 | 1 | 80 |
+-------+--------------+------------+---------------+-----------+----------+
| Dan | 2 | 1 | 0 | 1 | 40 |
+-------+--------------+------------+---------------+-----------+----------+
So I need a pivoting query of some kind using a sum case something like this:
SELECT
name,
SUM(CASE WHEN YEAR = '$safefy' THEN 1 ELSE 0 END) AS total,
SUM(CASE WHEN payment_type = 'BACs' OR payment_type = 'BACS' THEN 1 ELSE 0 END) AS BACS,
SUM(CASE WHEN payment_type = 'Cheque' THEN 1 ELSE 0 END) AS Cheque,
SUM(CASE WHEN payment_type = 'Voucher' THEN 1 ELSE 0 END) AS Voucher,
<Not sure what goes here.> AS Cost,
FROM
table_name
WHERE
YEAR = '2019' AND period = '5'
GROUP BY
name "
But I'm not sure how to total up the cost from the tables amount column for each user. I'm probably not using the correct terms in my search for answers because I don't know what it's called?
I think you just want sum(amount):
SELECT name,
SUM(CASE WHEN YEAR = '$safefy' THEN 1 ELSE 0 END) AS total,
SUM(CASE WHEN payment_type = 'BACs' OR payment_type = 'BACS' THEN 1 ELSE 0 END) AS BACS,
SUM(CASE WHEN payment_type = 'Cheque' THEN 1 ELSE 0 END) AS Cheque,
SUM(CASE WHEN payment_type = 'Voucher' THEN 1 ELSE 0 END) AS Voucher,
SUM(amount) AS Cost
FROM table_name
WHERE YEAR = '2019' AND period = '5'
GROUP BY name;
You can simplify the first part because the CASE is not needed:
SELECT name,
SUM(YEAR = '$safefy') AS total,
SUM(payment_type IN ('BACs', 'BACS') THEN 1 ELSE 0 END) AS BACS,
SUM(payment_type = 'Cheque') AS Cheque,
SUM(payment_type = 'Voucher') AS Voucher,
SUM(amount) AS Cost
FROM table_name
WHERE YEAR = '2019' AND period = '5'
GROUP BY name

Oracle SQL count and group by multiple fields

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]

SQL Aggregation depending on value of attribute in unselected column

I've got a table TABLE1 like this:
|--------------|--------------|--------------|
| POS | UNIT | VOLUME |
|--------------|--------------|--------------|
| 1 | M2 | 20 |
| 1 | M2 | 30 |
| 1 | M3 | 40 |
| 2 | M2 | 100 |
| 2 | M3 | 20 |
| 3 | ST | 30 |
| 3 | M2 | 10 |
|--------------|--------------|--------------|
Depending on the value of the column UNIT I want to aggregate as follows (each UNIT becomes a new column with the sum of the according value):
|--------------|--------------|--------------|--------------|
| POS | VOLUME_M2 | VOLUME_M3 | VOLUME_ST |
|--------------|--------------|--------------|--------------|
| 1 | 50 | 40 | 0 |
| 2 | 100 | 20 | 0 |
| 3 | 10 | 0 | 30 |
|--------------|--------------|--------------|--------------|
My Solution is
SELECT POS,
CASE
WHEN UNIT = 'M2'
THEN SUM(VOLUME)
ELSE 0
END AS VOLUME_M2,
CASE
WHEN UNIT = 'M3'
THEN SUM(VOLUME)
ELSE 0
END AS VOLUME_M3,
CASE
WHEN UNIT = 'ST'
THEN SUM(VOLUME)
ELSE 0
END AS VOLUME_S
FROM TABLE1
GROUP BY POS, UNIT
My problem is, that my code does not work if I leave out UNIT in the GROUP BY statement (I either have to use it in my aggregation or in my GROUP BY statement)
Therefore I get something like this:
|--------------|--------------|--------------|--------------|
| POS | VOLUME_M2 | VOLUME_M3 | VOLUME_ST |
|--------------|--------------|--------------|--------------|
| 1 | 50 | 0 | 0 |
| 1 | 0 | 40 | 0 |
| 2 | 0 | 20 | 0 |
| 2 | 100 | 0 | 0 |
| 3 | 10 | 0 | 0 |
| 3 | 0 | 0 | 30 |
|--------------|--------------|--------------|--------------|
Besides, could anyone give me a hint, how it is possible to automatically get this type of result (especially if there are a lot of values for UNIT).
Close. For conditional aggregation, the case expression is an argument to the aggregation function:
SELECT POS,
SUM(CASE WHEN UNIT = 'M2' THEN VOLUME ELSE 0 END) AS VOLUME_M2,
SUM(CASE WHEN UNIT = 'M3' THEN VOLUME ELSE 0 END) AS VOLUME_M3,
SUM(CASE WHEN UNIT = 'ST' THEN VOLUME ELSE 0 END) AS VOLUME_ST
FROM TABLE1
GROUP BY POS;

Calculation going wrong due to JOIN issue

Table -
+----+-----------+-----------+---------+---------------------+------------+
| ID | Client_Id | Driver_Id | City_Id | Status | Request_at |
+----+-----------+-----------+---------+---------------------+------------+
| 1 | 1 | 10 | 1 | completed | 2013-10-01 |
| 2 | 2 | 11 | 1 | cancelled_by_driver | 2013-10-01 |
| 3 | 3 | 12 | 6 | completed | 2013-10-01 |
| 4 | 4 | 13 | 6 | cancelled_by_client | 2013-10-01 |
| 5 | 1 | 10 | 1 | completed | 2013-10-02 |
| 6 | 2 | 11 | 6 | completed | 2013-10-02 |
| 7 | 3 | 12 | 6 | completed | 2013-10-02 |
| 8 | 2 | 12 | 12 | completed | 2013-10-03 |
| 9 | 3 | 10 | 12 | completed | 2013-10-03 |
| 10 | 4 | 13 | 12 | cancelled_by_driver | 2013-10-03 |
+----+-----------+-----------+---------+---------------------+------------+
My attempt -
WITH src
AS (SELECT Count(status) AS Denom,
request_at
FROM trips
WHERE status = 'completed'
GROUP BY request_at),
src2
AS (SELECT Count(status) AS Num,
request_at
FROM trips
WHERE status <> 'completed'
GROUP BY request_at)
SELECT Cast(Count(num) AS FLOAT)/Cast(Count(Denom) AS FLOAT) AS cancel_rate,
trips.request_at
FROM src,
src2,
trips
GROUP BY trips.request_at;
I am trying to find the cancellation rate per day but it is clearing wrong (MY OUTPUT)-
+-------------+------------+
| cancel_rate | request_at |
+-------------+------------+
| 24 | 2013-10-01 |
| 18 | 2013-10-02 |
| 18 | 2013-10-03 |
+-------------+------------+
The cancellation rate for 2013-10-01 should be 0.5 and not 24. Similarly for other dates it should be different.
I know the problem lies with this part but I do not know what is the correct way or how to approach it
SELECT Cast(Count(num) AS FLOAT)/Cast(Count(Denom) AS FLOAT) AS cancel_rate,
trips.request_at
FROM src,
src2,
trips
Is there any way to put in more than 1 select statement in With NAME as () clause ? So that I won't use any JOIN or multiple tables.
Use conditional aggregation:
SELECT SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as denom,
SUM(CASE WHEN status <> 'completed' THEN 1 ELSE 0 END) as num,
AVG(CASE WHEN status <> 'completed' THEN 1.0 ELSE 0 END) as cancel_rate
FROM trips
GROUP BY request_at;
Note that calculation for the cancel_rate. This is simpler to do using AVG() rather than dividing the two values. The use of 1.0is because SQL Server does integer arithmetic, so 1 / 2 is 0 rather than 0.5.
OK, a bit late again, but here is another variation (edited):
SELECT SUM(CASE LEFT(status,9) WHEN 'cancelled' THEN 1. ELSE 0 END)
/COUNT(*) cancellation_rate,
request_at
FROM trips GROUP BY request_at ORDER BY request_at

SQL Renaming NULL for null values and rollup

I'm trying to make a dashboard to show open tickets and who they are assigned to, by priority. The data set looks like:
|-------------------------|
| Assigned | Priority |
|-------------------------|
| JOE | Low |
| JOE | Medium |
| MARY | High |
| | Medium |
| TIM | Low |
| Mary | High |
The report I'm trying to get is:
|---------------------------------------------------------|
| Employee | Low | Medium | High | Total |
|---------------------------------------------------------|
| Total | 2 | 2 | 2 | 6 |
| Unassigned | 0 | 1 | 0 | 1 |
| MARY | 0 | 0 | 2 | 2 |
| JOE | 1 | 1 | 0 | 2 |
| TIM | 1 | 0 | 0 | 1 |
I can get it all, with this query
SELECT
CASE WHEN Assigned is null then 'Unassigned' Else Assigned End Employee
, SUM(CASE WHEN Priority = 'Low' THEN 1 ELSE 0 END) AS Low
, SUM(CASE WHEN Priority = 'Medium' THEN 1 ELSE 0 END) AS Medium
, SUM(CASE WHEN Priority = 'High' THEN 1 ELSE 0 END) AS High
, count(Priority) AS Total
FROM table
GROUP BY Assigned WITH ROLLUP
ORDER BY Assigned ASC
This way however, it is renaming anything that was NULL to Unassigned. This is perfect to give me the Unassigned values that don't have anyone in the Assigned field, however my Total column is also showing Unassigned. How do I rename that to Total?
Thanks in advance!
You need to use GROUPING, like this:
SQL Fiddle
SELECT
CASE WHEN (GROUPING(Assigned) = 1) THEN 'Total'
When Assigned is null then 'Unassigned'
Else Assigned End Employee
, SUM(CASE WHEN Priority = 'Low' THEN 1 ELSE 0 END) AS Low
, SUM(CASE WHEN Priority = 'Medium' THEN 1 ELSE 0 END) AS Medium
, SUM(CASE WHEN Priority = 'High' THEN 1 ELSE 0 END) AS High
, count(Priority) AS Total
FROM table1
GROUP BY Assigned WITH ROLLUP
--DER BY Assigned ASC
Results:
| EMPLOYEE | LOW | MEDIUM | HIGH | TOTAL |
|------------|-----|--------|------|-------|
| Unassigned | 0 | 1 | 0 | 1 |
| JOE | 1 | 1 | 0 | 2 |
| MARY | 0 | 0 | 2 | 2 |
| TIM | 1 | 0 | 0 | 1 |
| Total | 2 | 2 | 2 | 6 |