セットアップ
まず、テーブルのデータが次のデータであると想定します。dataset1
と想定していることに注意してください。 主キーがあります(複合キーにすることもできますが、簡単にするために整数にします):
CREATE TABLE dataset1
(
id INTEGER PRIMARY KEY,
column4 TEXT
) ;
CREATE TABLE dataset2
(
column1 TEXT
) ;
両方のテーブルにサンプルデータを入力します
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) ;
健全性チェック:
SELECT count(DISTINCT column4) FROM dataset1 ;
| count | | ----: | | 20 |
ケース1:データセット1の行数<=データセット2の行数
完全なシャッフルを実行します。データセット2の値は、1回だけ使用され、1回だけ使用されます。
説明
column4
のすべての値をシャッフルする更新を行うため ランダムな方法で、いくつかの中間ステップが必要です。
まず、dataset1
の場合 、タプルのリスト(関係)を作成する必要があります(id, rn)
、それはただ:
(id_1, 1),
(id_2, 2),
(id_3, 3),
...
(id_20, 20)
id_1
、...、id_20
dataset1
に存在するIDです 。それらは任意のタイプにすることができ、連続している必要はなく、複合することもできます。
dataset2
の場合 、(column_1,rn)
の別のリストを作成する必要があります 、次のようになります:
(column1_1, 17),
(column1_2, 3),
(column1_3, 11),
...
(column1_20, 15)
この場合、2番目の列にはすべての値1 .. 20が含まれていますが、シャッフルされています。
2つの関係ができたら、JOIN
それらはON ... rn
。これにより、実際には、(id, column1)
を持つタプルのさらに別のリストが生成されます。 、ペアリングがランダムに行われた場合。これらのペアを使用して、dataset1
を更新します 。
本当の質問
これはすべて、CTE(WITH
)を使用して行うことができます(明らかに、私は願っています)。 ステートメント)中間関係を保持する:
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 ;
トリックに注意してください によって実行されます:
row_number() OVER (ORDER BY random()) AS rn
row_number()
ウィンドウ関数
OVER
のため、これらの番号はランダムにシャッフルされます。 句はすべてのデータを取得し、ランダムに並べ替えます。
チェック
もう一度確認できます:
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
代替
これは、CTEの代わりに、単純な置換によってサブクエリを使用して実行することもできることに注意してください。これにより、場合によってはパフォーマンスが向上する可能性があります。
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 ;
そしてまた...
SELECT * FROM dataset1;
id | column4 --: | :------------- 101 | SOMETHING 1011 102 | SOMETHING 1018 103 | SOMETHING 1007 ... 118 | SOMETHING 1020 119 | SOMETHING 1002 120 | SOMETHING 1016
セットアップ全体と実験は、 dbfiddle こちら で確認できます。
注:非常に大きなデータセットでこれを行う場合は、極端に高速になるとは思わないでください。非常に大きなカードのデッキをシャッフルするのは費用がかかります。
ケース2:データセット1の行数>データセット2の行
この場合、column4
の値 数回繰り返すことができます。
私が考えることができる最も簡単な可能性(おそらく、効率的なものではありませんが、理解しやすい)は、関数random_column1
を作成することです。 、VOLATILE
としてマークされています :
CREATE FUNCTION random_column1()
RETURNS TEXT
VOLATILE -- important!
LANGUAGE SQL
AS
$$
SELECT
column1
FROM
dataset2
ORDER BY
random()
LIMIT
1 ;
$$ ;
そしてそれを使用して更新します:
UPDATE
dataset1
SET
column4 = random_column1();
このように、dataset2
からのいくつかの値 かもしれない まったく使用されませんが、他の人は 複数回使用する。
dbfiddle こちら