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