sql >> Databasteknik >  >> RDS >> PostgreSQL

Fyll i slumpmässiga data från en annan tabell

INSTÄLLNING

Låt oss börja med att anta att dina tabeller och data är följande. Observera att jag antar att dataset1 har en primärnyckel (den kan vara en sammansatt, men låt oss för enkelhetens skull göra den till ett heltal):

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

CREATE TABLE dataset2
(
    column1 TEXT
) ;

Vi fyller båda tabellerna med exempeldata

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) ;

Sanitetskontroll:

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

Fall 1:antal rader i dataset1 <=rader i dataset2

Vi kommer att utföra en fullständig blandning. Värden från dataset2 kommer att användas en gång och inte mer än en gång.

FÖRKLARING

För att göra en uppdatering som blandar alla värden från column4 på ett slumpmässigt sätt behöver vi några mellansteg.

Först, för dataset1 , måste vi skapa en lista (relation) över tupler (id, rn) , det är bara:

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

Där id_1 , ..., id_20 är de ID som finns på dataset1 .De kan vara av vilken typ som helst, de behöver inte vara på varandra och de kan vara sammansatta.

För dataset2 , måste vi skapa en annan lista med (column_1,rn) , som ser ut så här:

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

I det här fallet innehåller den andra kolumnen alla värden 1 .. 20, men blandade.

När vi väl har de två relationerna JOIN dem ON ... rn . Detta ger i praktiken ännu en lista med tupler med (id, column1) , där parningen har gjorts slumpmässigt. Vi använder dessa par för att uppdatera dataset1 .

DEN VERKLIGA FRÅGAN

Allt detta kan göras (så klart, hoppas jag) genom att använda någon CTE (WITH uttalande) för att hålla de mellanliggande relationerna:

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 ;

Observera att tricket utförs med hjälp av:

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

row_number() fönsterfunktion som ger lika många på varandra följande tal som det finns rader, med början från 1. Dessa siffror blandas slumpmässigt eftersom OVER klausul tar all data och sorterar den slumpmässigt.

KONTROLLER

Vi kan kontrollera igen:

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

ALTERNATIV

Observera att detta också kan göras med underfrågor, genom enkel substitution, istället för CTE. Det kan förbättra prestandan vid vissa tillfällen:

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 ;

Och igen...

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

Du kan kontrollera hela installationen och experimentera på dbfiddle här

OBS:om du gör detta med mycket stora datamängder, förvänta dig inte att det ska vara extremt snabbt. Att blanda en mycket stor kortlek är dyrt.

Fall 2:antal rader i dataset1> rader i dataset2

I det här fallet, värden för column4 kan upprepas flera gånger.

Den enklaste möjligheten jag kan tänka mig (förmodligen inte en effektiv, men lätt att förstå) är att skapa en funktion random_column1 , markerad som VOLATILE :

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

Och använd den för att uppdatera:

UPDATE
    dataset1
SET
    column4 = random_column1();

På så sätt kommer vissa värden från dataset2 kanske inte användas alls, medan andra kommer användas mer än en gång.

dbfiddle här



  1. Hur får jag asynkront/händelsedrivet LISTEN/NOTIFY-stöd i Java med hjälp av en Postgres-databas?

  2. Vad du bör veta om MED NOCHECK när du aktiverar en CHECK-begränsning i SQL Server

  3. Hur kan jag kontrollera om MySQL och Tomcat körs?

  4. PDO och ÄR INTE NULL Funktion