PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Điền dữ liệu ngẫu nhiên từ một bảng khác

THIẾT LẬP

Hãy bắt đầu bằng cách giả sử các bảng của bạn có một dữ liệu sau đây. Lưu ý rằng tôi giả sử rằng dataset1 có một khóa chính (nó có thể là một khóa tổng hợp, nhưng để đơn giản, hãy đặt nó là một số nguyên):

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

CREATE TABLE dataset2
(
    column1 TEXT
) ;

Chúng tôi điền vào cả hai bảng với dữ liệu mẫu

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

Kiểm tra tình trạng:

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

Trường hợp 1:số hàng trong tập dữ liệu1 <=hàng trong tập dữ liệu2

Chúng tôi sẽ thực hiện xáo trộn hoàn chỉnh. Các giá trị từ dataset2 sẽ được sử dụng một lần và không nhiều hơn một lần.

GIẢI THÍCH

Để thực hiện cập nhật xáo trộn tất cả các giá trị từ column4 trong thời trang arandom, chúng tôi cần một số bước trung gian.

Đầu tiên, đối với dataset1 , chúng ta cần tạo một danh sách (quan hệ) các bộ giá trị (id, rn) , đó chỉ là:

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

Ở đâu id_1 , ..., id_20 id có trên dataset1 không Chúng có thể thuộc bất kỳ loại nào, không cần liên tiếp và có thể là hỗn hợp.

Đối với dataset2 , chúng tôi cần tạo một danh sách khác gồm (column_1,rn) , trông giống như:

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

Trong trường hợp này, cột thứ hai chứa tất cả các giá trị 1 .. 20, nhưng bị xáo trộn.

Khi chúng ta có hai mối quan hệ, chúng ta JOIN chúng ON ... rn . Trên thực tế, điều này tạo ra một danh sách các bộ giá trị khác có (id, column1) , nơi việc ghép đôi đã được thực hiện một cách ngẫu nhiên. Chúng tôi sử dụng các cặp này để cập nhật dataset1 .

CÂU HỎI THỰC TẾ

Tất cả điều này có thể được thực hiện (rõ ràng, tôi hy vọng) bằng cách sử dụng một số CTE (WITH câu lệnh) để giữ các quan hệ trung gian:

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 ;

Lưu ý rằng thủ thuật được thực hiện bằng:

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

row_number() chức năng cửa sổ tạo ra nhiều số liên tiếp như có các hàng, bắt đầu từ 1. Các số này được xáo trộn ngẫu nhiên vì OVER mệnh đề lấy tất cả dữ liệu và sắp xếp nó một cách ngẫu nhiên.

KIỂM TRA

Chúng tôi có thể kiểm tra lại:

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

ĐẠI SỐ

Lưu ý rằng điều này cũng có thể được thực hiện với các truy vấn con, bằng cách thay thế đơn giản, thay vì CTE. Điều đó có thể cải thiện hiệu suất trong một số trường hợp:

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 ;

Và một lần nữa ...

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

Bạn có thể kiểm tra toàn bộ thiết lập và thử nghiệm tại dbfiddle tại đây

LƯU Ý:nếu bạn thực hiện việc này với bộ dữ liệu rất lớn, đừng mong đợi nó cực kỳ nhanh. Việc xáo trộn một bộ bài rất lớn rất tốn kém.

Trường hợp 2:số hàng trong tập dữ liệu1> hàng trong tập dữ liệu2

Trong trường hợp này, các giá trị cho column4 có thể được lặp lại nhiều lần.

Khả năng dễ nhất mà tôi có thể nghĩ đến (có thể, không phải là một cách hiệu quả, nhưng dễ hiểu) là tạo một hàm random_column1 , được đánh dấu là VOLATILE :

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

Và sử dụng nó để cập nhật:

UPDATE
    dataset1
SET
    column4 = random_column1();

Bằng cách này, một số giá trị từ dataset2 might hoàn toàn không được sử dụng, trong khi những người khác sẽ được sử dụng nhiều lần.

dbfiddle tại đây



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách giải mã nhật ký lỗi PostgreSQL

  2. Làm cách nào để đặt '5 ngày' (khoảng thời gian ngày tháng) trong jdbc cho PostgreSQL?

  3. Quyền của người dùng PostgreSQL

  4. chạy tổng số bằng cách sử dụng hàm windows trong sql có cùng một kết quả cho cùng một dữ liệu

  5. Postgresql:xóa khoảng trắng giữa các loại chữ số nhất định