Вы можете использовать row_number с разделением на animal
:
CREATE TABLE sample(animal, id) AS
VALUES
('Dog', 1),
('Cat', 2),
('Dog', 3),
('Dog', 4),
('Cat', 5),
('Dog', 6),
('Dog', 7),
('Dog', 8),
('Cat', 9),
('Dog', 10);
WITH tmp AS (
SELECT
*,
row_number() OVER (PARTITION BY animal ORDER BY id) AS ordinal
FROM
sample
)
SELECT * FROM tmp WHERE ordinal <= 3;