I have a dataset that looks like the following:
| Category | Employee | Output |
|:--------:|:--------:|:------:|
| Top | A | 97 |
| Mid | B | 50 |
| Mid | C | 35 |
| Mid | D | 45 |
| Low | E | 15 |
| Low | F | 16 |
| Top | G | 92 |
| Top | H | 84 |
| Mid | I | 49 |
| Mid | J | 31 |
| Low | K | 22 |
| Top | L | 79 |
| Mid | M | 63 |
| Mid | N | 33 |
| Low | O | 19 |
| Mid | P | 33 |
| Top | Q | 77 |
| Top | R | 88 |
| Low | S | 30 |
| Mid | T | 53 |
| Mid | U | 68 |
| Mid | V | 72 |
| Mid | W | 66 |
| Mid | X | 51 |
| Mid | Y | 35 |
| Mid | Z | 70 |
(The real dataset is much larger, about ~20K Rows)
I am trying to find the top 3 output numbers for each group. Ultimately resulting in a dataset like:
| Low | 30 |
|:---:|:--:|
| Low | 22 |
| Low | 19 |
| Mid | 72 |
| Mid | 70 |
| Mid | 68 |
| Top | 97 |
| Top | 92 |
| Top | 88 |
I have tried:
SELECT TOP 10
Category,
Output
FROM
raw_data
ORDER BY
Output DESC
But that only lists the top 10 overall, not by category.
Adding
GROUP BY Category, Count_Placements obviously does nothing, and I cannot group by Category itself.
Sorry there is no SQL Fiddle like I normally do, it is currently down.
You can use row_number():
select category, output
from (
select t.*, row_number() over(partition by category order by output desc) rn
from mytable t
) t
where rn <= 3
order by category, output desc
I have the following SQL table.
+----+--------+----------+--------+
| ID | TestNo | TestName | HeadID |
+----+--------+----------+--------+
| 1 | 21 | Comp-1 | null |
| 2 | 22 | C1 | 21 |
| 3 | 23 | C2 | 21 |
| 4 | 24 | C3 | 21 |
| 5 | 47 | Comp-2 | null |
| 6 | 25 | C4 | 47 |
| 7 | 26 | C1+ | 21 |
+----+--------+----------+--------+
I want to get all the child rows (according to their HeadID) below their head test.
select * from ranges order by HeadID
The ACTUAL OUPUT I get from the above query:
+----+--------+----------+--------+
| ID | TestNo | TestName | HeadID |
+----+--------+----------+--------+
| 1 | 21 | Comp-1 | null |
| 5 | 47 | Comp-2 | null |
| 2 | 22 | C1 | 21 |
| 3 | 23 | C2 | 21 |
| 4 | 24 | C3 | 21 |
| 7 | 26 | C1+ | 21 |
| 6 | 25 | C4 | 47 |
+----+--------+----------+--------+
but my DESIRED OUTPUT is:
+----+--------+----------+--------+
| ID | TestNo | TestName | HeadID |
+----+--------+----------+--------+
| 1 | 21 | Comp-1 | null |
| 2 | 22 | C1 | 21 |
| 3 | 23 | C2 | 21 |
| 4 | 24 | C3 | 21 |
| 7 | 26 | C1+ | 21 |
| 5 | 47 | Comp-2 | null |
| 6 | 25 | C4 | 47 |
+----+--------+----------+--------+
How can I achieve this?
If you have only one level of children, then you can achieve this ordering like this:
SELECT *
FROM Ranges
ORDER BY
CASE WHEN HeadID IS NULL THEN TestNo ELSE HeadID END
,HeadID
,ID
;
+----+---------------+--------------------+------------+----------+-----------------+
| id | restaurant_id | filename | is_profile | priority | show_in_profile |
+----+---------------+--------------------+------------+----------+-----------------+
| 40 | 20 | 1320849687_390.jpg | | | 1 |
| 60 | 24 | 1320853501_121.png | 1 | | 1 |
| 61 | 24 | 1320853504_847.png | | | 1 |
| 62 | 24 | 1320853505_732.png | | | 1 |
| 63 | 24 | 1320853505_865.png | | | 1 |
| 64 | 29 | 1320854617_311.png | 1 | | 1 |
| 65 | 29 | 1320854617_669.png | | | 1 |
| 66 | 29 | 1320854618_636.png | | | 1 |
| 67 | 29 | 1320854619_791.png | | | 1 |
| 74 | 154 | 1320922653_259.png | | | 1 |
| 76 | 154 | 1320922656_332.png | | | 1 |
| 77 | 154 | 1320922657_106.png | | | 1 |
| 84 | 130 | 1321269380_960.jpg | 1 | | 1 |
| 85 | 130 | 1321269383_555.jpg | | | 1 |
| 86 | 130 | 1321269384_251.jpg | | | 1 |
| 89 | 28 | 1321269714_303.jpg | | | 1 |
| 90 | 28 | 1321269716_938.jpg | 1 | | 1 |
| 91 | 28 | 1321269717_147.jpg | | | 1 |
| 92 | 28 | 1321269717_774.jpg | | | 1 |
| 93 | 28 | 1321269717_250.jpg | | | 1 |
| 94 | 28 | 1321269718_964.jpg | | | 1 |
| 95 | 28 | 1321269719_830.jpg | | | 1 |
| 96 | 43 | 1321270013_629.jpg | 1 | | 1 |
+----+---------------+--------------------+------------+----------+-----------------+
I have this table and I want to select the filename for a given list of restaurants ids.
For example for 24,29,154:
+----+---------------
| filename |
+----+---------------
1320853501_121.png (has is_profile 1)
1320854617_311.png (has is_profile 1)
1320922653_259.png (chosen as profile picture because restaurant doesn't have a profile pic but has pictures)
I tried group by and case statements but I got nowhere.Also if you use group by it should be a full group by.
You can do this with aggregation and some logic:
select restaurant_id,
coalesce(max(case when is_profile = 1 then filename end),
max(filename)
) as filename
from t
where restaurant_id in (24, 29, 154)
group by restaurant_id;
First look for the/a profile filename. Next just choose an arbitrary one.
I have the following table named foo:
ID | D1 | D2 | D3 |
---------------------
1 | 47 | 3 | 71 |
2 | 47 | 98 | 82 |
3 | 0 | 99 | 3 |
4 | 3 | 100 | 6 |
5 | 48 | 10 | 3 |
6 | 49 | 12 | 4 |
I want to run a select query and have the results show like this
ID | D1 | D2 | D3 | Result |
------------------------------
1 | 47 | 3 | 71 | D3 |
2 | 47 | 98 | 82 | D2 |
3 | 0 | 99 | 3 | D2 |
4 | 3 | 100 | 6 | D2 |
5 | 48 | 10 | 3 | D1 |
6 | 49 | 12 | 4 | D1 |
So, basically I want to get Maximum value between D1, D2, D3 column divided by id.
As You may seen , ID 1 have D3 in the Result column since Maximum value between
D1 : D2 : D3
That Means 4 : 3 : 71 , Max value is 71. Thats Why The Result show 'D3'
Is there a way to do this in a sql query ?
Thanks!
For Oracle please try this one
select foo.*, case when greatest(d1, d2, d3) = d1 then 'D1'
when greatest(d1, d2, d3) = d2 then 'D2'
when greatest(d1, d2, d3) = d3 then 'D3'
end result
from foo
Consider the following - a normalized approach...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL
,d INT NOT NULL
,val INT NOT NULL
,PRIMARY KEY(id,d)
);
INSERT INTO my_table VALUES
(1,1,47),
(2,1,47),
(3,1,0),
(4,1,3),
(5,1,48),
(6,1,49),
(1,2,3),
(2,2,98),
(3,2,99),
(4,2,100),
(5,2,10),
(6,2,12),
(1,3,71),
(2,3,82),
(3,3,3),
(4,3,6),
(5,3,3),
(6,3,4);
SELECT * FROM my_table;
+----+---+-----+
| id | d | val |
+----+---+-----+
| 1 | 1 | 47 |
| 1 | 2 | 3 |
| 1 | 3 | 71 |
| 2 | 1 | 47 |
| 2 | 2 | 98 |
| 2 | 3 | 82 |
| 3 | 1 | 0 |
| 3 | 2 | 99 |
| 3 | 3 | 3 |
| 4 | 1 | 3 |
| 4 | 2 | 100 |
| 4 | 3 | 6 |
| 5 | 1 | 48 |
| 5 | 2 | 10 |
| 5 | 3 | 3 |
| 6 | 1 | 49 |
| 6 | 2 | 12 |
| 6 | 3 | 4 |
+----+---+-----+
SELECT x.*
FROM my_table x
JOIN
( SELECT id,MAX(val) max_val FROM my_table GROUP BY id) y
ON y.id = x.id
AND y.max_val = x.val;
+----+---+-----+
| id | d | val |
+----+---+-----+
| 1 | 3 | 71 |
| 2 | 2 | 98 |
| 3 | 2 | 99 |
| 4 | 2 | 100 |
| 5 | 1 | 48 |
| 6 | 1 | 49 |
+----+---+-----+
(This is intended as a MySQL solution - I'm not familiar with ORACLE syntax, so apologies if this doesn't port)
Does this answer your comment?
SELECT x.* , y.max_val
FROM my_table x
JOIN
( SELECT id,MAX(val) max_val FROM my_table GROUP BY id) y
ON y.id = x.id ;
+----+---+-----+---------+
| id | d | val | max_val |
+----+---+-----+---------+
| 1 | 1 | 47 | 71 |
| 1 | 2 | 3 | 71 |
| 1 | 3 | 71 | 71 |
| 2 | 1 | 47 | 98 |
| 2 | 2 | 98 | 98 |
| 2 | 3 | 82 | 98 |
| 3 | 1 | 0 | 99 |
| 3 | 2 | 99 | 99 |
| 3 | 3 | 3 | 99 |
| 4 | 1 | 3 | 100 |
| 4 | 2 | 100 | 100 |
| 4 | 3 | 6 | 100 |
| 5 | 1 | 48 | 48 |
| 5 | 2 | 10 | 48 |
| 5 | 3 | 3 | 48 |
| 6 | 1 | 49 | 49 |
| 6 | 2 | 12 | 49 |
| 6 | 3 | 4 | 49 |
+----+---+-----+---------+
I've got the following SQL which basically works out the costings etc for each item.
SELECT
L.LocID,
L.LocationName,
L.LocationSqrMtr,
L.LocationAddress,
L.LocationPostCode,
L.LocationContact,
I.SubPIDItemID,
I.SPID,
I.ProductID,
C.SubPIDCostID,
C.PricePerItem,
C.ManDayPerItem
FROM
dbo.SubPIDCosts AS C
INNER JOIN dbo.SubPIDItems AS I ON
C.ProductID = I.ProductID
RIGHT OUTER JOIN dbo.SubPIDLocations AS L ON
I.LocationID = L.LocID AND C.LocationID = L.LocID
WHERE C.SPID = 48
This returns:
+-------+--------------+----------------+-----------------+------------------+-----------------+--------------+----------+-----------+--------------+--------------+---------------+-----+----+---+-----+--------+--------+--------+------+
| LocID | LocationName | LocationSqrMtr | LocationAddress | LocationPostCode | LocationContact | SubPIDItemID | SPID | ProductID | SubPIDCostID | PricePerItem | ManDayPerItem | | | | | | | | |
+-------+--------------+----------------+-----------------+------------------+-----------------+--------------+----------+-----------+--------------+--------------+---------------+-----+----+---+-----+--------+--------+--------+------+
| 379 | | | Location | 1 | 1 | 345 | Generic | Building | Generic | Building | NULL | 158 | 48 | | | | 108 | 0.3400 | 6.17 |
| 379 | | | Location | 1 | 1 | 345 | Generic | Building | Generic | Building | NULL | 159 | 48 | 1 | 109 | 0.3400 | | .47 | |
| 379 | 3 | Location | 1 | 615 | Generic | Building | Generic | Building | NULL | 160 | 48 | | | | 110 | 0.7317 | 0.50 | | |
| 379 | 4 | Location | | | 615 | Generic | Building | Generic | Building | NULL | 161 | 48 | | | | 111 | 0.7317 | 0.50 | |
| 379 | 4 | Location | | | 615 | Generic | Building | Generic | Building | NULL | 16 | | 48 | 1 | 11 | | 0.7317 | 0.50 | |
+-------+--------------+----------------+-----------------+------------------+-----------------+--------------+----------+-----------+--------------+--------------+---------------+-----+----+---+-----+--------+--------+--------+------+
But what I would like to do is group it by the product ID. So all the ones that are ProductID 22 it should add the values up for ManDayPerItem and PricePerItem and LocationSqrMtr
It's used in the following context
I'd like to have them grouped nicely in that list.
As you said, group by:
SELECT ProductID, SUM(ManDayPerItem), SUM(PricePerItem), SUM(LocationSqrMtr)
FROM
dbo.SubPIDCosts AS C
INNER JOIN dbo.SubPIDItems AS I ON
C.ProductID = I.ProductID
RIGHT OUTER JOIN dbo.SubPIDLocations AS L ON
I.LocationID = L.LocID AND C.LocationID = L.LocID
WHERE C.SPID = 48
GROUP BY ProductID;