joining columns of same table with different criteria - SQL - sql

I am able to query with one condition ( as shown in image below ) but when i query with couple of criterias and trying to create two same columns of same table with different criteria, i get no result. 2nd Image is the expected result which i am not able to retrieve. Any inputs are highly appreciated. Thanks.
select save_line from save_output_table
where execution_id in ('292')
and seq_id = '0'
and save_type='R'
order by line_id ASC
+------------+
| Save_line |
+------------+
| 17 |
| 22 |
| 23 |
+------------+
SELECT
( select save_line
from save_output_table
where execution_id in ('292')
and seq_id = '0'
and save_type='R'
order by line_id ASC
) as save_line1,
( select save_line
from save_output_table
where execution_id in ('286')
and seq_id = '0'
and save_type='R'
order by line_id ASC
) as save_line2
from save_output_table
+-------------+------------+
| Save_line 1 | Save_line2 |
+-------------+------------+
| 17 | 9 |
| 22 | 5 |
| 23 | 3 |
+-------------+------------+
Sample Data :
+---------------+--------+-----------+---------+-----------+
| execution_id | seq_id | save_type | line_id | save_line |
+---------------+--------+-----------+---------+-----------+
| 286 | 0 | R | 1 | 17 |
| 286 | 0 | R | 2 | 22 |
| 286 | 0 | R | 3 | 23 |
| 286 | 0 | D | 1 | 17 |
| 286 | 0 | D | 2 | 22 |
| 286 | 0 | D | 3 | 23 |
| 292 | 0 | R | 1 | 9 |
| 292 | 0 | R | 2 | 5 |
| 292 | 0 | R | 3 | 3 |
| 292 | 0 | D | 1 | 98 |
| 292 | 0 | D | 2 | 622 |
| 292 | 0 | D | 3 | 273 |
+---------------+--------+-----------+---------+-----------+

So if you want lists of save_line in order by line_id, in different columns according to save_type and execution_id, you need to pivot. There are a few different ways you can do this. Here are a couple that should work no matter what flavor of SQL you are using:
SELECT line_id,
max(CASE WHEN execution_id = '292' and save_type = 'R' then save_line end) R_292,
max(CASE WHEN execution_id = '286' and save_type = 'R' then save_line end) R_286
FROM save_output_table
GROUP BY line_id
or
SELECT t1.save_line save_line1,
t2.save_line save_line2
FROM
(SELECT *
FROM save_output_table
WHERE save_type = 'R'
and execution_id = '292'
) t1
JOIN (SELECT *
FROM save_output_table
WHERE save_type = 'R'
and execution_id = '286'
) t2
ON t1.line_id = t2.line_id
Note: for the second option, the join only gives complete lists if there are the same number of line_ids for each condition. If there aren't, you should change it to a FULL OUTER JOIN, which wouldn't work in MySQL and possibly others.

Related

Get ID alongside max value ORACLE SQL

I currently have the following:
TABLE "QUARTO":
CREATE TABLE Quarto (
Id number(2) NOT NULL,
LotacaoMaxima number(1) NOT NULL,
TipoQuartoId number(1) NOT NULL,
NumeroQuartoNumSequencial number(3) NOT NULL,
NumeroQuartoAndarId varchar2(1) NOT NULL,
PRIMARY KEY (Id));
TABLE RESERVA:
CREATE TABLE Reserva (
Id number(3) NOT NULL,
ClienteNif number(9) NOT NULL,
QuartoId number(2) NOT NULL,
DataInicio date NOT NULL,
DataFim date NOT NULL,
NumPessoas number(1) NOT NULL,
Estado varchar2(15) NOT NULL,
DataCancelamento date,
PRIMARY KEY (Id));
And some data I have in both is:
QUARTO:
| ID | LOTACAOMAXIMA | TIPOQUARTOID | NUMEROQUARTONUMSEQUENCIAL | NUMEROQUARTOANDARID |
| :--- | :--- | :--- | :--- | :--- |
| 1 | 1 | 1 | 1 | 1 |
| 2 | 1 | 1 | 2 | 1 |
| 3 | 1 | 1 | 3 | 1 |
| 4 | 1 | 1 | 4 | 1 |
| 5 | 1 | 1 | 5 | 1 |
| 6 | 1 | 1 | 6 | 1 |
| 7 | 1 | 1 | 7 | 1 |
| 8 | 1 | 1 | 8 | 1 |
| 9 | 1 | 1 | 9 | 1 |
| 10 | 1 | 1 | 10 | 1 |
| 11 | 2 | 2 | 11 | 1 |
| 12 | 2 | 2 | 12 | 1 |
| 13 | 2 | 2 | 13 | 1 |
| 14 | 2 | 2 | 14 | 1 |
| 15 | 2 | 2 | 15 | 1 |
| 16 | 2 | 2 | 16 | 1 |
| 17 | 2 | 2 | 17 | 1 |
| 18 | 2 | 2 | 18 | 1 |
| 19 | 2 | 2 | 19 | 1 |
| 20 | 2 | 2 | 20 | 1 |
RESERVA:
| ID | CLIENTENIF | QUARTOID | DATAINICIO | DATAFIM | NUMPESSOAS | ESTADO | DATACANCELAMENTO |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| 1 | 296837970 | 11 | 2020-06-01 00:00:00 | 2020-06-12 00:00:00 | 1 | Finalizada | NULL |
| 2 | 275784703 | 17 | 2020-06-13 00:00:00 | 2020-06-21 00:00:00 | 1 | Finalizada | NULL |
| 3 | 220347654 | 11 | 2020-07-07 00:00:00 | 2020-07-15 00:00:00 | 2 | Finalizada | NULL |
| 4 | 294772545 | 12 | 2020-08-01 00:00:00 | 2020-08-15 00:00:00 | 2 | Finalizada | NULL |
| 5 | 220347654 | 3 | 2020-01-01 00:00:00 | 2020-01-16 00:00:00 | 1 | Finalizada | NULL |
WITH CONTAGEM_QUARTO_POR_ID AS (SELECT q.ID, COUNT(r.QUARTOID) AS NUM_RESERVAS, q.TIPOQUARTOID, q.NUMEROQUARTOANDARID
FROM RESERVA r
INNER JOIN QUARTO q on q.ID = r.QUARTOID
GROUP BY q.ID, q.TIPOQUARTOID, q.NUMEROQUARTOANDARID)
SELECT t.TIPOQUARTOID, t.NUMEROQUARTOANDARID, MAX(t.NUM_RESERVAS) AS MAX
FROM CONTAGEM_QUARTO_POR_ID t
GROUP BY t.TIPOQUARTOID, t.NUMEROQUARTOANDARID
And the Output is the following:
| TIPOQUARTOID | NUMEROQUARTOANDARID | MAX |
| :----------- | :------------------ | :-- |
| 1 | 2 | 2 |
| 2 | 1 | 8 |
| 1 | 1 | 1 |
I want to, alongside the data I currently have, also show toe ID of each row, but when I add the t.ID to the SELECT it forces me to add it to GROUP BY and the output is this:
| TIPOQUARTOID | NUMEROQUARTOANDARID | MAX | ID |
| :----------- | :------------------ | :-- | :- |
| 2 | 1 | 2 | 11 |
| 1 | 1 | 1 | 1 |
| 1 | 1 | 1 | 3 |
| 1 | 2 | 2 | 21 |
| 2 | 1 | 1 | 17 |
| 2 | 1 | 1 | 12 |
| 2 | 1 | 8 | 16 |
I only wan to get the max value and the ID associated to that MAX.
You can use the KEEP clause in your query without changing it much as follows:
WITH CONTAGEM_QUARTO_POR_ID AS
(SELECT q.ID, COUNT(r.QUARTOID) AS NUM_RESERVAS, q.TIPOQUARTOID, q.NUMEROQUARTOANDARID
FROM RESERVA r
INNER JOIN QUARTO q on q.ID = r.QUARTOID
GROUP BY q.ID, q.TIPOQUARTOID, q.NUMEROQUARTOANDARID)
SELECT t.TIPOQUARTOID, t.NUMEROQUARTOANDARID, MAX(t.NUM_RESERVAS) AS MAX,
max(t.ID) keep(dense_rank first order by t.NUM_RESERVAS desc nulls last) as ID -- this
FROM CONTAGEM_QUARTO_POR_ID t
GROUP BY t.TIPOQUARTOID, t.NUMEROQUARTOANDARID
You need MAX() OVER () Analytic function for NUM_RESERVAS column with PARTITION BY TIPOQUARTOID, NUMEROQUARTOANDARID in order to provide grouping for those columns within the partition by list such as
WITH CONTAGEM_QUARTO_POR_ID AS
(
SELECT q.ID,
COUNT(r.QUARTOID) AS NUM_RESERVAS,
q.TIPOQUARTOID,
q.NUMEROQUARTOANDARID
FROM RESERVA r
JOIN QUARTO q
on q.ID = r.QUARTOID
GROUP BY q.ID, q.TIPOQUARTOID, q.NUMEROQUARTOANDARID
), t AS
(
SELECT t.TIPOQUARTOID, t.NUMEROQUARTOANDARID, t.NUM_RESERVAS,
MAX(t.NUM_RESERVAS)
OVER (PARTITION BY t.TIPOQUARTOID, t.NUMEROQUARTOANDARID) AS MAX,
t.ID
FROM CONTAGEM_QUARTO_POR_ID t
)
SELECT TIPOQUARTOID, NUMEROQUARTOANDARID, NUM_RESERVAS, ID
FROM t
WHERE NUM_RESERVAS = MAX
or more straightforward by using HAVING clause
SELECT q.TIPOQUARTOID,
q.NUMEROQUARTOANDARID,
COUNT(r.QUARTOID) AS NUM_RESERVAS,
q.ID
FROM RESERVA r
JOIN QUARTO q
on q.ID = r.QUARTOID
GROUP BY q.ID, q.TIPOQUARTOID, q.NUMEROQUARTOANDARID
HAVING COUNT(r.QUARTOID) = q.TIPOQUARTOID
I wouldn't suggest two levels of aggregation. Just use window funtions:
WITH CONTAGEM_QUARTO_POR_ID AS (
SELECT q.ID, COUNT(*) AS NUM_RESERVAS, q.TIPOQUARTOID, q.NUMEROQUARTOANDARID,
ROW_NUMBER() OVER (PARTITION BY q.TIPOQUARTOID, q.NUMEROQUARTOANDARID ORDER BY COUNT(*) DESC) as seqnum
FROM RESERVA r INNER JOIN
QUARTO q
ON q.ID = r.QUARTOID
GROUP BY q.ID, q.TIPOQUARTOID, q.NUMEROQUARTOANDARID
)
SELECT cq.*
FROM CONTAGEM_QUARTO_POR_ID cq
WHERE seqnum = 1;
I think this would have slightly better performance than two aggregations (but it is worth checking).
One advantage of this approach is that it is more flexible. If you want ties, just change the ROW_NUMBER() to RANK() in the subquery.
Perhaps more importantly, ROW_NUMBER() is an "idiom" in SQL for returning one row (or a specific number of rows) per group. Learning how to use it is very valuable.

Combine the data of two tables using SQL Pivot and joins for a subquery

I'm trying to create a report to find the number of users subscribed to the notification type.
I am stuck with subqueries because if these two tables
Table 1
NotificationMaster
+----+-------+
| ID | Name |
+----+-------+
| 1 | Email |
| 2 | Push |
| 3 | Call |
+----+-------+
Table 2
NotificationPreference
+------------+------------------+------------+--------------+
| ResourceID | NotificationID | IsChecked | AccountID |
+------------+------------------+------------+--------------+
| 23 | 1 | 1 1 |
| 36 | 2 | 0 2 |
| 45 | 3 | 1 3 |
| 23 | 1 | 0 1 |
| 36 | 2 | 1 2 |
| 45 | 3 | 0 3 |
| 23 | 1 | 1 1 |
| 36 | 2 | 0 3 |
| 45 | 3 | 1 3 |
+------------+------------------+--------------------------+
Expected Output
Notification Vs Resource Count
+----------+-------+------+------+
| Accountid Email | Push | Call |
+----------+-------+------+------+
| 1 | 2 | 1 | 2 |
+----------+-------+------+------+
Other Tables
AccountName
+----+-------+
| ID | Name |
+----+-------+
| 1 | Blues |
+----+-------+
| 2 | Jazz |
+----+-------+
| 3 | Rock |
+----+-------+
ResourceNames
+----------+----------------+-----------+
| Resource | Name | AccountID |
+----------+----------------+-----------+
| 23 | MJ | 1 |
| 36 | Paul | 1 |
| 45 | Jay Z | 3 |
+----------+----------------+-----------+
Progress Till Now
SELECT A.ID
,A.Name
,count(R.id) AS 'Total Resource Count'
,(SELECT count(DISTINCT np.resourceid)
FROM NotificationPreference np
INNER JOIN NotificationMaster nm ON np.notificationid = nm.id
WHERE np.accountid = A.ID
AND nm.id = 1
) AS 'Email'
FROM AccountName A
LEFT JOIN [ResourceNames] R ON A.ID = R.[AccountID]
LEFT JOIN NotificationPreference np ON np.resourceid = R.ID
GROUP BY A.ID
,A.Name
The basic pivot use conditional COUNT() :
SELECT Accountid
, COUNT( CASE WHEN nm.Name = 'Email' THEN 1 END ) as Email
, COUNT( CASE WHEN nm.Name = 'Push' THEN 1 END ) as Push
, COUNT( CASE WHEN nm.Name = 'Call' THEN 1 END ) as Call
FROM NotificationPreference np
JOIN NotificationMaster nm
ON np.NotificationID = nm.id
GROUP BY Accountid

Sum data from two tables with different number of rows

There are 3 Tables (SorMaster, SorDetail, and InvWarehouse):
SorMaster:
+------------+
| SalesOrder |
+------------+
| 100 |
| 101 |
| 102 |
+------------+
SorDetail:
+------------+------------+---------------+
| SalesOrder | MStockCode | MBackOrderQty |
+------------+------------+---------------+
| 100 | PN-1 | 4 |
| 100 | PN-2 | 9 |
| 100 | PN-3 | 1 |
| 100 | PN-4 | 6 |
| 101 | PN-1 | 6 |
| 101 | PN-3 | 2 |
| 102 | PN-2 | 19 |
| 102 | PN-3 | 14 |
| 102 | PN-4 | 6 |
| 102 | PN-5 | 4 |
+------------+------------+---------------+
InvWarehouse:
+------------+-----------+-----------+
| MStockCode | Warehouse | QtyOnHand |
+------------+-----------+-----------+
| PN-1 | A | 1 |
| PN-2 | B | 9 |
| PN-3 | A | 0 |
| PN-4 | B | 1 |
| PN-1 | A | 0 |
| PN-3 | B | 5 |
| PN-2 | A | 9 |
| PN-3 | B | 4 |
| PN-4 | A | 6 |
| PN-5 | B | 0 |
+------------+-----------+-----------+
Desired Results:
+------------+-----------------+--------------+
| MStockCode | SumBackOrderQty | SumQtyOnHand |
+------------+-----------------+--------------+
| PN-1 | 10 | 10 |
| PN-2 | 28 | 1 |
| PN-3 | 17 | 5 |
| PN-4 | 12 | 13 |
| PN-5 | 11 | 6 |
+------------+-----------------+--------------+
I have been going around in circles with no end in sight. Seems like it should be simple but just can't wrap my head around it. The SumBackOrderQty obviously getting counted twice as the SumQtyOnHand is evaluated. To this point I have been doing the calculations in the PHP instead of the select statement but would like to clean things up a bit where possible.
Current query statement is:
SELECT SorDetail.MStockCode,
SUM(SorDetail.MBackOrderQty) AS 'SumMBackOrderQty',
SUM(InvWarehouse.QtyOnHand) AS 'SumQtyOnHand'
FROM SysproCompanyJ.dbo.SorMaster SorMaster,
SysproCompanyJ.dbo.SorDetail SorDetail LEFT OUTER JOIN SysproCompanyJ.dbo.InvWarehouse InvWarehouse
ON SorDetail.MStockCode = InvWarehouse.StockCode
WHERE SorMaster.SalesOrder = SorDetail.SalesOrder
AND SorMaster.ActiveFlag != 'N'
AND SorDetail.MBackOrderQty > '0'
AND SorDetail.MPrice > '0'
GROUP BY SorDetail.MStockCode
ORDER BY SorDetail.MStockCode ASC
Without providing the complete picture, in terms of your RDBMS, database schema, a description of the problem you're trying to solve and sample data that matches the aforementioned, the following is just an illustration of what a solution based on Barmar's comment could look like:
SELECT SD.MStockCode,
SD.SumBackOrderQty,
IW.SumQtyOnHand
FROM (SELECT MStockCode,
SUM(MBackOrderQty) AS `SumBackOrderQty`
FROM SorDetail
JOIN SorMaster ON SorDetail.SalesOrder=SorMaster.SalesOrder
WHERE SorMaster.ActiveFlag != 'N'
AND SorDetail.MBackOrderQty > 0
AND SorDetail.MPrice > 0
GROUP BY MStockCode) AS SD
LEFT JOIN (SELECT MStockCode,
SUM(QtyOnHand) AS `SumQtyOnHand`
FROM InvWarehouse
GROUP BY MStockCode) AS IW ON SD.MStockCode=IW.MStockCode
ORDER BY SD.MStockCode;
Here's one approach:
select MStockCode,
(select sum(MBackOrderQty) from sorDetail as T2
where T2.MStockCode = T1.MStockCode ) as SumBackOrderQty,
(select sum(QtyOnHand) from invWarehouse as T3
where T3.MStockCode = T1.MStockCode ) as SumQtyOnHand
from
(
select mstockcode from sorDetail
union
select mstockcode from invWarehouse
) as T1
In a fiddle here: http://sqlfiddle.com/#!9/fdaca/6
Though my SumQtyOnHand values don't match yours (as #Gordon pointed out).

How to do this GROUP BY with the wanted result?

Basically, I have a table with all the bus stops of a route with the time_from_start value, that helps to put them in a good order.
CREATE TABLE `api_routestop` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`route_id` int(11) NOT NULL,
`station_id` varchar(10) NOT NULL,
`time_from_start` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `api_routestop_4fe3422a` (`route_id`),
KEY `api_routestop_15e3331d` (`station_id`)
)
I want to return for each stop of a line the time to go to the next stop.
I tried with this QUERY :
SELECT r1.station_id, r2.station_id, r1.route_id, COUNT(*), (r2.time_from_start - r1.time_from_start) as time
FROM api_routestop r1
LEFT JOIN api_routestop r2 ON r1.route_id = r2.route_id AND r1.id <> r2.id
GROUP BY r1.station_id
HAVING time >= 0
ORDER BY r1.route_id, r1.time_from_start, r2.time_from_start
But the group by seams not to work and the result looks like :
+------------+------------+----------+----------+------+
| station_id | station_id | route_id | COUNT(*) | time |
+------------+------------+----------+----------+------+
| Rub01 | Sal01 | 1 | 16 | 1 |
| Lyc02 | Sch02 | 2 | 17 | 2 |
| Paq01 | PoB01 | 3 | 15 | 1 |
| LaT02 | Gco02 | 4 | 16 | 1 |
| Sup01 | Tur01 | 5 | 132 | 1 |
| Oeu02 | CtC02 | 6 | 20 | 2 |
| Ver02 | Elo02 | 7 | 38 | 1 |
| Can01 | Mbo01 | 8 | 70 | 1 |
| Ver01 | Elo01 | 9 | 77 | 1 |
| MCH01 | for02 | 10 | 77 | 1 |
+------------+------------+----------+----------+------+
If I do that :
SELECT r1.station_id, r2.station_id, r1.route_id, COUNT(*), (r2.time_from_start - r1.time_from_start) as time
FROM api_routestop r1
LEFT JOIN api_routestop r2 ON r1.route_id = r2.route_id AND r1.id <> r2.id
GROUP BY r1.station_id, r2.station_id, r1.route_id
HAVING time >= 0
ORDER BY r1.route_id, r1.time_from_start, r2.time_from_start
I am approching :
+------------+------------+----------+----------+------+
| station_id | station_id | route_id | COUNT(*) | time |
+------------+------------+----------+----------+------+
| Rub01 | Sal01 | 1 | 1 | 1 |
| Rub01 | ARM01 | 1 | 1 | 2 |
| Rub01 | MaV01 | 1 | 1 | 4 |
| Rub01 | COl01 | 1 | 1 | 5 |
| Rub01 | Str01 | 1 | 1 | 6 |
| Rub01 | Jau01 | 1 | 1 | 7 |
| Rub01 | Cdp01 | 1 | 1 | 9 |
| Rub01 | Rep01 | 1 | 1 | 11 |
| Rub01 | CoT01 | 1 | 1 | 12 |
| Rub01 | Ctr01 | 1 | 1 | 14 |
| Rub01 | FLy01 | 1 | 1 | 15 |
| Rub01 | Lib01 | 1 | 1 | 17 |
| Rub01 | Bru01 | 1 | 1 | 18 |
| Rub01 | Sch01 | 1 | 1 | 20 |
| Rub01 | Lyc01 | 1 | 1 | 22 |
| Rub01 | Res01 | 1 | 1 | 24 |
| Sal01 | ARM01 | 1 | 1 | 1 |
| Sal01 | MaV01 | 1 | 1 | 3 |
| Sal01 | COl01 | 1 | 1 | 4 |
| Sal01 | Str01 | 1 | 1 | 5 |
| Sal01 | Jau01 | 1 | 1 | 6 |
| Sal01 | Cdp01 | 1 | 1 | 8 |
| Sal01 | Rep01 | 1 | 1 | 10 |
| Sal01 | CoT01 | 1 | 1 | 11 |
| Sal01 | Ctr01 | 1 | 1 | 13 |
| Sal01 | FLy01 | 1 | 1 | 14 |
| Sal01 | Lib01 | 1 | 1 | 16 |
| Sal01 | Bru01 | 1 | 1 | 17 |
| Sal01 | Sch01 | 1 | 1 | 19 |
| Sal01 | Lyc01 | 1 | 1 | 21 |
...
3769 rows in set (0.07 sec)
But what do I have to do to have only the first result for the same r1.station_id and r1.route_id ?
You're getting a lot of results back because your getting every stop joined to every other stop on the same route.
So you'll need to identify the "Next" stop as the stop that has the same route ID but has a minimum time from start later than the current one
Update Added routeId to the next_stop sub query to deal with the case of stations used in multiple routes
SELECT
r1.station_id,
r2.station_id,
r1.route_id,
r2.time_from_start - r1.time_from_start as time
FROM
api_routestop r1
INNER JOIN (SELECT
r1.station_id , r2.route_id, min(r2.time_from_start) next_time_from_start
FROM
api_routestop r1
LEFT JOIN api_routestop r2 ON r1.route_id = r2.route_id AND r1.id <> r2.id
and r2.time_from_start > r1.time_from_start
GROUP BY r1.Station_id, r2.route_id) next_stop
ON r1.Station_id = next_stop.station_id
and r1.route_id = next_stop.route_id
LEFT JOIN api_routestop r2
ON r2.time_from_start = r2.next_time_from_start
and r1.route_id = r2.route_id
AND r2.time_from_start > r1.time_from_start
SELECT station_id, coalesce(
(SELECT time_from_start
FROM api_routestop t2
WHERE t2.time_from_start > t1.time_from_start
AND t2.time_from_start <= (SELECT time_from_start FROM api_routestop t5 WHERE t5.station_id = '4' AND t5.route_id=t1.route_id)
AND t2.route_id = t1.route_id
ORDER BY t2.time_from_start LIMIT 1), time_from_start) - time_from_start AS difference
FROM api_routestop t1
WHERE t1.route_id = 1
AND t1.time_from_start >= (SELECT time_from_start FROM api_routestop t4 WHERE t4.station_id = '2' AND t4.route_id=t1.route_id)
AND t1.time_from_start <= (SELECT time_from_start FROM api_routestop t5 WHERE t5.station_id = '4' AND t5.route_id=t1.route_id)
ORDER BY time_from_start
Are you open to changing the schema? If so simply adding a column containing a sequential integer for all stops on route will make this query a lot easier and more efficient.
Failing that this will do it.
SELECT
station_id,
route_id,
time_from_start,
time_to_next
FROM
(
SELECT
station_id,route_id,time_from_start,
IF( #prev <> route_id, null, #time_from_start-time_from_start ) AS time_to_next,
#time_from_start := time_from_start,
#prev := route_id
FROM api_routestop
JOIN (SELECT #time_from_start := NULL, #prev := 0) AS r
ORDER BY route_id, time_from_start DESC
) t
ORDER BY route_id,time_from_start

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