【问题标题】:I want to update with string in a table with rdbms function我想用 rdbms 函数的表中的字符串更新
【发布时间】:2021-04-30 19:04:14
【问题描述】:

我想用带有rdbms 的行选择的随机字符串更新一个表,但它给了我ORA-00907: missing right parenthesis 的错误。 我试图找到右括号在哪里丢失但没有得到这个请帮助我关于这个我选择同一个表并想要更新同一个表列 我做的是这个

UPDATE PAY_IN_OUT
SET ATT_PRESENT ='L'
WHERE EMP_CODE = 
( SELECT EMP_CODE
    FROM   PAY_IN_OUT
    ORDER BY DBMS_RANDOM.RANDOM )
WHERE  rownum < 40
AND ATT_DATE BETWEEN DATE '2020-09-01' AND DATE '2021-03-31'
AND  ((TO_CHAR(ATT_DATE, 'DAY'))) != 'SUNDAY';

【问题讨论】:

  • 您有两个不正确的 where 子句。您有一个子查询,它可能在只能使用标量子查询的上下文中返回多行。代码有很多问题。
  • @GordonLinoff 好的,那么我能做什么我想在随机行上用L 更新att_present 列我能做什么亲爱的,请帮助我
  • 从 2020 年 9 月 1 日到 2021 年 3 月 31 日之间的所有行中,除了星期日,您想随机选择 39 行并设置它们的 att_present = 'L'?是的?表的主键是什么?

标签: sql oracle plsql


【解决方案1】:

此语句会将部分行 ATT_PRESENT 更新为 L

MERGE INTO pay_in_out src
     USING (  SELECT 'L' AS NEW_ATT_PRESENT, emp_code
                FROM pay_in_out
               WHERE     ATT_DATE BETWEEN DATE '2020-09-01' AND DATE '2021-03-31'
                     AND ((TO_CHAR (ATT_DATE, 'DAY'))) != 'SUNDAY'
            ORDER BY DBMS_RANDOM.VALUE
               FETCH FIRST 40 ROWS ONLY) d
        ON (src.emp_code = d.emp_code)
WHEN MATCHED
THEN
    UPDATE SET src.att_present = d.new_att_present;

【讨论】:

  • 亲爱的,它在前 39 行中有些行不是随机的整个表
  • @Zedan 您最初的尝试包括WHERE rownum &lt; 40。如果您只想更新所有星期日,请删除该条件。
  • @EJ to_char(att_date,'DAY') 可能需要为 to_char(att_date,'fmDAY')。 OP的双括号也不是必需的。
  • @Zedan,我已更新声明以使用 MERGE。这个 UPDATE 应该从表中随机选择 40 行。
  • 亲爱的@WilliamRobertson 我删除了WHERE rownum &lt; 40error 是一样的
【解决方案2】:

根据您的评论,您似乎想要这样的东西:

UPDATE PAY_IN_OUT PO
    SET ATT_PRESENT = 'L'
    WHERE PO.EMP_CODE IN (SELECT PO2.EMP_CODE 
                          FROM PAY_IN_OUT PO2
                          WHERE ATT_DATE BETWEEN DATE '2020-09-01' AND DATE '2021-03-31' AND
                              TO_CHAR(ATT_DATE, 'DY') <> 'SUN'
                          ORDER BY DBMS_RANDOM.RANDOM
                          FETCH FIRST 40 ROWS ONLY
                         );

在旧版本的 Oracle 中,尝试:

UPDATE PAY_IN_OUT PO
    SET ATT_PRESENT = 'L'
    WHERE PO.EMP_CODE IN (SELECT PO2.EMP_CODE
                          FROM (SELECT PO2.EMP_CODE 
                                FROM PAY_IN_OUT PO2
                                WHERE ATT_DATE BETWEEN DATE '2020-09-01' AND DATE '2021-03-31' AND
                                      TO_CHAR(ATT_DATE, 'DY') <> 'SUN'
                                ORDER BY DBMS_RANDOM.RANDOM
                               ) PO2
                          WHERE rownum <= 40
                         );

这假定EMP_CODE 在表中是唯一的。如果不是,请使用主键进行比较。

【讨论】:

  • 尊敬的先生,您的代码也适用于 18C 我检查了 dbfiddle 但不是 11gR2
  • @Zedan 。 . .该版本不再受支持。但我添加了另一个版本。
【解决方案3】:

由于您标记了 PL/SQL,您可以尝试编程方法:

declare
    rows_updated number := 0;
begin
    for r in (
        select rowid as rwd from pay_in_out sample(10)
        where  att_date between date '2020-09-01' and date '2021-03-31'
        and    to_char(att_date, 'DY', 'nls_date_language = English') != 'SUN'
        for update
    )
    loop
        update pay_in_out
        set    att_present = 'L'
        where  rowid = r.rwd;
        
        rows_updated := rows_updated +1;
        exit when rows_updated >= 40;
    end loop;
end;

请注意,sample(10) 会从表格中抽取 10% 的样本。这是太小还是太大取决于表中有多少行。您可以查询 user_tables.num_rows 以获取近似计数,然后根据您指定日期范围内的非星期天数调整它(如果您的统计数据不是过时的,或者您可以计算它们)。

【讨论】:

    【解决方案4】:

    从 2020 年 9 月 1 日到 2021 年 3 月 31 日之间的所有行中,除了星期日,您想随机选择 39 行并设置它们的 att_present = 'L'。

    在 Oracle 11 之前,您必须使用 Oracle 的 ROWNUM,因为标准 SQL 子句 FETCH FIRST ROWS 不可用。

    update pay_in_out
    set att_present = 'L'
    where rowid in 
    (
      select random_rowid
      from
      (
        select rowid as random_rowid
        from pay_in_out
        where att_date between date '2020-09-01' and date '2021-03-31'
        and to_char(att_date, 'fmDAY', 'nls_date_language=English') <> 'SUNDAY';
        order by dbms_random.random
      )
      where rownum <= 39
    );
    

    在标准 SQL 中,不能保证子查询会被打乱(因为子查询是无序的数据集,所以 ORDER BY 子句可以被忽略),但 Oracle 保证,为了使他们的 ROWNUM 方法工作:-)

    ROWID 也是 Oracle 特定的。如果需要,您可以使用表的主键。

    【讨论】:

    • 'DAY' 应该是'fmDAY'(或'Dy',因为它总是3个英文字符)。为什么 Oracle 用我们永远不会知道的空白填充值。
    • @William Robertson:正确,我完全忘记了那些烦人的空白。谢谢。我已经相应地更新了我的答案。
    • @WilliamRobertson 只是对空白填充的假设。 Oracle V2 于 1979 年发布。当时,主要的输出格式是具有非比例字体的固定长度列。空间填充非常适合这种风格。所以也许甲骨文只是没有更新。 (他们会声称具有向后可比性。)哦,程序员该做什么?
    猜你喜欢
    • 1970-01-01
    • 2021-12-14
    • 2021-11-12
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 2020-01-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多