Astuce Dupliquer une ligne n fois avec PostgreSQL

Par exemple, vous avez une donnée en base, et pour vos tests, vous en voudriez 10 000.

Il est possible d’utiliser cette boucle SQL pour faire 10 000 insertions :

-- Copie d’une ligne n fois
--
-- Paramètres modifiables :
--   - nb de fois (ici 10000)
--   - table concernée (ici my_table)
--   - liste des colonnes à copier (ici column_1, column_2, column_x)
--   - id de la ligne à copier (ici 1)

DO
$$
    DECLARE
        i integer;
    BEGIN
        FOR i IN 1..10000
            LOOP
                INSERT INTO public.my_table (column_1, column_2, column_x)
                SELECT column_1, column_2, column_x
                FROM public.my_table
                WHERE id = 1;
            END LOOP;
    END
$$ LANGUAGE plpgsql;

Pour générer cette requête avec toutes les colonnes de votre table, vous pouvez faire générer l’INSERT directement à PostgreSQL, avec la requête suivante :

-- Génération de la requête d’insertion avec toutes les colonnes sauf la colonne id (car auto-incrémentale)
--
-- Paramètres modifiables :
--   - table concernée (ici my_table)
--   - id de la ligne à copier (ici 1)
WITH cols AS (SELECT column_name, ordinal_position
              FROM information_schema.columns
              WHERE table_schema = 'public'
                AND table_name = 'my_table'
                AND column_name NOT IN ('id')
              ORDER BY ordinal_position)
SELECT format(
               'INSERT INTO %I.%I (%s) SELECT %s FROM %I.%I WHERE id = 1;',
               'public',
               'my_table', string_agg(quote_ident(column_name), ', '), string_agg(quote_ident(column_name), ', '),
               'public', 'my_table') AS sql

Un dernier problème se pose si certaines colonnes doivent contenir des données uniques.
Dans les INSERT précédents, on ne gère que le cas de la colonne id, supposée auto-incrémentale. Pour générer des données pour d’autres colonnes, remplacez la requête précédente par celle-ci :

-- Génération de la requête de copie avec toutes les colonnes sauf celle contenant des ID uniques
--
-- Paramètres modifiables :
--   - table concernée (ici my_table)
--   - liste des colonnes pour lesquelles générer des uuid uniques (ici 'uuid1', 'uuid2')
--   - id de la ligne à copier (ici 1)
WITH cols AS (SELECT column_name, ordinal_position
              FROM information_schema.columns
              WHERE table_schema = 'public'
                AND table_name = 'my_table'
                AND column_name NOT IN ('id', 'uuid1', 'uuid2')
              ORDER BY ordinal_position)
SELECT format(
               'INSERT INTO %I.%I (uuid1, uuid2, %s) SELECT gen_random_uuid(), gen_random_uuid(), %s FROM %I.%I WHERE id = 1;',
               'public',
               'my_table', string_agg(quote_ident(column_name), ', '), string_agg(quote_ident(column_name), ', '),
               'public', 'my_table') AS sql

Note : si les valeurs uniques ne sont pas des UUID, il faut rechercher si PostgreSQL propose d’autres fonctions de génération aléatoires que gen_random_uuid().