I would like to create a query that operates similar to a cash register. Imagine a cash register full of coins of different sizes. I would like to retrieve a total value of coins in the fewest number of coins possible.
Given this table:
id
value
1
100
2
100
3
500
4
500
5
1000
How would I query for a list of rows that:
has a total value of AT LEAST a given threshold
with the minimum excess value (value above the threshod)
in the fewest possible rows
For example, if my threshold is 1050, this would be the expected result:
id
value
1
100
5
1000
I'm working with postgres and elixir/ecto. If it can be done in a single query great, if it requires a sequence of multiple queries no problem.
I had a go at this myself, using answers from previous questions:
Using ABS() to order by the closest value to the threshold
Select rows until a sum reduction of a single column reaches a threshold
Based on #TheImpaler's comment above, this prioritises minimum number of rows over minimum excess. It's not 100% what I was looking for, so open to improvements if anyone can, but if not I think this is going to be good enough:
-- outer query selects all rows underneath the threshold
-- inner subquery adds a running total column
-- window function orders by the difference between value and threshold
SELECT
*
FROM (
SELECT
i.*,
SUM(i.value) OVER (
ORDER BY
ABS(i.value - $THRESHOLD),
i.id
) AS total
FROM
inputs i
) t
WHERE
t.total - t.value < $THRESHOLD;
I am new to Postgres and would like to query the following table to get the average % of the total allocation at a user level from the following table:
e.g. I would like to get
Column 1 Columns 2
Label Avg Percent of the total from each user for a given label
Chickens 0.347
Goats 0.335
Does anybody understand what I am asking and would be able to point me in the right direction?
Are you just looking for group by?
select label, avg(percent_of_total)
from t
group by label;
I have a table with the following fields
ID,Content,QuestionMarks,TypeofQuestion
350, What is the symbol used to represent Bromine?,2,MCQ
758,What is the symbol used to represent Bromine? ,2,MCQ
2425,What is the symbol used to represent Bromine?,3,Essay
2080,A quadrilateral has four sides, four angles ,1,MCQ
2614,A circular cone has a curved surface area of ,2,MCQ
2520,Two triangles have sides 5 cm, 11 cm, 2 cm . ,2,MCQ
2196,Life supporting process mediated by water? ,2,Essay
I would like to get random questions where total marks is an input number.
For example if I say 25, the result should be all the random questions whose Sum(QuestionMarks) is 25(+/-1)
Is this really possible using a SQL
select content,id,questionmarks,sum(questionmarks) from quiz_question
group by content,id,questionmarks;
Expected Input 25
Expected Result (Sum of Question Marks =25)
Update:
How do I ensure I get atleast 2 Essay Type Questions (this is just an example) I would extend this for other conditions. Thank you for all the help
S-Man's cumulative sum is the right approach. For your logic, though, I think you want to get up to the first row that is 24 or more. That logic is:
where total - questionmark < 24
If you have enough questions, then you could get exactly 25 using:
with q25 as (
select *
from (select t.*,
sum(questionmark) over (order by random()) as running_questionmark
from t
) t
where running_questionmark < 25
)
select q.ID, q.Content, q.QuestionMarks, q.TypeofQuestion
from q25 q
union all
(select t.ID, t.Content, t.QuestionMarks, t.TypeofQuestion
from t cross join
(select sum(questionmark) as questionmark_25 from q25) x
where not exists (select 1 from q25 where q25.id = t.id)
order by abs(questionmark - (25 - questionmark_25))
limit 1
)
This selects questions up to 25 but not at 25. It then tries to find one more to make the total 25.
Supposing, questionmark is of type integer. Then you want to get some records in random order whose questionmark sum is not more than 25:
You can use the consecutive SUM() window function. The order is random. The consecutive SUM() adds every current value to the previous sum. So, you could filter where SUM() <= <your value>:
demo:db<>fiddle
SELECT
*
FROM (
SELECT
*,
SUM(questionmark) OVER (ORDER BY random()) as total
FROM
t
)s
WHERE total <= 25
Note:
This returns a records list with no more than 25, but as close as possible to it with an random order.
To find an exact match of your value is some sort of combinatorical problem which shouldn't be solved in a database. Especially when there's a random factor. What if your current SUM is 22 and the next randomly chosen value is 4. Would you retry maybe until infinity to randomly find a value = 3? Or are you trying to remove an already counted record with value = 1?
I am new to SQL and I got stuck at this problem.
There are three separate tables needed for this problem, with relevant information as follows
copies table rentalrates table movies table
movienum rentalcode rentalcode rate movienum title yearreleased
1000 D D 10 1000 Matrix 2001
... D WN 12 ... ... ...
... WN WL 15 ... ... ...
So I am required to display the output of "the title and year released of the movie that has the lowest rental rate" using sub queries, and "order by" is not allowed here.
final output like
title yearreleased rate
matrix 2001 10
My trouble is I don't really know hot to compare the rate and select those movies of the lowest rates.
Any help or hint is extremely appreciated :)
thanks a lot!
This query:
select min(rate) from rentalrates
will yield the minimum rental rate. To go one step further, this query:
select m.title as title,
m.yearreleased as yearreleased,
r.rate as rate
from copies as c,
rentalrates as r,
movies as m
where c.movienum = m.movienum
and r.rentalcode = c.rentalcode
and r.rate = select min(rate) from rentalrates;
will display any movies (title, year, rate) where the rate is the lowest rate in the database.
I would like to compare and get only stations which are within a distance range ONE TO THE OTHER. Let say I have 3 stations A-B-C they all have a position x-y-z. I would like to get the stations that are distant from 30 meters (I have a function to compute the distance so let's call it distance(x,y)).
SELECT * FROM Station WHERE distance(Station1, Station2) < 30
My problem is how can you compare distance of two different rows Station1 and Station2?
Thanks!!!
You could do something like this:
select a.*
from station a
inner join station b
on distance(a.station_id, b.station_id) < 30;