Create table based on max value - sql

I am working on a PostgreSQL database with data from car tracking which looks similar to this.
+--------+-------+---------+------------+
| car_id | trip | speed | Segment |
+--------+-------+---------+------------+
| 1 | 1 | 82 | s1 |
| 1 | 1 | 81 | |
| 1 | 1 | 85 | s1 |
| 1 | 2 | 82 | s1 |
| 1 | 2 | 76 | s2 |
| 2 | 3 | 80 | s1 |
| 2 | 3 | 84 | s2 |
| 2 | 3 | 83 | s2 |
+--------+-------+---------+------------+
Where every car has a specific car_id, and the trip changes based on that car_id or a change in date-time bigger than 5 sec. For every data point the speed is registered, and what part of the road the track belongs to (segment).
I would like to end up with a table where the maximum speed is shown, for each trip for each segment. If possible the car_id should be shown as well. It should look like this:
+-------+----------+------+------+
| trip | car_id | s1 | s2 |
+-------+----------+------+------+
| 1 | 1 | 85 | |
| 2 | 1 | 82 | 76 |
| 3 | 2 | 80 | 84 |
+-------+----------+------+------+
I have tried to use a group by but I can't make it work. I will be grateful if anyone can help.

I think this is just conditional aggregation:
select trip_id, car_id,
max(speed) filter (where segment = 's1') as s1,
max(speed) filter (where segment = 's2') as s2
from t
group by trip_id, car_id

Related

How to determine top x rows with a group by - SQL Server 2017

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

DB2 SQL - Limit the number of groups returned

I am trying to find a way to limit the first n groups returned. I have a scenario where I want to only select 10 groups of user data and no more. How would I limit 10 groups of user data where the group size for the user can vary. Some groups may have more than 4 records for a user, some may have less than 4 records for a user. But I only want to get 10 users at a time. I tried thinking about how ROW_NUMBER() and PARTITION BY could be leveraged or even FETCH FIRST N ROWS ONLY could be leveraged, but couldn't come up with a solution.
Below is some sample data. NOTE: The GROUP_NUMBER column doesn't exist in the data set I am working with. It is what I was thinking about creating via SQL so that I can leverage this to select where the "GROUP_NUMBER" < 11 for example. I am absolutely open to other solutions given my question, but this was one solution I was thinking about but didn't know how to do it.
+-----------+--------------+-----------+-----------+----------+------------------+--------------+
| REQUESTID | USERID | COMPANYID | FIRSTNAME | LASTNAME | EMAIL | GROUP_NUMBER |
+-----------+--------------+-----------+-----------+----------+------------------+--------------+
| 157 | test.bulkup1 | 44 | BulkUp | Test | bulkup1#test.com | 1 |
| 157 | test.bulkup1 | 44 | BulkUp | Test | bulkup1#test.com | 1 |
| 157 | test.bulkup1 | 44 | BulkUp | Test | bulkup1#test.com | 1 |
| 162 | test.bulkup2 | 44 | BulkUp | Test | bulkup2#test.com | 2 |
| 162 | test.bulkup2 | 44 | BulkUp | Test | bulkup2#test.com | 2 |
| 162 | test.bulkup2 | 44 | BulkUp | Test | bulkup2#test.com | 2 |
| 162 | test.bulkup2 | 44 | BulkUp | Test | bulkup2#test.com | 2 |
| 187 | test.bulkup3 | 44 | BulkUp | Test | bulkup3#test.com | 3 |
| 187 | test.bulkup3 | 44 | BulkUp | Test | bulkup3#test.com | 3 |
| 187 | test.bulkup3 | 44 | BulkUp | Test | bulkup3#test.com | 3 |
| 187 | test.bulkup3 | 44 | BulkUp | Test | bulkup3#test.com | 3 |
| 192 | test.bulkup4 | 44 | BulkUp | Test | bulkup4#test.com | 4 |
+-----------+--------------+-----------+-----------+----------+------------------+--------------+
You can use dense_rank(). I think you want:
select t.*
from (select t.*,
dense_rank() over (order by requestId) as seqnum
from t
) t
where seqnum <= 3;

find other columns value based on maximum of one column using groupby particular column

I have data like below
+-------+---------+--------+
| Count | Mindif | Device |
+-------+---------+--------+
| 45 | 3 | A |
| 78 | 4 | A |
| 52 | 5 | A |
| 24 | 6 | A |
| 22 | 1 | B |
| 22 | 2 | B |
| 34 | 3 | B |
| 37 | 4 | B |
| 52 | 5 | B |
| 34 | 6 | B |
| 13 | 1 | C |
| 30 | 2 | C |
| 57 | 3 | C |
| 111 | 4 | C |
| 35 | 5 | C |
+-------+---------+--------+
Want to find Mindif and device based on max value of count.
Output be like
+-------+---------+--------+
| Count | Mindif | Device |
+-------+---------+--------+
| 78 | 4 | A |
| 52 | 5 | B |
| 111 | 4 | C |
+-------+---------+--------+
You can use a query like this:
SELECT t1.Count, t1.Mindif, t1.Device
FROM mytable AS t1
JOIN (
SELECT Device, MAX(Count) AS Count
FROM mytable
GROUP BY Device
) AS t2 ON t1.Device = t2.Device AND t1.Count = t2.Count
The query uses a derived table that returns the max Count value per Device. Joining back to the original table we can get the desired result.
using Window Function
SELECT Count, Mindif, Device
FROM
(SELECT Count, Mindif, Device,
rank() over (order by Count desc) as r
FROM table) S
WHERE S.r = 1;
OR
Simple Join with MAX
SELECT a.* FROM table a
LEFT SEMI JOIN
(SELECT MAX(Count)Cnt
FROM table)b on (a.Count = b.Cnt)

How to update a row with the first value of that group if another column matches?

My issue is pretty straight forward, all of the queries we have tried error out. I am a novice user and am still learning the SQL language, any help would be very appreciated.
I'm attempting to update a table to where if the rate column matches Mat ID will update with the first value from that grouping.
+------+--------+
| Rate | Mat ID |
+------+--------+
| 1 | 81 |
| 2 | 82 |
| 2 | 83 |
| 3 | 85 |
| 2 | 86 |
| 2 | 87 |
| 3 | 88 |
+------+--------+
Expected result:
+------+--------+
| Rate | Mat ID |
+------+--------+
| 1 | 81 |
| 2 | 82 |
| 2 | 82 |
| 3 | 85 |
| 2 | 82 |
| 2 | 82 |
| 3 | 85 |
+------+--------+
Assuming the following:
Your definition of 'first' means the minimum value per grouping.
Typo on the last row in your expected results should be 85 and not 88.
The following UPDATE statement meets your requirements:
;
WITH CTE_MinMatID
AS (
SELECT Rate,
MIN(MatID) MinMatID
FROM #table
GROUP BY Rate
)
UPDATE t
SET t.MatID = cte.MinMatID
FROM #table AS t
INNER JOIN CTE_MinMatID cte ON cte.Rate = t.Rate;
Working example here.

MS Access SQL query from 3 tables

I have 3 tables shown below in MS Access 2010:
Table: devices
id | device_id | Company | Version | Revision |
-----------------------------------------------
1 | dev_a | Almaras | 1.5.1 | 0.2A |
2 | dev_b | Enigma | 1.5.1 | 0.2A |
3 | dev_c | Almaras | 1.5.1 | 0.2C |
*Field: device_id is Primary Key Unique String
*Field ID is just an auto-number column
Table: activities
id | act_id | act_date | act_type | act_note |
------------------------------------------------
1 | dev_a | 07/22/2013 | usb_axc | ok |
2 | dev_a | 07/23/2013 | usb_axe | ok | (LAST ROW for dev_a)
3 | dev_c | 07/22/2013 | usb_axc | ok | (LAST ROW for dev_c)
4 | dev_b | 07/21/2013 | usb_axc | ok | (LAST ROW for dev_b)
*Field: act_id contains device_id; NOT UNIQUE
*Field ID is just an auto-number column
Table: matrix
id | mat_id | tc | ts | bat | cycles |
-----------------------------------------
1 | dev_a | 2811 | 10 | 99 | 200 |
2 | dev_a | 2911 | 10 | 97 | 400 |
3 | dev_a | 3007 | 10 | 94 | 600 |
4 | dev_a | 3210 | 10 | 92 | 800 | (LAST ROW for dev_d)
5 | dev_b | 1100 | 5 | 98 | 100 |
6 | dev_b | 1300 | 8 | 93 | 200 |
7 | dev_b | 1411 | 11 | 90 | 300 | (LAST ROW for dev_b)
8 | dev_c | 4000 | 27 | 77 | 478 | (LAST ROW for dev_c)
*Field: mat_id contains device_id; NOT UNIQUE
*Field ID is just an auto-number column
Is there any way to query tables to get results as shown below (each device from devices and only last row added [see example output table] from each of the other two tables):
Query Results:
device_id | Company | act_date | act_type | bat | cycles |
------------------------------------------------------------
device_a | Almaras | 07/23/2013 | usb_axe | 92 | 800 |
device_b | Enigma | 07/21/2013 | usb_axc | 90 | 300 |
device_c | Almaras | 07/22/2013 | usb_axc | 77 | 478 |
Any ideas? Thank you in advance for reading and helping me out :)
I think is what you want,
SELECT a.device_id, a.Company,
b.act_date, b.act_type,
c.bat, c.cycles
FROM ((((devices AS a
INNER JOIN activities AS b
ON a.device_id = b.act_id)
INNER JOIN matrix AS c
ON a.device_id = c.mat_id)
INNER JOIN
(
SELECT act_id, MAX(act_date) AS max_date
FROM activities
GROUP BY act_id
) AS d ON b.act_id = d.act_id AND b.act_date = d.max_date)
INNER JOIN
(
SELECT mat_id, MAX(tc) AS max_tc
FROM matrix
GROUP BY mat_id
) AS e ON c.mat_id = e.mat_id AND c.tc = e.max_tc)
The subqueries: d and e separately gets the latest row for every act_id.
Try
SELECT devices.device_id, devices.Company, activities.act_data, activities.act_type, matrix.bat, matrix.cycles
FROM devices
LEFT JOIN activities
ON devices.device_id = activities.act_id
LEFT JOIN matrix
ON devices.device_id = matrix.mat_id;
What do you consider the "last" row in Matrix?
You need to do something like
WHERE act_date in (SELECT max(a.act_date) from activities a where a.mat_id=d.device_id GROUP BY a.mat_id)
and something similar for the join to matrix.