使用 PL SQL 删除

Posted

技术标签:

【中文标题】使用 PL SQL 删除【英文标题】:Delete using PL SQL 【发布时间】:2014-12-11 08:46:55 【问题描述】:

如何通过提供输入文件使用 PL SQL 执行删除操作?我不想冒险直接从表中删除。是否可以通过将值作为输入来删除?如果有怎么办?

【问题讨论】:

你的实际问题是什么!详细说明你的情况 不直接从表中删除是什么意思。您还想在哪里删除? 情况是从一个表中删除 10K 个条目。我将这些 id 保存在一个文件中,我只想从表中删除它们。那么如何通过输入文件来删除呢? “不直接从表中删除”我的意思是我不想在 sn-p 中给出一个条件,例如“从条件 1 和条件 2 的 xxx 中删除” 如果不使用delete,就无法从表中删除。那么你的问题到底是什么? 【参考方案1】:

您可以将文件加载为外部表

然后编写查询以使用外部表中的条目删除条目

例如。

delete from yourtable where id in (select id from extTable)

外部表的一些文档:

http://docs.oracle.com/cd/B19306_01/server.102/b14215/et_concepts.htm

另一种方法是使用 oracle/sql 之外的脚本(例如 excel)生成删除语句,然后执行您的删除语句

【讨论】:

【参考方案2】:

编辑 仅用于使用 plsql 提取数据。

https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:68212348056

其他方法

1) 使用 shell 脚本(如 BASH)将数据从 FILE 传输到临时表中。

2) 然后使用临时表从主表中删除数据。

3) 在设置 Cron 作业后,您将获得额外的优势来再次执行相同的操作

示例脚本文件

#!/bin/ksh
ORAENV_ASK=NO
export ORAENV_ASK

ORACLE_SID=newsp1
inputFileBkUpDir=/usr/users/backup
inputFileDir=/usr/users/file
LogDir=/usr/users/log
ORACLE_HOME=/u01/app/oracle/product/9.2.0.6

export ORACLE_SID
export ORACLE_HOME
export inputFileBkUpDir
export inputFileDir
export LogDir

PATH=$PATH:/usr/local/bin
export PATH

. oraenv

# Log File
LOGFILE=$LogDir/EDI_file_`date +%y%m%d`.log;


# Create backup directory if its not created
if ! [ -d $inputFileBkUpDir ]
then
    mkdir $inputFileBkUpDir
fi


if ! [ -d $LogDir ] 
then
  echo 'LogDir not exists'
    echo "Trying to create directory" 
    mkdir $LogDir 
    if [ $? -ne 0 ]
    then
        echo "Log Directory " $LogDir " creation problem\nCannot continue process" >> $LOGFILE
        exit
    fi
    echo 'after LogDir created'
else
    chmod 777 $LogDir
    echo log permission changed of $LogDir
fi



#*********************************** FILE EXECUTION START ***********************************************

echo "\n>>> ******Processing File - STARTED at `date '+%d-%m-%Y %T %Z'`******">> $LOGFILE

sqlplus TEST_USER/PASS_USER << EOF
set serveroutput on;
spool /usr/users/spool.lst
delete from new_t.data;
commit;
spool off
exit
EOF

echo "\n>>> Check if EDI file has arrived - STARTED at `date '+%d-%m-%Y %T %Z'`">> $LOGFILE

for entry in "$inputFileDir"/YOUR_FILE*.dat;
do
  if [ -f "$entry" ];then
    echo "\n>>> Files present in input directory $inputFileDir">> $LOGFILE
    echo "\n>>> $entry" >> $LOGFILE
    echo "\n>>> Loading $entry file data for EDI DUMP\n" >>$LOGFILE

    sqlldr TEST_USER/PASS_USER control=/usr/users/control.ctl data=$entry log=$LogDir/fileLoader.log
    echo 'Total number of Records Successfully Loaded         \t\t\t\c'>>$LOGFILE; grep 'Rows successfully loaded' $LogDir/fileLoader.log | awk 'print $1'>>$LOGFILE
    echo 'Rows not loaded due to data error                   \t\t\t\c'>>$LOGFILE; grep 'Rows not loaded due to data errors' $LogDir/fileLoader.log | awk 'print $1'>>$LOGFILE
    echo 'Rows not loaded because all WHEN clauses were failed\t\t\t\c'>>$LOGFILE; grep 'Rows not loaded because all WHEN clauses were failed' $LogDir/fileLoader.log | awk 'print $1'>>$LOGFILE
    echo 'Rows not loaded because all fields were null        \t\t\t\c'>>$LOGFILE; grep 'Rows not loaded because all fields were null' $LogDir/fileLoader.log | awk 'print $1'>>$LOGFILE
    echo "\n>>> Data loaded from $entry file" >>$LOGFILE

    mv $entry $inputFileBkUpDir
    echo "\n>>> Moving $entry file to archive path $inputFileBkUpDir" >>$LOGFILE

  else
    echo 'Files not present' >> $LOGFILE
  fi
done

echo "\n>>> ******Data Load Completed******" >>$LOGFILE

echo "\n>>> ******Processing Started FILE TO DELETE DATA******" >>$LOGFILE

sqlplus TEST_USER/PASS_USER << EOF
set serveroutput on;
spool /usr/users/spool.lst
@/usr/users/Data_Processing.sql;
spool off
exit
EOF
echo "\n>>> ******Processing complete- Data DELETED******" >>$LOGFILE
echo "End of the script">> $LOGFILE

设置如何从您的文件中读取 IDS 到临时表的示例控制文件

LOAD DATA
        APPEND INTO TABLE COLSIMS.EDI_DATA_LOAD
        (
          S_NUMBER        POSITION(1:25),
          P_CODE          POSITION(26:50),
          P_NUMBER        POSITION(51:80),
          T_TIMESTAMP     POSITION(406:417) date "YYMMDDHH24MISS",
          L_TIMESTAMP     sysdate
         )

【讨论】:

【参考方案3】:

假设这些 ID 值在文件中以每行一个 ID 的形式存储,并且 ID 值是数字,那么您应该可以开始以下操作:

DECLARE
  fHandle        UTL_FILE.FILE_TYPE;
  strBuffer      VARCHAR2(32767);
  nRows_deleted  NUMBER := 0;
BEGIN
  fHandle := UTL_FILE.FOPEN('some_directory', 'filename.dat', 'r');

  LOOP
    BEGIN
      UTL_FILE.GET_LINE(fHandle, strBuffer);
    EXCEPTION
      WHEN NO_DATA_FOUND THEN  -- end of file
        EXIT;                  -- exit the loop
    END;

    DELETE FROM SOME_TABLE
      WHERE ID = TO_NUMBER(strBuffer);

    nRows_deleted := nRows_deleted + SQL%ROWCOUNT;
  END LOOP;

  COMMIT;

  DBMS_OUTPUT.PUT_LINE('Changes committed');

  UTL_FILE.FCLOSE(fHandle);

  DBMS_OUTPUT.PUT_LINE('Completed successfully, ' || nRows_deleted || ' rows deleted');
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('Error: ' || SQLCODE  || ' - ' || SQLERRM);
    ROLLBACK;
    DBMS_OUTPUT.PUT_LINE('All changes ROLLED BACK');
    RAISE;
END;

编辑

作为替代选项,您可以定义一个外部表以允许您的文件被视为只读表:

CREATE TABLE DATA_FROM_FILE
  (ID     CHAR(10))
  ORGANIZATION EXTERNAL
    (TYPE ORACLE_LOADER
     DEFAULT DIRECTORY some_directory
     ACCESS PARAMETERS
       (RECORDS DELIMITED BY NEWLINE
        FIELDS (ID  CHAR(10))
       )
     LOCATION ('filename.dat'));

这将允许你做类似的事情

DELETE FROM SOME_TABLE
  WHERE ID IN DATA_FROM_FILE;

分享和享受。

【讨论】:

以上是关于使用 PL SQL 删除的主要内容,如果未能解决你的问题,请参考以下文章

PL/SQl,oracle 9i,使用sql删除重复行

PL SQL - 使用动态 SQL 生成删除语句

在 PL/SQL 中删除 xml 节点

PL SQL 删除非 Ascii 字符,但不删除回车符

更新/删除不存在的行时的 PL/SQL 异常

PL/SQL 触发器更新或删除