2017-08-04 7 views
3
update dataset1.test 
    set column4 = (select column1 
       from dataset2 
       order by random() 
       limit 1 
       ) 

データセット2の列からランダムなエントリを更新する各行で列4のdataset1を更新する必要があります。私がそれをランダムにしたいと思うdataset1とそのすべての行。ランダムなデータを別のテーブルから読み込む

+0

いくつかの質問:あなたができるようになるから一つの値 'dataset1''上で複数回使用することdataset2'、または各値は高々一度使用されるようにしているのでしょうか? 'dataset2'は少なくとも' dataset1'と同じ行数を持っていますか? –

+0

[ランダムな名前のテーブルからのSQl更新]の可能な複製(https://stackoverflow.com/questions/21560392/sql-update-from-table-of-random-names)。 dataset2に数値IDがあると仮定します。 – JeffUK

+0

[Redshift:別のテーブルのランダムデータを含む列の各行を更新または挿入する]の可能な複製(https://stackoverflow.com/questions/45535038/redshift-update-or-insert-each-row-in-column-他のタブレットからのランダムデータ付き) –

答えて

3

SETUP

データは以下のものです、あなたのテーブルを想定して起動するのをしてみましょう。私たちは、サンプルデータ

で両方のテーブルを埋める

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

CREATE TABLE dataset2 
(
    column1 TEXT 
) ; 

:私はdataset1は、主キーを(それが複合いずれかになります、しかし、簡単のために、のは、それ整数にしましょう)があることを前提としてい 注意

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の行

完全シャッフリングを実行します。 dataset2の値は1回だけ使用され、1回だけ使用されます。

EXPLANATION

ランダムにcolumn4からすべての値をシャッフル更新を行うために、我々はいくつかの中間ステップを必要としています。

まず、dataset1のために、私たちは だけであることを、リストを作成するタプル(id, rn)の(関係を)必要があります。

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

id_1、...、id_20dataset1上に存在IDです。 これらは、どのようなタイプでもよく、連続している必要はなく、コンポジットでもかまいません。 dataset2については

、私たちがどのように見える(column_1,rn)の別のリスト、作成する必要があります。

この場合
(column1_1, 17), 
(column1_2, 3), 
(column1_3, 11), 
... 
(column1_20, 15) 

を、2番目の列はすべての値1 ... 20が含まれていますが、シャッフル。

2つの関係が成立すると、JOINON ... rnとなります。これは、実際には(id, column1)のタプルの別のリストを生成します。ペアリングはランダムに行われます。これらのペアを使用してdataset1を更新します。

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 ; 

注意をトリックこと:これは、すべての中間の関係を保持するために、いくつかのCTE(WITHの文)を使用して(私は願って明確に)行うことができます

REAL QUERY

は、

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

row_number() window functionは、1から始まる行数と同じ連続した数値を生成します。 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 

ALTERNATIVE

これは、サブクエリ、CTEではなく単純な置換によっても行うことができます。あなたはhere

dbfiddle で全体のセットアップと実験を確認することができます

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 

:それはいくつかの場面でパフォーマンスが向上する可能性があります注:非常に大きなデータセットでこれを行う場合は、それが非常に高速であることを期待する。非常に大きなカードデッキをシャッフルするのは高価です。


ケース2:DATASET1の行数>この場合DATASET2

の行、column4の値は数回繰り返すことができます。

私は(効率的な1、おそらくないが、理解しやすい)を考えることができる最も簡単な可能性は機能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

+0

あなたのクエリは正当だと思われます。しかし、私はdataset1がdataset2よりも大きいことを忘れていました。例えば、dataset2は50個のデータを持ち、dataset1は100個のデータを持っています。 - > dataset1は、値が10回発生してもデータセット2からランダムな値で更新する必要があります –

+0

あなたの質問を編集し、この情報を追加する必要があります。可能な答えはそれによって多くの影響を受けるでしょう。 – joanolo

+0

私の答えは**ケース2 **を参照してください。 – joanolo

0

ベターがサブクエリから外側のテーブルを参照することです。そして、サブクエリが行ごとにevaluedする必要があります。

update dataset1.test 
    set column4 = (select 
     case when dataset1.test.column4 = dataset1.test.column4 
      then column1 end 
     from dataset2 
     order by random() 
     limit 1 
    ) 
関連する問題