【问题标题】:Oracle CTAS randomly populating column with specific charactersOracle CTAS 用特定字符随机填充列
【发布时间】:2020-07-01 17:01:03
【问题描述】:

我目前正在使用 CTAS 创建并使用随机值填充表。

我想更改 CTAS 以添加新列 work_days VARCHAR2(7)。这个新列的所有 7 个字节,对于所有行,如何随机填充“Y”或“N”?

例子:

YYYYNY

首先重写创建和清空表的过程,利用2个循环然后将所有内容连接在一起。

Create table employees(
 employee_id NUMBER(6), 
 first_name VARCHAR2(20),
 last_name VARCHAR2(20),
card_num VARCHAR2(10),
work_days VARCHAR2(7)
);

insert into employees.    (employee_id, first_name, last_name, card_num,  work_days)
with loop1(employee_id) as.    (select level from
 dual connect by level <= 50)
    ,loop2(b) as (select level from dual connect by level <= 7)

SELECT employee_id, 
CASE round(dbms_random.value(1,20)) 
        WHEN 1 THEN 'Albert' 
        WHEN 2 THEN 'Tom' 
        WHEN 3 THEN 'Anna'
        WHEN 4 THEN 'Ty' 
        WHEN 5 THEN 'Andy' 
        WHEN 6 THEN 'Thomas' 
        WHEN 7 THEN 'Alan'
        WHEN 8 THEN 'Tara' 
        WHEN 9 THEN 'Cheryl' 
        WHEN 10 THEN 'Ed' 
        WHEN 11 THEN 'Steve'
        WHEN 12 THEN 'Mel' 
        WHEN 13 THEN 'Micheal' 
        WHEN 14 THEN 'Ron' 
        WHEN 15 THEN 'Donald'
        WHEN 16 THEN 'Donny' 
        WHEN 17 THEN 'Racheal' 
        WHEN 18 THEN 'Debbie' 
        WHEN 19 THEN 'Madison'
        WHEN  20 THEN 'Danny' 
     END AS first_name,

 CASE  round(dbms_random.value(1,20)) 
        WHEN 1 THEN 'Andrews' 
        WHEN 2 THEN 'Thorton' 
        WHEN 3 THEN 'Smith'
        WHEN 4 THEN 'Jones' 
        WHEN 5 THEN 'Ott' 
        WHEN 6 THEN 'Stevens' 
        WHEN 7 THEN 'Feldman'
        WHEN 8 THEN 'Stein' 
        WHEN 9 THEN 'Ross' 
        WHEN 10 THEN 'Eden' 
        WHEN 11 THEN 'Saltzman'
        WHEN 12 THEN 'Kramer'
        WHEN 13 THEN 'Monroe' 
        WHEN 14 THEN 'Hanks' 
        WHEN 15 THEN 'Dunn'
        WHEN 16 THEN 'Dunbar' 
        WHEN 17 THEN 'Rucker' 
        WHEN 18 THEN 'Silverberg' 
        WHEN 19 THEN 'Daniels'
        WHEN  20 THEN 'Kahn' 
     END AS last_name, 
    
 dbms_random.string('X',        dbms_random.value(5, 10))  AS card_num,

      replace(listagg(CASE round(dbms_random.value(1,2))
                       WHEN 1 THEN 'Y'
                       WHEN 2 THEN 'N'
                      END,',')               within group (order by b)
             ,',') AS work_days
  FROM  loop1
    cross join loop2
 group by employee_id;

【问题讨论】:

    标签: sql oracle random


    【解决方案1】:

    我在获得非唯一值时遇到了一些麻烦,但是这个野兽起作用了:

    update employees set work_days = (
      select wd from (
        select level id, substr(wd, level, 7) wd
          from (select listagg(case when dbms_random.value(0, 1) <.5 then 'Y' else 'N' end) 
                       within group (order by null) wd
                  from dual connect by level <= 7*50)
          connect by level < 50 )
       where id = employees.employee_id)
    

    dbfiddle

    想法很简单,0.5以下的数字变为'Y',否则为'N'。然后将这个长字符串连接并切割成 50 个块。


    第二个,也许更简单的解决方案是merge

    merge into employees e
    using (select employee_id, translate(dbms_random.string('U', 7),
                                         'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
                                         'YYYYYYYYYYYYYNNNNNNNNNNNNN') str
             from employees) r
    on (e.employee_id = r.employee_id)
    when matched then update set work_days = str
    

    dbfiddle

    【讨论】:

    • 是否可以在单个语句中执行此操作?也许是循环中的循环?
    • 如果可以避免的话,我不喜欢硬编码值超过 1 个位置的想法。
    • 是的,我添加了第二个解决方案。
    【解决方案2】:

    您可以使用将 EMPLOYEE_ID 转换为二进制值的函数,并将它们转换为 Ys 和 Ns 的组合。

    功能(原here

    create or replace function dec2yn ( n number )
    return varchar2
    deterministic
    is
      binval varchar2( 7 ) := '' ;
      n2     pls_integer := mod( n, 128 ) ;  -- allow decimals between 0 and 127 (we only have 7 days)
    begin
      if n2 = 0 then return 'NNNNNNN' ;
      else
        while ( n2 > 0 ) loop
           binval := mod( n2, 2 ) || binval;
           n2 := trunc( n2 / 2 );
        end loop;
        binval := lpad( binval, 7, '0' ) ;           -- add 0 padding (lhs)
        binval := translate( binval, '01', 'NY' ) ;  -- translate: 0 -> N and 1 -> Y
        return binval;
      end if ;
    end dec2yn;
    /
    

    您可以在虚拟列中使用它(请参阅DBfiddle),或者您可以调用它并传入 EMPLOYEE_ID。

    查询

    select employee_id, first_name, last_name,  dec2yn( employee_id ) workdays_
    from employees ;
    
    -- result
    +-----------+----------+---------+---------+
    |EMPLOYEE_ID|FIRST_NAME|LAST_NAME|WORKDAYS_|
    +-----------+----------+---------+---------+
    |1          |Thomas    |Dunbar   |NNNNNNY  |
    |2          |Micheal   |Stein    |NNNNNYN  |
    |3          |Steve     |Monroe   |NNNNNYY  |
    |4          |Madison   |Eden     |NNNNYNN  |
    |5          |Albert    |Andrews  |NNNNYNY  |
    |6          |Donald    |Kramer   |NNNNYYN  |
    |7          |Andy      |Thorton  |NNNNYYY  |
    |8          |Donald    |Ross     |NNNYNNN  |
    |9          |Debbie    |Kramer   |NNNYNNY  |
    |10         |Steve     |Stevens  |NNNYNYN  |
    |11         |Micheal   |Monroe   |NNNYNYY  |
    |12         |Steve     |Smith    |NNNYYNN  |
    ...
    ...
    +-----------+----------+---------+---------+
    

    【讨论】:

    • 感谢大家的解决方案,所有的想法都很棒,但这只是为了生成示例数据来测试应用程序并提出了一个简单的解决方案并回答了我自己的问题。
    • 不用担心。感谢您的反馈。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多