SQL Interview: Repeating Rows Based on a Ratio


Given a table with a ratio column, expand each row so that it appears ceil(1/ratio) times in the output.

dataratio
a0.3
b0.5
c0.4
d1.0

Expected output:

value
a
a
a
a
b
b
c
c
c
d

Setup

create table public.log
(
    data  text,
    ratio double precision
);
INSERT INTO public.log (data, ratio) VALUES ('a', 0.3);
INSERT INTO public.log (data, ratio) VALUES ('b', 0.5);
INSERT INTO public.log (data, ratio) VALUES ('c', 0.4);
INSERT INTO public.log (data, ratio) VALUES ('d', 1);

Verify the source data:

select data, ratio from log;
valueratio
a0.3
b0.5
c0.4
d1.0

Compute the repetition count per row:

select data, ceil(1/ratio) from log;
valueceil
a4
b2
c3
d1

Approach 1: generate_series

generate_series produces a set of integers from 1 to N. Joining each row against a series of the appropriate length repeats it the right number of times:

SELECT generate_series(1, ceil(1/.2)::integer);
value
1
2
3
4
5

Applied to the full table:

select data
  from log
  join generate_series(1, ceil(1/ratio)::integer) as series on true;
value
a
a
a
a
b
b
c
c
c
d

Approach 2: array_fill + unnest

An alternative using array_fill to construct an array of the target length, then unnest to expand it into rows.

array_fill creates an array of a given value repeated N times:

SELECT array_fill(0, ARRAY[5]);
value
{0,0,0,0,0}

unnest explodes an array into individual rows:

SELECT unnest(array_fill(0, ARRAY[5]));
value
0
0
0
0
0

Combine with the source table:

select l.data
  from log l
  join unnest(array_fill(0, ARRAY[ceil(1/l.ratio)::integer])) on true;
value
a
a
a
a
b
b
c
c
c
d

Both approaches produce the same result. generate_series is more idiomatic for integer ranges; array_fill + unnest is useful when working with existing array data or when the range logic is more complex.