How to join different speed limit to one segment in Postgresql? - postgresql

I need to join speed limit to a network. However, in the network data, some of the segments have different speed limit. For example, a street has two different speed limit in the beginning and in the end. Because of that I get this error:
SQL Error [21000]: ERROR: more than one row returned by a subquery used as an expression
Do you have any suggestions?
This is my current query:
ALTER TABLE speed_signs_geob
ADD COLUMN speed SMALLINT NOT NULL DEFAULT 50;
UPDATE speed_signs_geob
SET speed = CASE
WHEN description_rpa = 'MAXIMUM 10 KM/H' THEN 10
WHEN description_rpa = 'MAXIMUM 20' THEN 20
WHEN description_rpa = 'MAXIMUM 30' THEN 30
WHEN description_rpa = 'MAXIMUM 30 SECTEUR' THEN 30
WHEN description_rpa = 'MAXIMUM 40' THEN 40
WHEN description_rpa = 'MAXIMUM 40 SECTEUR' THEN 40
WHEN description_rpa = 'MAXIMUM 50' THEN 50
WHEN description_rpa = 'MAXIMUM 60' THEN 60
WHEN description_rpa = 'MAXIMUM 70' THEN 70
ELSE 50
END
;
UPDATE mtl_road_network
SET speed = (SELECT (speed) FROM speed_signs_geob s WHERE s.seg_id = seg_id);

Related

"partition by" giving incorrect value

battery_pct tstamp charging phone_id
90 t1 yes 12
91 t2 yes 22
95 t3 no 22
89 t4 no 22
87 t5 no 22
80 t6 no 22
78 t7 yes 22
85 t8 yes 4
50 t9 no 4
40 t10 no 4
38 t11 no 4
20 t12 yes 4
I want to calculate battery depletion rate as : change in battery / time taken
This should be calculated for ALL the windows when charging is 'no' (sandwiched in between 2 "yes"), and then the average of those rates should be taken.
So, for this dataset it should be:
95 - 80 / t6 - t3 = rate for phone_id 22
50 - 38 / t11 - t9 = rate for phone_id 4
average rate = ( rate 1 + rate 2 ) / 2
Please note there can be more than one windows of no's for each phone_id in the data.
I have to find average rate across ALL phone id's. i.e. one value for average rate which encompasses all phones.
Here is my current code, it does not give any error, but is returning a value that is NOT plausible -
with discharge_intervals as (
select battery_pct, tstamp,
sum((charging = 'yes')::int) over (partition by phone_id order by tstamp) as ival_number,
charging = 'no' as keep
from dataset
), interval_rates as (
select ival_number,
(max(battery_pct) - min(battery_pct))
/ extract(epoch from max(tstamp) - min(tstamp)) as ival_rate
from discharge_intervals
where keep
group by ival_number
)
select avg(ival_rate)
from interval_rates;
Your interval_rates are calculated without grouping by phone, but should be. The ival_numbers are partitioned by phone_id, but that just means multiple phones will create rows with the same ival_number. You'll want to use
with discharge_intervals as (
select battery_pct, tstamp, phone_id,
-- ^^^^^^^^^
sum((charging = 'yes')::int) over (partition by phone_id order by tstamp) as ival_number,
charging = 'no' as keep
from dataset
), interval_rates as (
select (max(battery_pct) - min(battery_pct))
/ extract(epoch from max(tstamp) - min(tstamp)) as ival_rate
from discharge_intervals
where keep
group by phone_id, ival_number
-- ^^^^^^^^^
)
select avg(ival_rate)
from interval_rates;

Add condition to where clause in q/kdb+

Table Tab
minThreshold
maxThreshold
point
1000
10000
10
wClause,:enlist((';~:;<);`qty;Tab[`minThreshold])
trying to incorporate maxThreshold column to where clause
qty >= MinThreshold
qty <= MaxThreshold
something like
wClause,:enlist((';~:;<);`qty;Tab[`minThreshold]);Tab[`maxThreshold])
q)Tab:([] minThreshold:500 1000;maxThreshold:700 2000;point:5 10)
q)Tab
minThreshold maxThreshold point
-------------------------------
500 700 5
1000 2000 10
q)select from Tab where minThreshold>=900,maxThreshold<=2500
minThreshold maxThreshold point
-------------------------------
1000 2000 10
q)parse"select from Tab where minThreshold>=900,maxThreshold<=2500"
?
`Tab
,(((';~:;<);`minThreshold;900);((';~:;>);`maxThreshold;2500))
0b
()
q)?[Tab;((>=;`minThreshold;900);(<=;`maxThreshold;2500));0b;()]
minThreshold maxThreshold point
-------------------------------
1000 2000 10
See the whitepaper for more information on functional selects:
https://code.kx.com/q/wp/parse-trees/
Is your problem
you have a Where phrase that works for functional qSQL and you want to extend it?
you want to select rows of a table where the value of a quantity falls within an upper and lower bound?
If (2) you can use Join Each to get the bounds for each row, and within to test the quantity.
q)show t:([]lwr:1000 900 150;upr:10000 25000 500;qty:10 1000 450)
lwr upr qty
---------------
1000 10000 10
900 25000 1000
150 500 450
q)select from t where qty within' lwr{x,y}'upr
lwr upr qty
--------------
900 25000 1000
150 500 450
Above we use {x,y} because in qSQL queries comma does not denote Join.

Postgres: calculate the percentage of successful events per day of week

For each city in my dataset and each day of the week, I need to determine the percentage of signups in the first week of 2016 that resulted in a completed trip within 168 hours of the sign up date.
So far I can calculate the overall percentage for each city with
select cities.city_name, round( 100.0 * (sum(case when event_name='sign_up_success' then 1 end)) / count(events), 2) as percent from
trips inner join events on
trips.client_id = events.rider_id inner join cities on
trips.city_id = cities.city_id
group by city_name;
however, when I try to add a over (partition by date_trunc('day', event._ts)) clause the error states round cannot be used as a aggregate or window function.
The closest I am able to get is the following,
select cities.city_name,
round( 100.0 * (sum(case when event_name='sign_up_success' then 1 end)) / count(events), 2) as percent
from trips
inner join events
on trips.client_id = events.rider_id
inner join cities
on trips.city_id = cities.city_id
where trips.status = 'completed'
and events._ts < '2016-01-08'
and (trips.request_at - events._ts) < interval '168 hours'
group by cities.city_name;
How can I extend this such that the percentage of completed trips is calculated per day? e.g.
Day | City_1 | City_2
1 | 45 | 25
2 | 0 | 66
3 | 100 | 25
4 | 45 | 75
etc

Use Group By without Aggregate

I have below data
UserId Val txt
100 10 A
200 25 B
100 30 GV
300 15 BHG
200 20 BGV
and want to write a query that give min(val) for each user
Result :
100 10 A
200 20 BGV
300 15 BHG
Try this:
SELECT DISTINCT ON (userID) *
FROM your_table
ORDER BY userID, val

Complicated AVG within date range

I've got a table with a tracking of a plant's equipment installation.
Here is a sample:
ID Name Date Percentage
1 GT-001 2011-01-08 30
2 GT-002 2011-01-11 40
3 GT-003 2011-02-02 30
4 GT-001 2011-02-03 50
5 GT-003 2011-02-15 50
6 GT-004 2011-02-15 30
7 GT-002 2011-02-15 60
8 GT-001 2011-02-20 60
9 GT-003 2011-03-01 60
10 GT-004 2011-03-05 50
11 GT-001 2011-03-10 70
12 GT-004 2011-03-15 60
And the corresponding script:
CREATE TABLE [dbo].[SampleTable](
[ID] [int] NOT NULL,
[Name] [nvarchar](50) NULL,
[Date] [date] NULL,
[Percentage] [int] NULL) ON [PRIMARY]
GO
--Populate the table with values
INSERT INTO [dbo].[SampleTable] VALUES
('1', 'GT-001', '2011-01-08', '30'),
('2', 'GT-002', '2011-01-11', '40'),
('3', 'GT-003', '2011-02-02', '30'),
('4', 'GT-001', '2011-02-03', '50'),
('5', 'GT-003', '2011-02-15', '50'),
('6', 'GT-004', '2011-02-15', '30'),
('7', 'GT-002', '2011-02-15', '60'),
('8', 'GT-001', '2011-02-20', '60'),
('9', 'GT-003', '2011-03-01', '60'),
('10', 'GT-004', '2011-03-05', '50'),
('11', 'GT-001', '2011-03-10', '70'),
('12', 'GT-004', '2011-03-15', '60');
GO
What i need is to create a chart with Date on the X and Average Percentage on the Y. Average Percentage is an average percentage of all equipment by that particular date starting from the beggining of the installation process (MIN(Fields!Date.Value, "EquipmentDataset"))
Having no luck in implementing this using SSRS only, i decided to create a more complicated dataset for it using T-SQL.
I guess that it is nessesary to add a calculated column named 'AveragePercentage' that should store an average percentage on that date, calculating only the most latest equipment percentage values in a range between the beggining of the installation process (MIN(Date)) and the current row's date. Smells like a recursion, but i'm newbie to T-SQL....))
Here is the desired output
ID Name Date Percentage Average
1 GT-001 2011-01-08 30 30
2 GT-002 2011-01-11 40 35
3 GT-003 2011-02-02 30 33
4 GT-001 2011-02-03 50 40
5 GT-003 2011-02-15 50 48
6 GT-004 2011-02-15 30 48
7 GT-002 2011-02-15 60 48
8 GT-001 2011-02-20 60 50
9 GT-003 2011-03-01 60 53
10 GT-004 2011-03-05 50 58
11 GT-001 2011-03-10 70 60
12 GT-004 2011-03-15 60 63
What do you think?
I'll be very appreciated for any help.
You could use cross apply with row_number to find the latest value for each machine. An additional subquery is required because you cannot use row_number in the where clause directly. Here's the query:
select t1.id
, t1.Name
, t1.Date
, t1.Percentage
, avg(1.0*last_per_machine.percentage)
from SampleTable t1
outer apply
(
select *
from (
select row_number() over (partition by Name order by id desc)
as rn
, *
from SampleTable t2
where t2.date <= t1.date
) as numbered
where rn = 1
) as last_per_machine
group by
t1.id
, t1.Name
, t1.Date
, t1.Percentage
Working example on SE Data.