CONFIGURACIÓN
Comencemos asumiendo que sus tablas y datos son los siguientes. Tenga en cuenta que asumo que dataset1
tiene una clave principal (puede ser una compuesta, pero, por simplicidad, hagámosla un número entero):
CREATE TABLE dataset1
(
id INTEGER PRIMARY KEY,
column4 TEXT
) ;
CREATE TABLE dataset2
(
column1 TEXT
) ;
Llenamos ambas tablas con datos de muestra
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) ;
Control de cordura:
SELECT count(DISTINCT column4) FROM dataset1 ;
| count | | ----: | | 20 |
Caso 1:número de filas en el conjunto de datos1 <=filas en el conjunto de datos2
Realizaremos un barajado completo. Los valores de dataset2 se usarán una vez y no más de una vez.
EXPLICACIÓN
Para hacer una actualización que baraje todos los valores de column4
de forma aleatoria, necesitamos algunos pasos intermedios.
Primero, para el dataset1
, necesitamos crear una lista (relación) de tuplas (id, rn)
, que son solo:
(id_1, 1),
(id_2, 2),
(id_3, 3),
...
(id_20, 20)
Donde id_1
, ..., id_20
son los identificadores presentes en dataset1
.Pueden ser de cualquier tipo, no es necesario que sean consecutivos y pueden ser compuestos.
Para el dataset2
, necesitamos crear otra lista de (column_1,rn)
, que se parece a:
(column1_1, 17),
(column1_2, 3),
(column1_3, 11),
...
(column1_20, 15)
En este caso, la segunda columna contiene todos los valores 1 .. 20, pero barajados.
Una vez que tenemos las dos relaciones, JOIN
ellos ON ... rn
. Esto, en la práctica, produce otra lista de tuplas con (id, column1)
, donde el emparejamiento se ha realizado de forma aleatoria. Usamos estos pares para actualizar dataset1
.
LA CONSULTA REAL
Todo esto se puede hacer (claramente, espero) usando algún CTE (WITH
instrucción) para mantener las relaciones intermedias:
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 ;
Tenga en cuenta que el truco se realiza mediante:
row_number() OVER (ORDER BY random()) AS rn
El row_number()
función de ventana
que produce tantos números consecutivos como filas, comenzando desde 1. Estos números se barajan aleatoriamente porque OVER
cláusula toma todos los datos y los ordena aleatoriamente.
CHEQUES
Podemos comprobar de nuevo:
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
ALTERNATIVA
Tenga en cuenta que esto también se puede hacer con subconsultas, por simple sustitución, en lugar de CTE. Eso podría mejorar el rendimiento en algunas ocasiones:
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 ;
Y otra vez...
SELECT * FROM dataset1;
id | column4 --: | :------------- 101 | SOMETHING 1011 102 | SOMETHING 1018 103 | SOMETHING 1007 ... 118 | SOMETHING 1020 119 | SOMETHING 1002 120 | SOMETHING 1016
Puede consultar toda la configuración y el experimento en dbfiddle aquí
NOTA:si hace esto con conjuntos de datos muy grandes, no espere que sea extremadamente rápido. Barajar una gran baraja de cartas es caro.
Caso 2:número de filas en el conjunto de datos1> filas en el conjunto de datos2
En este caso, valores para column4
se puede repetir varias veces.
La posibilidad más fácil que se me ocurre (probablemente, no eficiente, pero fácil de entender) es crear una función random_column1
, marcado como VOLATILE
:
CREATE FUNCTION random_column1()
RETURNS TEXT
VOLATILE -- important!
LANGUAGE SQL
AS
$$
SELECT
column1
FROM
dataset2
ORDER BY
random()
LIMIT
1 ;
$$ ;
Y úsalo para actualizar:
UPDATE
dataset1
SET
column4 = random_column1();
De esta forma, algunos valores de dataset2
podría no se usará en absoluto, mientras que otros lo harán utilizarse más de una vez.
dbfiddle aquí