NASTAVENÍ
Začněme tím, že předpokládejme, že vaše tabulky a data jsou následující. Všimněte si, že předpokládám, že dataset1
má primární klíč (může být složený, ale pro zjednodušení z něj udělejme celé číslo):
CREATE TABLE dataset1
(
id INTEGER PRIMARY KEY,
column4 TEXT
) ;
CREATE TABLE dataset2
(
column1 TEXT
) ;
Obě tabulky naplníme vzorovými údaji
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) ;
Kontrola příčetnosti:
SELECT count(DISTINCT column4) FROM dataset1 ;
| count | | ----: | | 20 |
Případ 1:počet řádků v datové sadě1 <=řádků v datové sadě2
Provedeme kompletní promíchání. Hodnoty z datové sady2 budou použity jednou a ne více než jednou.
VYSVĚTLENÍ
Chcete-li provést aktualizaci, která zamíchá všechny hodnoty ze column4
náhodně potřebujeme nějaké mezikroky.
Nejprve pro dataset1
, musíme vytvořit seznam (relaci) n-tic (id, rn)
, to jsou jen:
(id_1, 1),
(id_2, 2),
(id_3, 3),
...
(id_20, 20)
Kde id_1
, ..., id_20
jsou ID přítomná v dataset1
.Mohou být libovolného typu, nemusí být po sobě jdoucí a mohou být složené.
Pro dataset2
, musíme vytvořit další seznam (column_1,rn)
, to vypadá takto:
(column1_1, 17),
(column1_2, 3),
(column1_3, 11),
...
(column1_20, 15)
V tomto případě druhý sloupec obsahuje všechny hodnoty 1 .. 20, ale zamíchané.
Jakmile máme oba vztahy, JOIN
ON ... rn
. To v praxi vytváří další seznam n-tic s (id, column1)
, kde bylo párování provedeno náhodně. Tyto páry používáme k aktualizaci dataset1
.
SKUTEČNÝ DOTAZ
To vše lze provést (jasně, doufám) pomocí nějakého CTE (WITH
příkaz) k udržení mezilehlých vztahů:
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 ;
Všimněte si, že trik se provádí pomocí:
row_number() OVER (ORDER BY random()) AS rn
row_number()
funkce okna
který vytvoří tolik po sobě jdoucích čísel, kolik je řádků, počínaje 1. Tato čísla jsou náhodně zamíchána, protože OVER
klauzule vezme všechna data a náhodně je seřadí.
KONTROLY
Můžeme znovu zkontrolovat:
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
ALTERNATIVNÍ
Všimněte si, že to lze také provést pomocí poddotazů, jednoduchou substitucí, namísto CTE. To by mohlo v některých případech zlepšit výkon:
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 ;
A znovu...
SELECT * FROM dataset1;
id | column4 --: | :------------- 101 | SOMETHING 1011 102 | SOMETHING 1018 103 | SOMETHING 1007 ... 118 | SOMETHING 1020 119 | SOMETHING 1002 120 | SOMETHING 1016
Celé nastavení a experiment můžete zkontrolovat na dbfiddle zde
POZNÁMKA:Pokud to uděláte s velmi velkými datovými sadami, neočekávejte, že to bude extrémně rychlé. Míchání velmi velkého balíčku karet je drahé.
Případ 2:počet řádků v datové sadě1> řádků v datové sadě2
V tomto případě hodnoty pro column4
lze několikrát opakovat.
Nejjednodušší možnost, kterou si dokážu představit (pravděpodobně ne efektivní, ale snadno pochopitelná), je vytvořit funkci random_column1
, označené jako VOLATILE
:
CREATE FUNCTION random_column1()
RETURNS TEXT
VOLATILE -- important!
LANGUAGE SQL
AS
$$
SELECT
column1
FROM
dataset2
ORDER BY
random()
LIMIT
1 ;
$$ ;
A použijte jej k aktualizaci:
UPDATE
dataset1
SET
column4 = random_column1();
Tímto způsobem některé hodnoty z dataset2
možná nebudou použity vůbec, zatímco ostatní budou použít více než jednou.
dbfiddle zde