PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Füllen Sie zufällige Daten aus einer anderen Tabelle

EINRICHTUNG

Beginnen wir mit der Annahme, dass Ihre Tabellen und Daten die folgenden sind. Beachten Sie, dass ich davon ausgehe, dass dataset1 hat einen Primärschlüssel (es kann ein zusammengesetzter Schlüssel sein, aber der Einfachheit halber machen wir daraus eine Ganzzahl):

CREATE TABLE dataset1
(
     id INTEGER PRIMARY KEY,
     column4 TEXT
) ;

CREATE TABLE dataset2
(
    column1 TEXT
) ;

Wir füllen beide Tabellen mit Beispieldaten

INSERT INTO dataset1
    (id, column4)
SELECT
    i, 'column 4 for id ' || i
FROM
    generate_series(101, 120) AS s(i);

INSERT INTO dataset2
    (column1)
SELECT
    'SOMETHING ' || i
FROM 
    generate_series (1001, 1020) AS s(i) ;

Plausibilitätsprüfung:

SELECT count(DISTINCT column4) FROM dataset1 ;
| count |
| ----: |
|    20 |

Fall 1:Anzahl Zeilen in Datensatz1 <=Zeilen in Datensatz2

Wir führen ein komplettes Mischen durch. Werte aus Datensatz2 werden einmal und nicht mehr als einmal verwendet.

ERKLÄRUNG

Um ein Update zu machen, das alle Werte aus column4 mischt zufälligerweise brauchen wir einige Zwischenschritte.

Zuerst für dataset1 , müssen wir eine Liste (Relation) von Tupeln (id, rn) erstellen , das sind nur:

(id_1,   1),
(id_2,   2),
(id_3,   3),
...
(id_20, 20)

Wobei id_1 , ..., id_20 sind die IDs, die auf dataset1 vorhanden sind .Sie können von beliebigem Typ sein, sie müssen nicht aufeinanderfolgend sein, und sie können zusammengesetzt sein.

Für dataset2 , müssen wir eine weitere Liste von (column_1,rn) erstellen , das sieht so aus:

(column1_1,  17),
(column1_2,   3),
(column1_3,  11),
...
(column1_20, 15)

In diesem Fall enthält die zweite Spalte alle Werte 1 .. 20, aber gemischt.

Sobald wir die beiden Beziehungen haben, JOIN wir uns sie ON ... rn . Dies erzeugt in der Praxis eine weitere Liste von Tupeln mit (id, column1) , wo die Kopplung zufällig erfolgt ist. Wir verwenden diese Paare, um dataset1 zu aktualisieren .

DIE ECHTE FRAGE

Dies alles kann (offensichtlich, hoffe ich) durch die Verwendung von CTE (WITH -Anweisung), um die Zwischenbeziehungen zu halten:

WITH original_keys AS
(
    -- This creates tuples (id, rn), 
    -- where rn increases from 1 to number or rows
    SELECT 
        id, 
        row_number() OVER  () AS rn
    FROM 
        dataset1
)
, shuffled_data AS
(
    -- This creates tuples (column1, rn)
    -- where rn moves between 1 and number of rows, but is randomly shuffled
    SELECT 
        column1,
        -- The next statement is what *shuffles* all the data
        row_number() OVER  (ORDER BY random()) AS rn
    FROM 
        dataset2
)
-- You update your dataset1
-- with the shuffled data, linking back to the original keys
UPDATE
    dataset1
SET
    column4 = shuffled_data.column1
FROM
    shuffled_data
    JOIN original_keys ON original_keys.rn = shuffled_data.rn
WHERE
    dataset1.id = original_keys.id ;

Beachten Sie den Trick erfolgt mittels:

row_number() OVER (ORDER BY random()) AS rn

Der row_number() Fensterfunktion das erzeugt so viele aufeinanderfolgende Zahlen wie es Zeilen gibt, beginnend bei 1. Diese Zahlen werden zufällig gemischt, weil der OVER -Klausel nimmt alle Daten und sortiert sie nach dem Zufallsprinzip.

CHECKS

Wir können es noch einmal überprüfen:

SELECT count(DISTINCT column4) FROM dataset1 ;
| count |
| ----: |
|    20 |
SELECT * FROM dataset1;
 id | column4       
--: | :-------------
101 | SOMETHING 1016
102 | SOMETHING 1009
103 | SOMETHING 1003
...
118 | SOMETHING 1012
119 | SOMETHING 1017
120 | SOMETHING 1011

ALTERNATIVE

Beachten Sie, dass dies auch mit Unterabfragen durch einfache Substitution anstelle von CTEs erfolgen kann. Das kann in manchen Fällen die Leistung verbessern:

UPDATE
    dataset1
SET
    column4 = shuffled_data.column1
FROM
    (SELECT 
        column1,
        row_number() OVER  (ORDER BY random()) AS rn
    FROM 
        dataset2
    ) AS shuffled_data
    JOIN 
    (SELECT 
        id, 
        row_number() OVER  () AS rn
    FROM 
        dataset1
    ) AS original_keys ON original_keys.rn = shuffled_data.rn
WHERE
    dataset1.id = original_keys.id ;

Und nochmal...

SELECT * FROM dataset1;
 id | column4       
--: | :-------------
101 | SOMETHING 1011
102 | SOMETHING 1018
103 | SOMETHING 1007
...
118 | SOMETHING 1020
119 | SOMETHING 1002
120 | SOMETHING 1016

Sie können das gesamte Setup und Experimente dbfiddle hier überprüfen

HINWEIS:Wenn Sie dies mit sehr großen Datensätzen tun, erwarten Sie nicht, dass es extrem schnell geht. Das Mischen eines sehr großen Kartenspiels ist teuer.

Fall 2:Anzahl Zeilen in Datensatz1> Zeilen in Datensatz2

In diesem Fall Werte für column4 kann mehrmals wiederholt werden.

Die einfachste Möglichkeit, die mir einfällt (wahrscheinlich nicht effizient, aber leicht verständlich), besteht darin, eine Funktion random_column1 zu erstellen , gekennzeichnet als VOLATILE :

CREATE FUNCTION random_column1() 
    RETURNS TEXT
    VOLATILE      -- important!
    LANGUAGE SQL
AS
$$
    SELECT
        column1
    FROM
        dataset2
    ORDER BY
        random()
    LIMIT
        1 ;
$$ ;

Und verwenden Sie es zum Aktualisieren:

UPDATE
    dataset1
SET
    column4 = random_column1();

Auf diese Weise einige Werte aus dataset2 vielleicht überhaupt nicht verwendet werden, während andere werden mehr als einmal verwendet werden.

dbfiddle hier