设置
让我们首先假设您的表和数据如下。
请注意,我假设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 ;
|计数 |
| ----: |
| 20 |
案例 1:dataset1 中的行数
我们将执行一次完整的洗牌。 dataset2 中的值将被使用一次,并且不会超过一次。
解释
为了进行更新,将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)
在这种情况下,第二列包含所有值 1 .. 20,但被打乱了。
一旦我们有了这两个关系,我们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() window function 产生与行数一样多的连续数字,从 1 开始。
这些数字是随机打乱的,因为OVER 子句获取所有数据并随机排序。
检查
我们可以再检查一下:
SELECT count(DISTINCT column4) FROM dataset1 ;
|计数 |
| ----: |
| 20 |
SELECT * FROM dataset1 ;
编号 |第 4 列
--: | :-------------
101 |东西 1016
102 |东西 1009
103 |东西 1003
...
118 |东西 1012
119 |东西 1017
120 |东西 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;
编号 |第 4 列
--: | :-------------
101 |东西 1011
102 |东西 1018
103 |东西 1007
...
118 |东西 1020
119 |东西 1002
120 |东西 1016
您可以在 dbfiddle here
查看整个设置和实验
注意:如果您使用非常大的数据集执行此操作,请不要期望它非常快。洗一副非常大的牌很昂贵。
案例 2:dataset1 中的行数 > dataset2 中的行数
在这种情况下,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 here