如何使用另一个表作为随机值的集合而不使用循环来随机更新一组值?

时间:2019-04-04 13:18:18

标签: sql oracle

我有一个表,其中的列包含一些值。我想用另一个表中的随机值替换所有现有值(但仅替换现有值-WHERE COL1 IS NOT NULL)。无法关联这两个表。每个随机值都必须不同(嗯...除非它们随机地相同,在这种情况下就可以了)。

例如:

CREATE TABLE T1 (ID NUMBER(11,0), COL1 VARCHAR2(20));
CREATE TABLE T2 (COL2 VARCHAR2(20));

INSERT INTO T1 VALUES (1, NULL);
INSERT INTO T1 VALUES (54, NULL);
INSERT INTO T1 VALUES (941, 'Some text');
INSERT INTO T1 VALUES (251, NULL);
INSERT INTO T1 VALUES (352, 'Some other text');
INSERT INTO T1 VALUES (354, NULL);

INSERT INTO T2 VALUES ('Val1');
INSERT INTO T2 VALUES ('Val2');
INSERT INTO T2 VALUES ('Val3');
INSERT INTO T2 VALUES ('Val4');
INSERT INTO T2 VALUES ('Val5');
INSERT INTO T2 VALUES ('Val6');
INSERT INTO T2 VALUES ('Val7');

我尝试了一些操作,并在此站点上搜索了答案。我发现的答案似乎要求两个表之间有一定的相关性。许多示例都是针对SQL Server的。无论如何,我都尝试了一些,但是似乎无法获得MERGECROSS APPLY的工作方式(我很欣赏这很可能是我的失败...)。

目前,我唯一实际可行的解决方案是:

BEGIN
  FOR X IN (
    SELECT ID FROM T1 WHERE COL1 IS NOT NULL
  )
  LOOP
    UPDATE T1 SET COL1 = (
      SELECT COL2 FROM (
        SELECT COL2 FROM T2 ORDER BY SYS_GUID()
      ) WHERE ROWNUM = 1
    ) 
    WHERE T1.ID = X.ID;
  END LOOP;
END;
/

这将产生(期望的)结果:

SELECT * FROM T1;

ID           COL1
---------------------------
1            
54           
941          Val3
251          
352          Val7
354          

(每次运行循环时,COL1值都是随机的。)

...但是我知道 必须 是一种基于集合的方法来实现这一目标...对吗?

2 个答案:

答案 0 :(得分:2)

您可以使用MERGE语句来实现。

merge into t1
using ( select a1.id
               , a2.col2
        from ( select id
                      , row_number() over (order by dbms_random.value) rn
               from t1
               where col1 is not null ) a1
         join ( select col2
                      , row_number() over (order by dbms_random.value) rn
               from t2) a2
          on a1.rn = a2.rn
      ) q
on ( q.id = t1.id) 
when matched then
     update set t1.col1 = q.col2
/

USING查询有点不合常规。有两个子查询,每个子查询一个,以随机顺序生成分析row_number()(这比使用rownum更为简洁。这两个子查询在随机行号上连接在一起,给出了以下项的随机组合) T1.ID和T2.COL_2。之后,这是一个简单的合并。

答案 1 :(得分:1)

您可以创建一个名为GET_RANDOM_VALUE的功能

create or replace FUNCTION GET_RANDOM_VALUE 
RETURN VARCHAR2 AS
  sValue VARCHAR2(100) := '?';
BEGIN

  select col2 INTO sValue 
    from t2 
    order by dbms_random.value
    fetch first 1 rows only;

  RETURN sValue;
END GET_RANDOM_VALUE;

和UPDATE命令可以

UPDATE t1
  SET col1 = GET_RANDOM_VALUE()
  WHERE col1 IS NOT NULL;

通常,我避免在函数中使用SELECT,但是在这种情况下,我发现此解决方案更易读且更易于理解。

相关问题