sql >> Database teknologi >  >> RDS >> PostgreSQL

Udfyld tilfældige data fra en anden tabel

OPSÆTNING

Lad os starte med at antage, at dine tabeller og data er følgende. Bemærk, at jeg antager, at dataset1 har en primær nøgle (det kan være en sammensat nøgle, men lad os for nemheds skyld gøre det til et heltal):

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

CREATE TABLE dataset2
(
    column1 TEXT
) ;
 

Vi udfylder begge tabeller med eksempeldata

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

Sundhedstjek:

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

Case 1:antal rækker i datasæt1 <=rækker i datasæt2

Vi udfører en fuldstændig blanding. Værdier fra datasæt2 vil blive brugt én gang og ikke mere end én gang.

FORKLARING

For at lave en opdatering, der blander alle værdierne fra column4 på en tilfældig måde har vi brug for nogle mellemtrin.

Først for dataset1 , skal vi oprette en liste (relation) over tuples (id, rn) , det er bare:

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

Hvor id_1 , ..., id_20 er id'erne til stede på dataset1 .De kan være af enhver type, de behøver ikke være fortløbende, og de kan være sammensatte.

For dataset2 , skal vi oprette en anden liste over (column_1,rn) , der ser ud som:

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

I dette tilfælde indeholder den anden kolonne alle værdierne 1 .. 20, men blandet.

Når vi har de to relationer, JOIN dem ON ... rn . Dette giver i praksis endnu en liste over tuples med (id, column1) , hvor parringen er foretaget tilfældigt. Vi bruger disse par til at opdatere dataset1 .

DEN RIGTIGE FORESPØRGSEL

Det hele kan gøres (håber jeg klart) ved at bruge nogle CTE (WITH erklæring) for at holde de mellemliggende relationer:

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 ;

Bemærk, at tricket udføres ved hjælp af:

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

row_number() vinduesfunktion der producerer lige så mange på hinanden følgende tal, som der er rækker, startende fra 1. Disse tal blandes tilfældigt, fordi OVER klausul tager alle data og sorterer dem tilfældigt.

KONTROL

Vi kan tjekke igen:

SELECT count(DISTINCT column4) FROM dataset1 ;
 
| tælle || ----:|| 20 |
SELECT * FROM dataset1 ;
 
 id | kolonne 4 --:| :-------------101 | NOGET 1016102 | NOGET 1009103 | NOGET 1003...118 | NOGET 1012119 | NOGET 1017120 | SOMETHING 1011

ALTERNATIV

Bemærk, at dette også kan gøres med underforespørgsler, ved simpel substitution, i stedet for CTE'er. Det kan i nogle tilfælde forbedre ydeevnen:

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 ;
 

Og igen...

SELECT * FROM dataset1 ;
 
 id | kolonne 4 --:| :-------------101 | NOGET 1011102 | NOGET 1018103 | NOGET 1007...118 | NOGET 1020119 | NOGET 1002120 | SOMETHING 1016

Du kan tjekke hele opsætningen og eksperimentere på dbfiddle her

BEMÆRK:Hvis du gør dette med meget store datasæt, skal du ikke forvente, at det er ekstremt hurtigt. Det er dyrt at blande et meget stort sæt kort.

Case 2:antal rækker i datasæt1> rækker i datasæt2

I dette tilfælde værdier for column4 kan gentages flere gange.

Den nemmeste mulighed jeg kan komme i tanke om (sandsynligvis ikke en effektiv, men nem at forstå) er at oprette en funktion random_column1 , markeret som VOLATILE :

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

Og brug det til at opdatere:

UPDATE
    dataset1
SET
    column4 = random_column1();
 

På denne måde er nogle værdier fra dataset2 måske slet ikke bruges, hvorimod andre vil bruges mere end én gang.

dbfiddle her



  1. SQL - Hvordan gemmer og navigerer man i hierarkier?

  2. Er arrays optimeret i jOOQ &PostgreSQL?

  3. MySQL forbindelsesfejl, som jeg aldrig har set

  4. En gennemgang af de nye analytiske vinduesfunktioner i MySQL 8.0