mp1_update_oracle.ksh

#!/usr/bin/ksh

################################################################################

#

# @PRODUCT@ update scripts for Single or RAC database V1.0 

#

# Upgrade Oracle from 10.1.0.4.0 to 10.1.0.5.0

# Upgrade Oracle OPatch from 1.0.0.0.55 to 1.0.0.0.57

# Install Oracle CPU October 2008 (7375686)

#

# @COPYRIGHT@

################################################################################

 

export ORACLE_HOME=/opt/oracle/server/10.1

export CRS_HOME=/opt/oracle/crs/10.1

 

SOURCE_DIR=`dirname $0`

SOURCE_DIR=`cd $SOURCE_DIR && pwd`

export SOURCE_DIR

 

 

INSTALL_LOG_DIR=/var/tmp/prof6_install

export INSTALL_LOG_DIR

 

HISTORY_LOG=$INSTALL_LOG_DIR/install_history.log

export HISTORY_LOG

 

CLUSTER=false

export CLUSTER

 

CLUSTER_NODE_ID=0

export CLUSTER_NODE_ID

 

SKIP_PATCHSET=false

SKIP_OPATCH=false

SKIP_CPU=false

export SKIP_PATCHSET

export SKIP_OPATCH

export SKIP_CPU

 

test ! -d $INSTALL_LOG_DIR && mkdir -p $INSTALL_LOG_DIR && chown root:other $INSTALL_LOG_DIR && chmod 777 $INSTALL_LOG_DIR

test -f $HISTORY_LOG && rm -f $HISTORY_LOG

touch $HISTORY_LOG

chown root:other $HISTORY_LOG

chmod 777 $HISTORY_LOG

 

 

# Copy all screen output to install_history.log file

# Thus all output can be found also from log file

tee -a $HISTORY_LOG >/dev/tty |&

 

exec 1>&p

# Redirect errout to stdout

exec 2>&1

echo "Script Started at `date /"+%Y-%m-%d  %H:%M:%S/"`" >>$HISTORY_LOG

HOSTNAME=`uname -n`

if [ "$HOSTNAME" = "" ];then

  echo "ERROR: Could not resolve hostname with command /"uname -n/"...please restart the setup"

  exit 1

fi

 

###############################################################################

#

# Functions

#

###############################################################################

 

#

# Test RSH connection in clustered installations.

#

test_rsh_connection() {

  echo "Testing RSH connection.../c"

    rsh clnode2 "ls -la" >> /dev/null

    if [ $? -eq 0 ]; then

      echo "Done"

      return 0

    else

      echo "ERROR: RSH connection to clnode2 is not working."

      echo "ERROR: Please check /.rhosts and /etc/inet/inetd.conf files from clnode2."

      exit 1

    fi

}

 

 

###############################################################################

#

# Check OS,  Set CLUSTER & CLUSTER_NODE_ID variables

#

###############################################################################

/usr/sbin/clinfo > /dev/null 2>&1

if [ $? -eq 0 ]; then

  CLUSTER=true

  PATH=$PATH:/usr/cluster/bin

  export PATH

  CLUSTER_NODE_ID=`/usr/sbin/clinfo -n` > /dev/null

  NODE_COUNT=`/usr/cluster/bin/scha_cluster_get -O ALL_NODEIDS | wc -l` > /dev/null

  if [ $NODE_COUNT -eq 4 ]; then

    echo "ERROR: This installation does not support installations in multinode."

    exit 1

  elif [ $CLUSTER_NODE_ID -ne 1 ]; then

    echo "ERROR: Installation must be started in node 1"

    exit 1

  fi

  echo "Clustered Solaris detected with node id $CLUSTER_NODE_ID"

  test_rsh_connection

else

  echo "Non clustered Solaris detected"

fi

echo "Operating system check finished/n"

 

###############################################################################

#

# Pre-condition Check

#

###############################################################################

ORA_VER=`su - oracle -c "sqlplus -v"|grep .|awk '{print $3}'`

if [ "$ORA_VER" = "10.1.0.4.0" ];then

  echo "Current Oracle Version $ORA_VER detected."  

elif [ "$ORA_VER" = "10.1.0.5.0" ];then

  echo  "Current Oracle Version is already 10.1.0.5.0, Continue? Please answer Yes(Y) or No(N):/c"

  while read answer 

  do

    case $answer in

      N|n)

        echo "Cancelled by User."

        exit 1

        ;;

      Y|y)

        SKIP_PATCHSET=true

        break

        ;;

      *)

        echo  "Please answer Yes(Y) or No(N):/c"

        ;;

    esac

  done    

else

  echo "Current Oracle Version is $ORA_VER, not 10.1.0.4.0. Can not upgrade to 10.1.0.5.0. Transaction exit !"

  exit 1

fi  

 

# Go on to check OPatch version

#OPATCH_VER=`su - oracle -c "$ORACLE_HOME/OPatch/opatch version"|grep "OPatch Version: "|awk '{print $3}'` 

 

#if [ "$OPATCH_VER" = "1.0.0.0.55"  ]; then  

#  echo "Current Oracle OPatch Version $OPATCH_VER detected."

#elif   [ "$OPATCH_VER" = "1.0.0.0.57"  ]; then

#  echo "Current Oracle Opatch Version is already 1.0.0.0.57, Continue? Please answer Yes(Y) or No(N):/c"

#    while read answer 

#    do

#      case $answer in

#        N|n)

#          echo "Cancelled by User."

#          exit 1

#          ;;

#        Y|y)

#          SKIP_OPATCH=true

#          break

#          ;;

#        *)

#          echo "Please answer Yes(Y) or No(N):/c"

#          ;;

#      esac

#    done    

#else

#  echo "Current Oracle OPatch Version is $OPATCH_VER, not 1.0.0.0.55. Can not upgrade to 1.0.0.0.57. Transaction exit !"

#  exit 1

#fi

 

# Check cpu

su - oracle -c "$ORACLE_HOME/OPatch/opatch lsinventory"| grep 7375686 > /dev/null

if [ $? -eq 0 ]; then

  echo "CPU Oct 2008 already installed. Continue? Please answer Yes(Y) or No(N):/c"

  while read answer 

    do

      case $answer in

        N|n)

          echo "Cancelled by User."

          exit 1

          ;;

        Y|y)

          SKIP_CPU=true

          break

          ;;

        *)

          echo "Please answer Yes(Y) or No(N):/c"

          ;;

      esac

    done    

else

  echo "CPU Oct 2008 not installed as expected."  

fi

 

###############################################################################

#

#Free disk space check

#1. space for backup crs 800M

#2. space for backup database 1.8G

#3. space for unzip 10.1.0.5 patch 800M 

#4. space for unzip cpuOct2008 100M

#

###############################################################################

if [ "$SKIP_PATCHSET" = "false" ];then

  #Please specify BACKUP_DIR in a filesystem which has at least 2.5GB left free space.

  #if this directory is shared by both nodes, free space should be doubled.

  if [ "$BACKUP_DIR" = "" ];then

    if [ "$CLUSTER" = "true" ];then

      BACKUP_DIR=/global/clnode1/archive/backup

    else

      BACKUP_DIR=/var/tmp/backup

    fi

    export BACKUP_DIR

  fi

 

  ENOUGH_SPACE=true

 

  BACKUP_DIR_ROOT=`echo $BACKUP_DIR|cut -d/ -f2`

  if [ "$BACKUP_DIR_ROOT" = "global" ];then

    FREE_SPACE=6291456

  else

    FREE_SPACE=3145728

  fi

  test ! -d $BACKUP_DIR && mkdir $BACKUP_DIR && chmod 666 $BACKUP_DIR

  VAR_FREE1=`df -k $BACKUP_DIR|grep -v avail|awk '{print $4}'`

  if [ "$CLUSTER" = "true" ];then

    rsh clnode2 "test ! -d $BACKUP_DIR && mkdir $BACKUP_DIR && chmod 666 $BACKUP_DIR"

    VAR_FREE2=`rsh clnode2 "df -k $BACKUP_DIR"|grep -v avail|awk '{print $4}'`

    if [ $VAR_FREE1 -le $FREE_SPACE ] -o [ ]$VAR_FREE2 -le $FREE_SPACE ];then

      echo "Not enough free space on $BACKUP_DIR, at least $FREE_SPACE KB, only $VAR_FREE1 KB on clnode1 and $VAR_FREE2 KB on clnode2 left."

      ENOUGH_SPACE=false

    else

      echo   "$BACKUP_DIR has $VAR_FREE1 KB on clnode1 and $VAR_FREE2 KB on clnode2 left."

    fi

  else

    if [ $VAR_FREE1 -le $FREE_SPACE ];then

      echo "Not enough free space on $BACKUP_DIR, at least $FREE_SPACE KB, only $VAR_FREE1 KB left."

      ENOUGH_SPACE=false

    else

      echo   "$BACKUP_DIR has $VAR_FREE1 KB left."

    fi

  fi

 

  TMP_FREE=`df -k /tmp|grep -v avail|awk '{print $4}'`

  if [ $TMP_FREE -le 1048576 ];then

    echo "Not enough free space on /tmp, at least 1048576 KB, only $TMP_FREE KB left"

    ENOUGH_SPACE=false

  else

    echo   "/tmp has $TMP_FREE KB left."

  fi

  if [ "$ENOUGH_SPACE" = "false" ];then

    echo "Please define BACKUP_DIR environment variable to specify the directory for backup that has enough freespace, and re-run the update script."

    exit 1

  fi

fi

 

#End of Free disk space check

 

echo "Environment Checking .... Passed! Ready to Update!"

 

echo "/nDebugging Informations:"

echo "SKIP_PATCHSET=$SKIP_PATCHSET"

echo "SKIP_OPATCH=$SKIP_OPATCH"

echo "SKIP_CPU=$SKIP_CPU"

echo "ENOUGH_SPACE=$ENOUGH_SPACE"

echo "INSTALL_LOG_DIR=$INSTALL_LOG_DIR"

echo "BACKUP_DIR=$BACKUP_DIR"

 

###############################################################################

#

# Oracle shutdown

#

###############################################################################

echo "/n**1** Shutting down Oracle"

 

if [ "$SKIP_PATCHSET" = "false" ];then

  echo "Shutting down all oracle instances"

  if [ "$CLUSTER" = "true" ]; then

    echo "Stopping database.../c"

    su - oracle -c "srvctl stop database -d nap3"

    echo "Done."

    echo "Stopping nodeapps.../c"

    su - oracle -c "srvctl stop nodeapps -n clnode1"

    echo ", clnode1 shutdown finished/c"

    su - oracle -c "srvctl stop nodeapps -n clnode2"

    echo ", clnode2 shutdown finished."

    echo "Stopping crs daemon..."

    /etc/init.d/init.crs stop

    rsh clnode2 "/etc/init.d/init.crs stop"

  else

    /etc/init.d/dbora stop

  fi

  echo "Shutdown completed."

fi

 

###############################################################################

#

#Backup Oracle Software

#

###############################################################################

echo "/n**2** Backup Oracle Software"

if [ "$SKIP_PATCHSET" = "false" ]; then

  if [ "$CLUSTER" = "true" ]; then

    echo "Backup crs software on clnode1.../c"

    tar -cvf $BACKUP_DIR/crs1.tar $CRS_HOME >>$HISTORY_LOG

    if [ $? -eq 0 ]; then

      echo "Done."

    else

      echo "Failed."

      exit 1

    fi

 

    echo "Backup crs software on clnode2.../c"

    rsh clnode2 "tar -cvf $BACKUP_DIR/crs2.tar $CRS_HOME" >>$HISTORY_LOG

    if [ $? -eq 0 ]; then

      echo "Done."

    else

      echo "Failed."

      exit 1

    fi

 

    echo "Backup oracle software on clnode1.../c"

    tar -cvf $BACKUP_DIR/server1.tar $ORACLE_HOME >>$HISTORY_LOG

    if [ $? -eq 0 ]; then

      echo "Done."

    else

      echo "Failed."

      exit 1

    fi

 

    echo "Backup oracle software on clnode2.../c"

    rsh clnode2 "tar -cvf $BACKUP_DIR/server2.tar $ORACLE_HOME" >>$HISTORY_LOG

    if [ $? -eq 0 ]; then

      echo "Done."

    else

      echo "Failed."

      exit 1

    fi

  else

    echo "Backup oracle software .../c"

    tar -cvf $BACKUP_DIR/server10.1.tar $ORACLE_HOME >>$HISTORY_LOG

     if [ $? -eq 0 ]; then

      echo "Done."

    else

      echo "Failed."

      exit 1

    fi

  fi

elif [ "$SKIP_PATCHSET" = "true" ]; then

  echo "Skip Oracle software backup."

fi

#End of Backup Oracle Software

 

echo "/nOracle backup finished!"

 

 

#Backup old OPatch

echo "/n**3** Backup old OPatch tool"

if [ "$SKIP_OPATCH" = "false" ];then

  OPATCH_VER=`su - oracle -c "$ORACLE_HOME/OPatch/opatch version"|grep "OPatch Version: "|awk '{print $3}'` 

  if [ "$CLUSTER" = "true" ]; then

    cp -r $ORACLE_HOME/OPatch $ORACLE_HOME/OPatch_bak_$OPATCH_VER 

    echo "clonde1 OPatch $OPATCH_VER Backup completed successfully! "

 

    rsh clnode2 "cp -r $ORACLE_HOME/OPatch $ORACLE_HOME/OPatch_bak_$OPATCH_VER"

    echo "clonde2 OPatch $OPATCH_VER Backup completed successfully! "

  else

#    /etc/init.d/dbora stop

    cp -r $ORACLE_HOME/OPatch $ORACLE_HOME/OPatch_bak_$OPATCH_VER  

    echo "OPatch $OPATCH_VER Backup completed successfully! "

  fi

else

  echo "Skip OPatch backup."

fi

 

 

 

 

###############################################################################

#

# 1. Oracle upgrade to 10.1.0.5.0 

# 2. Oracle OPatch update to 10.0.0.0.57

# 3. Oracle cpuOct2008 apply

#

###############################################################################

 

# 1. Oracle upgrade to 10.1.0.5.0 

#unpacking file and install patch

echo "/n**4** Upgrade Oracle Software"

if [ "$SKIP_PATCHSET" = "false" ];then

  echo "Unpacking Oracle 10.1.0.5.0 patch..../c"

  if [ "$CLUSTER" = "true" ]; then

    su - oracle -c "cd /tmp; unzip -o $SOURCE_DIR/patchset/p4505133_10105_SOLARIS64.zip" >> $HISTORY_LOG

    su - oracle -c "cd /tmp/Disk1/;./runInstaller -silent -responseFile $SOURCE_DIR/response/rac_crs.rsp"| tee -a /tmp/oracle10.1.0.5.log 

    echo "Starting to patch Oracle database home"

    su - oracle -c "cd /tmp/Disk1/;./runInstaller -silent -responseFile $SOURCE_DIR/response/rac_db.rsp"| tee -a /tmp/oracle10.1.0.5.log 

    echo "Running db root.sh on clnode1"

    $ORACLE_HOME/root.sh <<@EOF

 

Y

Y

Y

@EOF

    echo "Running db root.sh on clnode2"

    rsh clnode2 "$ORACLE_HOME/root.sh <<@EOF

 

Y

Y

Y

@EOF"

  else

    su - oracle -c "cd /tmp; unzip -o $SOURCE_DIR/patchset/p4505133_10105_SOLARIS64.zip" >> $HISTORY_LOG

    su - oracle -c "cd /tmp/Disk1;./runInstaller -silent -responseFile $SOURCE_DIR/response/single.rsp"| tee -a /tmp/oracle10.1.0.5.log 

    echo "Running db root.sh"

    $ORACLE_HOME/root.sh <<@EOF

 

Y

Y

Y

@EOF

  fi

  echo "Done"

 

  #Verify if Oracle is updated successfully

  ORA_VER=`su - oracle -c "sqlplus -v"|grep .|awk '{print $3}'`

  if [ "$ORA_VER" != "10.1.0.5.0" ];then 

    echo "Oracle upgrade failed! Transaction abort !"

    exit 1

  else 

    echo "/nOracle database software updated successfully! Need executing sqls..."

  fi

 

  #Start Upgrade Oracle 10.1.0.5

  if [ "$CLUSTER" = "true" ]; then

    /etc/init.d/init.crs start

    echo "Sleeping 300 seconds to wait crs startup"

    sleep 300

    su - oracle -c "srvctl start nodeapps -n clnode1"

    su - oracle -c "srvctl start instance -d nap3 -i nap3x1"

    su - oracle -c "sqlplus /nolog" <<@EOF

    CONNECT / AS SYSDBA

    ALTER SYSTEM SET CLUSTER_DATABASE=FALSE SCOPE=spfile;

    SHUTDOWN IMMEDIATE

    STARTUP UPGRADE

    SPOOL patch.log

    @$ORACLE_HOME/rdbms/admin/catpatch.sql

    SPOOL OFF

    SHUTDOWN IMMEDIATE

    STARTUP

    @$ORACLE_HOME/rdbms/admin/utlrp.sql

    ALTER SYSTEM SET CLUSTER_DATABASE=TRUE SCOPE=spfile;

    SHUTDOWN IMMEDIATE

    STARTUP

@EOF

  else

    su - oracle -c "sqlplus /nolog" <<@EOF 

    CONNECT / AS SYSDBA

    STARTUP UPGRADE

    SPOOL patch.log

    @$ORACLE_HOME/rdbms/admin/catpatch.sql

    SPOOL OFF

    SHUTDOWN IMMEDIATE

    STARTUP

    @$ORACLE_HOME/rdbms/admin/utlrp.sql

@EOF

  fi

  #Running changePerm.sh script on an Oracle database server home

  su - oracle -c "cd $ORACLE_HOME/install;./changePerm.sh <<@EOF

y

@EOF"  

  if [ "$CLUSTER" = "true" ]; then

    rsh clnode2 "su - oracle -c /"cd $ORACLE_HOME/install;./changePerm.sh <<@EOF

y

@EOF/""

  fi

else

  echo "Skip Oracle Patchset 10.1.0.5 installation."

fi

 

# 2. Oracle OPatch update to 10.0.0.0.57

echo "/n**5** Upgrade OPatch tool"

if [ "$SKIP_OPATCH" = "false" ];then

  if [ "$CLUSTER" = "true" ]; then

    su - oracle -c "srvctl stop database -d nap3"

    su - oracle -c "srvctl stop nodeapps -n clnode1"

    su - oracle -c "srvctl stop nodeapps -n clnode2"

    /etc/init.d/init.crs stop

    rsh clnode2 "/etc/init.d/init.crs stop"

 

    cd $ORACLE_HOME && unzip -o $SOURCE_DIR/patchset/p2617419_10102_GENERIC.zip >> $HISTORY_LOG

    #should check if clnode1 is already 1.0.0.0.57

    echo "clonde1 OPatch Upgrade completed successfully! Current OPatch version is 1.0.0.0.57."

 

    rcp $SOURCE_DIR/patchset/p2617419_10102_GENERIC.zip clnode2:/tmp  

    rsh clnode2 "cd $ORACLE_HOME && unzip -o /tmp/p2617419_10102_GENERIC.zip"

    #should check if clnode2 is already 1.0.0.0.57

    echo "clnode2 OPatch Upgrade completed successfully! Current OPatch version is 1.0.0.0.57."

  else

    /etc/init.d/dbora stop

    mv $ORACLE_HOME/OPatch $ORACLE_HOME/OPatch_bak_1.0.0.0.55  

    #OPatch update

    cd $ORACLE_HOME && unzip -o $SOURCE_DIR/patchset/p2617419_10102_GENERIC.zip >> $HISTORY_LOG

    echo "OPatch Upgrade completed successfully! Current OPatch version is 1.0.0.0.57."

  fi

else

  echo "Skip OPatch installation."

fi

 

 

# 3. Oracle cpuOct2008 apply p7375686_10105_SOLARIS64.zip

echo "/n**6** Apply cpuOct2008"

if [ "$SKIP_CPU" = "false" ]; then

  echo "Updating system with CPU Oct 2008"

  echo "Unpacking patch.../c"

  su - oracle -c "cd /tmp; unzip -o $SOURCE_DIR/patchset/p7375686_10105_SOLARIS64.zip" >> $HISTORY_LOG

  echo "Done"

 

  if [ "$CLUSTER" = "true" ]; then

    su - oracle -c ". /etc/oracle_env.sh;cd /tmp/7375686; $ORACLE_HOME/OPatch/opatch apply -local <<@EOF

Y

@EOF"

    su - oracle -c "/tmp/7375686/custom/scripts/post"

echo "/ncpuOct2008 applied successfully in clnode1! "

 

    rcp $SOURCE_DIR/patchset/p7375686_10105_SOLARIS64.zip clnode2:/tmp

    rsh clnode2 "su - oracle -c /"cd /tmp; unzip -o p7375686_10105_SOLARIS64.zip/""

    rsh clnode2 "su - oracle -c /". /etc/oracle_env.sh;cd /tmp/7375686; $ORACLE_HOME/OPatch/opatch apply -local <<@EOF

Y

@EOF/""

    rsh clnode2 "su - oracle -c /"/tmp/7375686/custom/scripts/post/""

echo "/ncpuOct2008 applied successfully in clnode1! "

  else

    su - oracle -c ". /etc/oracle_env.sh;cd /tmp/7375686; $ORACLE_HOME/OPatch/opatch apply <<@EOF

Y

@EOF"

    . /etc/oracle_env.sh; sh /tmp/7375686/cpu_root.sh <<@EOF

Y

@EOF

echo "/ncpuOct2008 applied successfully in clnode1! "

  fi

else

  echo "Skip CPU 2008 October installation."

fi

###############################################################################

#

# Finalizing Oracle patching

#

###############################################################################  

if [ "$SKIP_CPU" = "false" ];then

  echo "/nFinalizing Oracle patching.../c"

  if [ "$CLUSTER" = "true" ]; then

    echo "/nStarting Oracle CRS in clnode1..."

    /etc/init.d/init.crs start

    echo "/nWaiting 300 seconds CRS startup..."

    sleep 300

    su - oracle -c "srvctl start nodeapps -n clnode1"

    su - oracle -c "srvctl start instance -d nap3 -i nap3x1"

    su - oracle -c ". /etc/oracle_env.sh;cd /$ORACLE_HOME/cpu/CPUOct2008; sqlplus /"/ as sysdba/" <<@EOF

  @catcpu.sql

  @$ORACLE_HOME/rdbms/admin/utlrp.sql

  shutdown immediate

  exit

@EOF"

    echo "Finalizing done."

  else

    su - oracle -c ". /etc/oracle_env.sh;cd /$ORACLE_HOME/cpu/CPUOct2008; sqlplus /"/ as sysdba/" <<@EOF

  startup

  @catcpu.sql

  @$ORACLE_HOME/rdbms/admin/utlrp.sql

  shutdown

  exit

@EOF"

    echo "Finalizing done."

  fi

fi

  #Start All Oracle Service

if [ "$SKIP_PATCHSET" = "false" -o "$SKIP_CPU" = "false" ]; then

  if [ "$CLUSTER" = "true" ]; then

    su - oracle -c "srvctl start instance -d nap3 -i nap3x1"

    rsh clnode2 "/etc/init.d/init.crs start"

    echo "Waiting 300 seconds CRS startup..."

    sleep 300

    su - oracle -c "srvctl start nodeapps -n clnode2"

    su - oracle -c "srvctl start instance -d nap3 -i nap3x2"

  else

    /etc/init.d/dbora start

  fi

fi

echo "Oracle Update Finished."

su - oracle -c "/opt/oracle/crs/10.1/bin/crs_stat -t"

echo "Script Ended at `date /"+%Y-%m-%d  %H:%M:%S/"`" >>$HISTORY_LOG

修正前:SElECT mi2.item_code , mp1.pma_code , mp1.pma_name , mp1.pma_display_order , mic1.information_category_code , mic1.information_category_name , mic1.information_category_display_order , ms1.subcategory_code , ms1.subcategory_name , ms1.subcategory_display_order , mi2.recommendation_sales_price , mi2.quantity_cost_price , mvn1.vendor_code , mvn1.vendor_name FROM ( SELECT DISTINCT mi1.pattern_type , mi1.pattern_code , mi1.item_code , mi1.information_category_code , mi1.subcategory_code , mi1.pma_code , mi1.recommendation_sales_price , mi1.quantity_cost_price , mi1.vendor_code FROM m_item_0226_001 mi1 WHERE item_code IN (‘01’) AND mi1.apply_start_date <= Cast(‘20240220’ as date) AND Cast(‘20240220’ as date) <= mi1.apply_end_date ) mi2 , m_information_category_0226_001 mic1 , m_subcategory_0226_001 AS ms1 , m_pattern_0105_001 AS mpt1 , m_pma_0226_001 mp1 , m_vendor_name_0226_001 mvn1 WHERE mpt1.original_store_code = ‘1234567890’ AND mi2.pattern_type = mpt1.pattern_type AND mi2.pattern_code = mpt1.pattern_code AND mpt1.apply_start_date <= Cast(‘20240220’ as date) AND Cast(‘20240220’ as date) <= mpt1.apply_end_date AND mi2.information_category_code = mic1.information_category_code AND mic1.apply_start_date <= Cast(‘20240220’ as date) AND Cast(‘20240220’ as date) <= mic1.apply_end_date AND mi2.information_category_code = ms1.information_category_code AND mi2.subcategory_code = ms1.subcategory_code AND ms1.apply_start_date <= Cast(‘20240220’ as date) AND Cast(‘20240220’ as date) <= ms1.apply_end_date AND mi2.pma_code = mp1.pma_code AND mp1.apply_start_date <= Cast(‘20240220’ as date) AND Cast(‘20240220’ as date) <= mp1.apply_end_date AND mi2.vendor_code = mvn1.vendor_code order by mi2.item_code 修正后:SElECT DISTINCT mi2.item_code , mp1.pma_code , mp1.pma_name , mp1.pma_display_order , mic1.information_category_code , mic1.information_category_name , mic1.information_category_display_order , ms1.subcategory_code , ms1.subcategory_name , ms1.subcategory_display_order , mi2.recommendation_sales_price , mi2.quantity_cost_price , mvn1.vendor_code , mvn1.vendor_name FROM ( SELECT mi1.pattern_type , mi1.pattern_code , mi1.item_code , mi1.information_category_code , mi1.subcategory_code , mi1.pma_code , mi1.recommendation_sales_price , mi1.quantity_cost_price , mi1.vendor_code FROM m_item_0226_001 mi1 WHERE item_code IN (‘01’) AND mi1.apply_start_date <= Cast(‘20240220’ as date) AND Cast(‘20240220’ as date) <= mi1.apply_end_date ) mi2 , m_information_category_0226_001 mic1 , m_subcategory_0226_001 AS ms1 , m_pattern_0105_001 AS mpt1 , m_pma_0226_001 mp1 , m_vendor_name_0226_001 mvn1 WHERE mpt1.original_store_code = ‘1234567890’ AND mi2.pattern_type = mpt1.pattern_type AND mi2.pattern_code = mpt1.pattern_code AND mpt1.apply_start_date <= Cast(‘20240220’ as date) AND Cast(‘20240220’ as date) <= mpt1.apply_end_date AND mi2.information_category_code = mic1.information_category_code AND mic1.apply_start_date <= Cast(‘20240220’ as date) AND Cast(‘20240220’ as date) <= mic1.apply_end_date AND mi2.information_category_code = ms1.information_category_code AND mi2.subcategory_code = ms1.subcategory_code AND ms1.apply_start_date <= Cast(‘20240220’ as date) AND Cast(‘20240220’ as date) <= ms1.apply_end_date AND mi2.pma_code = mp1.pma_code AND mp1.apply_start_date <= Cast(‘20240220’ as date) AND Cast(‘20240220’ as date) <= mp1.apply_end_date AND mi2.vendor_code = mvn1.vendor_code order by mi2.item_code 他两是等价的吗
08-13
<think>我们有两个SQL查询,修正前和修正后。我们需要判断它们是否等价。 修正前的查询在子查询中使用了DISTINCT,而修正后的查询在外部查询中使用了DISTINCT,同时子查询中去掉了DISTINCT。 修正前: 子查询:SELECT DISTINCT ... FROM m_item_0226_001 ... 然后与其他表连接,最后没有使用DISTINCT(但子查询已经去重) 修正后: 子查询:SELECT ... FROM m_item_0226_001 ... (没有DISTINCT) 然后与其他表连接,最后在外部查询使用SELECT DISTINCT ... 我们需要考虑:在连接操作后,两种方式是否会产生相同的结果? 分析: 1. 修正前的查询:在子查询中先对m_item_0226_001表进行去重(根据子查询中选出的所有列),然后再与其他表连接。这样,在连接时,由于子查询已经去重,所以每个item_code在子查询中只会出现一次(除非有重复的列值,但DISTINCT已经去重了)。然后连接其他表,如果其他表有多个匹配行,则仍然会产生多行。最后的结果集没有再次去重,所以如果连接后有多行,就会显示多行。 2. 修正后的查询:子查询没有去重,所以如果m_item_0226_001表中有重复的行(根据子查询中选出的列),那么子查询会返回多行。然后与其他表连接,连接后可能会产生更多的行。最后在外部查询使用DISTINCT,会对最终结果的所有列进行去重。 因此,这两个查询不一定等价。原因如下: - 如果子查询中的行在去重后数量不同(即原表中有重复行),那么连接前的数据集行数就不同。 - 此外,在连接过程中,如果子查询返回多行(修正后)与连接表匹配,可能会产生比修正前更多的行,然后通过外部DISTINCT去重。而修正前在连接前已经去重,所以连接时行数较少,但连接后如果其他表有多行匹配,也会多行,最后没有去重。 但是,我们注意到在修正前的子查询中,DISTINCT是基于多个列的,包括pattern_type, pattern_code, item_code, information_category_code, subcategory_code, pma_code, recommendation_sales_price, quantity_cost_price, vendor_code。如果这些列的组合有重复,那么DISTINCT会去掉重复行。 修正后的查询没有在子查询中去重,而是在最终结果上对所有的列(包括连接后的其他表的列)进行去重。 因此,这两个查询的结果可能不同,因为: - 修正前:在连接前对子查询表去重,然后连接,最后结果不去重(可能有多行,因为连接导致)。 - 修正后:子查询不去重(可能多行),然后连接(可能更多行),最后对整个结果集去重。 但是,如果满足以下条件,它们可能是等价的: - 条件1:子查询中的表(m_item_0226_001)在子查询选出的列上具有唯一性(即没有重复行),那么子查询加不加DISTINCT结果行数一样。 - 条件2:连接操作是一对一的,即其他每个表(m_pattern_0105_001, m_information_category_0226_001, m_subcategory_0226_001, m_pma_0226_001, m_vendor_name_0226_001)与子查询结果连接时,每个子查询的行只匹配到这些表中的一行。这样,连接不会产生重复行。 如果同时满足条件1和条件2,那么两个查询的结果行数相同,且内容相同(因为即使修正前子查询去重,但实际无重复;修正后连接后没有产生重复行,所以外部DISTINCT也不会改变结果)。但是,如果条件1不满足(即子查询有重复行),那么修正前的子查询会去掉重复行,而修正后的子查询会保留重复行,然后连接,最后外部DISTINCT再去重。此时,如果重复行在连接后仍然重复(即连接的其他列值也相同),那么修正后外部DISTINCT会去掉这些重复行,最终结果可能与修正前相同(因为修正前去掉了重复行,连接后没有重复行);但如果连接后重复行变成了不重复(比如其他表连接时匹配到不同的行),那么修正后会产生多行,然后外部DISTINCT根据所有列去重,可能仍然会保留这些行(如果这些行在最终列上不完全相同),这样结果就会不同。 因此,在一般情况下,这两个查询不等价。但是,如果数据满足上述两个条件,则结果相同。 然而,我们还需要注意,修正前在子查询中使用了DISTINCT,修正后在外部使用DISTINCT,它们去重的范围不同: - 修正前:只对子查询的列去重(即m_item_0226_001表选出的列) - 修正后:对最终结果的所有列(包括其他表的列)去重 所以,即使子查询有重复行,但如果在与其他表连接后,由于其他表的列值不同,导致最终行并不重复,那么修正后的DISTINCT不会去掉这些行,而修正前由于在子查询中已经去重,所以连接后不会出现重复行(但可能因为其他表的多行匹配而出现多行,这些多行在最终列上可能不重复)。因此,修正后的DISTINCT可能会去掉一些修正前没有的行(如果修正后连接后出现重复的最终行),但同时也可能保留一些修正前没有的行(如果修正前因为去重而少了一些行,而这些行在连接后产生了不同的最终行)。 结论:不等价。 但是,我们也可以从另一个角度考虑:修正后的查询是否能够替代修正前的查询?这取决于业务需求。如果业务需要的是根据所有最终列去重,那么修正后的写法是合理的。而修正前的写法是保证子查询中的行不重复,然后连接,但最终结果可能重复(如果连接导致重复)也可能不重复。 具体到这个查询,我们注意到在修正前的子查询中,DISTINCT所基于的列包括多个,这些列在连接时作为连接键的有一部分(如pattern_type, pattern_code, information_category_code, subcategory_code, pma_code, vendor_code),但也包括非连接键(如recommendation_sales_price, quantity_cost_price)。如果这些非连接键的值不同,那么DISTINCT会保留这些不同的行,这样在连接时就会多行。而修正后的查询在外部去重,则不会考虑这些中间步骤的重复,只关心最终结果。 因此,从逻辑上,这两个查询的结果可能不同。 但是,我们还需要注意,在修正前的查询中,子查询的DISTINCT可能是不必要的,因为如果m_item_0226_001表在item_code和日期范围内本身就没有重复(比如有唯一约束),那么DISTINCT就没有效果。同样,修正后的外部DISTINCT也可能是不必要的,如果连接后不会产生重复行。 所以,要判断等价性,需要知道表的数据和约束。在不知道数据和约束的情况下,我们不能说它们等价。 不过,我们可以通过一个简单的例子说明可能的不同: 假设m_item_0226_001表中有两行相同的记录(在子查询选出的所有列上相同),那么: - 修正前:子查询DISTINCT会去掉一行,只剩下一行。 - 修正后:子查询返回两行,然后与其他表连接。如果其他表与这一行连接后,每一行都得到相同的连接结果(因为其他表通过等值连接,且连接键相同,所以匹配到的行也相同),那么连接后会有两行完全相同的记录,然后外部DISTINCT会去掉重复,只剩下一行。此时结果相同。 但是,如果其他表连接时,对于这两行相同的子查询行,分别匹配到了不同的行(这可能吗?注意连接条件中,除了m_pattern_0105_001表用到了pattern_type和pattern_code,其他表都是通过information_category_code, subcategory_code, pma_code, vendor_code连接。如果这两行相同的子查询行,它们的pattern_type和pattern_code也相同,那么连接m_pattern_0105_001表时,会匹配到相同的行(因为m_pattern_0105_001表通过pattern_type, pattern_code和日期条件过滤,并且原始商店代码固定),所以连接后,这两行会变成相同的行(因为其他表连接键相同,匹配到的行也相同)。因此,最终这两行会变成重复行,然后被外部DISTINCT去掉。 所以,在这种情况下,结果相同。 但是,如果两行相同的子查询行,它们的pattern_type和pattern_code不同,那么连接m_pattern_0105_001表时,可能匹配到不同的行(如果m_pattern_0105_001表中有不同的行具有这两个不同的pattern_type和pattern_code)。这样,连接后的两行就会不同(因为m_pattern_0105_001表的行不同),所以外部DISTINCT不会去掉。而修正前,因为子查询去重,只剩下一行(假设我们保留其中一行),那么连接时只连接一次,得到一行。这样,修正后的查询就会多出一行(两行不同的结果),而修正前只有一行。 因此,在这种情况下,结果不同。 所以,结论是:不等价。 但是,我们注意到,在子查询中,我们是通过item_code IN ('01')和日期范围来选择的,而且item_code是特定的。如果对于同一个item_code,在同一个日期范围内,出现了两行具有相同的pattern_type, pattern_code, ... 等所有列,那么这两行在子查询中就是重复的。这种情况在规范化的数据库中应该不会出现(通常一个商品在同一时间段内应该有唯一的属性)。如果数据库设计有唯一约束,则不会重复。 因此,在业务数据符合唯一性的情况下,两个查询可能是等价的。但如果没有唯一性约束,则可能不等价。 所以,严格来说,两个查询不等价,但如果在子查询中选出的列上,m_item_0226_001表在指定日期范围内对于同一个item_code没有重复行,那么它们等价。 但是,我们还要注意,修正后的查询在外部使用DISTINCT,可能会比修正前更慢,因为DISTINCT操作的数据量更大(连接后可能有更多行)。而修正前的DISTINCT在子查询中,数据量小。 因此,建议根据业务需求和数据情况选择合适的写法。 如果目的是确保最终结果去重,那么修正后的写法更安全,因为它确保最终结果无重复。而修正前的写法只能保证中间步骤去重,但连接后仍可能重复(尽管在这个例子中,由于连接键是唯一的,可能不会重复,但不确定)。 但是,我们注意到修正前的查询没有在外部使用DISTINCT,而修正后使用了。所以如果修正前连接后产生了重复行,那么修正前的结果就会有重复行,而修正后会去重。所以修正后的查询更严格。 因此,如果业务要求最终结果不能重复(即所有列都相同的行要去重),那么修正后的查询更符合要求。 综上所述,两个查询不等价,修正后的查询在最终结果上进行了去重,而修正前的查询只在子查询去重,连接后不去重。 但是,我们还需要考虑连接条件是否会导致重复行。如果连接条件都是一对一的,那么修正前的查询结果也不会重复,此时两个查询结果相同。但如果不确定,则修正后的查询更安全。 所以,如果修正前的查询在连接后不会产生重复行,那么两个查询等价;否则,不等价。 如何确保连接后不会产生重复行?需要检查每个连接表: - m_pattern_0105_001:通过pattern_type, pattern_code和日期范围连接,并且还有original_store_code='1234567890'。如果这个组合是唯一的,那么一个子查询行只会匹配一行。 - 其他表(mic1, ms1, mp1, mvn1)都是通过代码连接,并且有日期范围。如果这些代码在各自的表中是主键(或唯一键),那么连接就是一对一的。 因此,如果这些表的设计上,连接键都是唯一的(在日期范围内),那么连接后不会产生重复行。这样,修正前的查询结果就不会重复。而修正后的查询由于外部DISTINCT,也会得到同样的行(因为原本就不重复,所以DISTINCT不会去掉任何行)。同时,修正前的子查询DISTINCT如果去掉了重复行,那么连接后也不会重复(因为连接是一对一的)。所以,在满足唯一性的前提下,两个查询等价。 但是,如果子查询中有重复行,而连接键在m_pattern_0105_001表中不是唯一的(即同一个pattern_type, pattern_code在日期范围内有多行),那么连接后就会多行,修正前的结果就会多行(重复行?注意,子查询去重后,每个子查询行只出现一次,但连接后可能因为m_pattern_0105_001表有多行匹配而出现多行)。这些多行在最终列上可能不同(比如m_pattern_0105_001表中有不同的行),那么就不是重复行。而修正后的查询由于在外部去重,只会去掉所有列完全相同的行。 所以,即使连接表有唯一性,如果子查询有重复行(在子查询列上重复),那么修正前的子查询会去掉重复行,而修正后不会(但连接后可能因为连接表匹配而不同,所以最终行可能不重复,因此外部DISTINCT不会去掉)。这样,修正后可能行数更多(因为保留了重复行,然后连接后变成了不同的行)。 因此,在子查询有重复行的情况下,即使连接表有唯一性,两个查询也可能不同。 所以,最保险的结论是:不等价。 但具体是否等价,需要根据实际数据来判断。 所以,回答:不一定等价,取决于数据。 如果希望等价,可以同时满足以下两个条件: 1. 子查询中的表(m_item_0226_001)在子查询选出的列上,对于条件(item_code IN ('01')和日期范围)没有重复行。 2. 连接操作是一对一的(即每个连接表在连接键和日期范围内有唯一行)。 在满足这两个条件时,等价。 否则,不等价。 因此,不能保证等价。 建议:如果业务逻辑允许,并且希望结果去重,那么使用修正后的写法(外部DISTINCT)更安全。如果业务逻辑要求保留所有连接产生的行(即使重复),那么修正前的写法可能更合适(但修正前在子查询去重,可能已经去掉了一些行)。 由于问题只问是否等价,答案是不等价(在一般情况下)。</think>### 分析:两个SQL是否等价? 这两个SQL查询的核心差异在于 **`DISTINCT` 的位置**: 1. **修正前**:在子查询中使用 `SELECT DISTINCT`,对中间结果去重后再连接其他表。 2. **修正后**:在外部查询使用 `SELECT DISTINCT`,先连接所有表再对最终结果去重。 #### 关键结论:**不等价** 原因: 1. **去重范围不同**: - 修正前:仅对子查询中的 `m_item_0226_001` 表去重(基于 `pattern_type, item_code` 等列)。 - 修正后:对连接后的所有表结果去重(基于 `item_code, pma_name, vendor_name` 等最终列)。 2. **连接后可能产生重复行**: - 如果其他表(如 `m_pattern_0105_001`, `m_subcategory_0226_001`)存在多行匹配,连接后会产生重复行。 - 修正前因子查询已去重,可能减少重复风险。 - 修正后依赖外部 `DISTINCT` 消除重复,但可能因连接后列值不同而保留多行。 3. **性能差异**: - 修正前:子查询去重减少数据量后再连接,效率较高。 - 修正后:先连接大表再整体去重,可能更慢。 --- ### 示例验证 假设 `m_item_0226_001` 表有重复数据: ```sql -- 子查询数据 (存在重复) pattern_type | item_code | ... -------------------------------- A | 01 | ... A | 01 | ... -- 重复行 ``` - **修正前结果**: - 子查询 `DISTINCT` 去重 → 仅1行参与连接 → 最终输出1行。 - **修正后结果**: - 子查询返回2行 → 连接其他表后可能输出2行 → 外部 `DISTINCT` 若列值相同则去重为1行;**若连接后列值不同则保留多行**。 --- ### 建议 1. **明确业务需求**: - 若需确保每个 `item_code` 只返回一行,优先使用 **修正前(子查询去重)**。 - 若需保留所有关联表的完整组合,使用 **修正后(最终结果去重)**。 2. **优化方向**: ```sql -- 更清晰的写法(结合两者优点) WITH mi2 AS ( SELECT DISTINCT -- 子查询去重 pattern_type, pattern_code, item_code, ... FROM m_item_0226_001 WHERE ... ) SELECT DISTINCT -- 最终去重(可选) mi2.item_code, mp1.pma_name, ... FROM mi2 JOIN m_pattern_0105_001 mpt1 ON ... JOIN m_pma_0226_001 mp1 ON ... ... ORDER BY mi2.item_code; ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值