PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Isi data acak dari tabel lain

PENYIAPAN

Mari kita mulai dengan menganggap tabel Anda sebagai data berikut. Perhatikan bahwa saya berasumsi bahwa dataset1 memiliki kunci utama (bisa berupa kunci komposit, tetapi, demi kesederhanaan, mari kita buat bilangan bulat):

CREATE TABLE dataset1
(
     id INTEGER PRIMARY KEY,
     column4 TEXT
) ;

CREATE TABLE dataset2
(
    column1 TEXT
) ;

Kami mengisi kedua tabel dengan data sampel

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) ;

Pemeriksaan kesehatan:

SELECT count(DISTINCT column4) FROM dataset1 ;
| count |
| ----: |
|    20 |

Kasus 1:jumlah baris dalam kumpulan data1 <=baris dalam kumpulan data2

Kami akan melakukan pengocokan lengkap. Nilai dari dataset2 akan digunakan sekali, dan tidak lebih dari sekali.

PENJELASAN

Untuk membuat pembaruan yang mengacak semua nilai dari column4 secara acak, kami membutuhkan beberapa langkah perantara.

Pertama, untuk dataset1 , kita perlu membuat daftar (relasi) dari tupel (id, rn) , itu saja:

(id_1,   1),
(id_2,   2),
(id_3,   3),
...
(id_20, 20)

Dimana id_1 , ..., id_20 apakah id ada di dataset1 .Mereka bisa dari jenis apa saja, tidak perlu berurutan, dan bisa gabungan.

Untuk dataset2 , kita perlu membuat daftar lagi dari (column_1,rn) , yang terlihat seperti:

(column1_1,  17),
(column1_2,   3),
(column1_3,  11),
...
(column1_20, 15)

Dalam hal ini, kolom kedua berisi semua nilai 1 .. 20, tetapi diacak.

Setelah kita memiliki dua relasi, kita JOIN mereka ON ... rn . Ini, dalam praktiknya, menghasilkan daftar tupel lain dengan (id, column1) , dimana pairing dilakukan secara random. Kami menggunakan pasangan ini untuk memperbarui dataset1 .

PERTANYAAN NYATA

Ini semua dapat dilakukan (jelas, saya harap) dengan menggunakan beberapa CTE (WITH pernyataan) untuk mengadakan hubungan perantara:

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 ;

Perhatikan bahwa trik dilakukan dengan cara:

row_number() OVER (ORDER BY random()) AS rn

row_number() fungsi jendela yang menghasilkan angka berurutan sebanyak baris, mulai dari 1. Angka-angka ini diacak secara acak karena OVER klausa mengambil semua data dan mengurutkannya secara acak.

CEK

Kita bisa cek lagi:

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

ALTERNATIF

Perhatikan bahwa ini juga dapat dilakukan dengan subquery, dengan substitusi sederhana, bukan CTE. Itu mungkin meningkatkan kinerja di beberapa kesempatan:

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 ;

Dan lagi...

SELECT * FROM dataset1;
 id | column4       
--: | :-------------
101 | SOMETHING 1011
102 | SOMETHING 1018
103 | SOMETHING 1007
...
118 | SOMETHING 1020
119 | SOMETHING 1002
120 | SOMETHING 1016

Anda dapat memeriksa seluruh penyiapan dan eksperimen di dbfiddle di sini

CATATAN:jika Anda melakukan ini dengan kumpulan data yang sangat besar, jangan berharap itu menjadi sangat cepat. Mengocok setumpuk kartu yang sangat besar itu mahal.

Kasus 2:jumlah baris dalam kumpulan data1> baris dalam kumpulan data2

Dalam hal ini, nilai untuk column4 dapat diulang beberapa kali.

Kemungkinan termudah yang dapat saya pikirkan (mungkin, bukan yang efisien, tetapi mudah dimengerti) adalah membuat fungsi random_column1 , ditandai sebagai VOLATILE :

CREATE FUNCTION random_column1() 
    RETURNS TEXT
    VOLATILE      -- important!
    LANGUAGE SQL
AS
$$
    SELECT
        column1
    FROM
        dataset2
    ORDER BY
        random()
    LIMIT
        1 ;
$$ ;

Dan gunakan untuk memperbarui:

UPDATE
    dataset1
SET
    column4 = random_column1();

Dengan cara ini, beberapa nilai dari dataset2 mungkin tidak digunakan sama sekali, sedangkan yang lain akan digunakan lebih dari sekali.

dbfiddle di sini



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. psql:FATAL:tidak dapat membuka basis file/11951/11717:Sistem file hanya-baca

  2. Lebih Banyak Kueri PostgreSQL Favorit Saya - dan Mengapa Mereka Juga Penting

  3. Menghindari kondisi balapan, Django + Heroku + PostgreSQL

  4. Instal RPostgreSQL pada RHEL 6.5 libpq-fe.h Error

  5. Statistik cakupan kode