public function insertOrUpdate($strTable, $mixColumnsAndValuesArray, $strPKNames = null)
    {
        $strEscapedArray = $this->escapeIdentifiersAndValues($mixColumnsAndValuesArray);
        $strColumns = array_keys($strEscapedArray);
        $strUpdateStatement = '';
        foreach ($strEscapedArray as $strColumn => $strValue) {
            if ($strUpdateStatement) {
                $strUpdateStatement .= ', ';
            }
            $strUpdateStatement .= $strColumn . ' = ' . $strValue;
        }
        if (is_null($strPKNames)) {
            $strMatchCondition = 'target_.' . $strColumns[0] . ' = source_.' . $strColumns[0];
        } else {
            if (is_array($strPKNames)) {
                $strMatchCondition = '';
                foreach ($strPKNames as $strPKName) {
                    if ($strMatchCondition) {
                        $strMatchCondition .= ' AND ';
                    }
                    $strMatchCondition .= 'target_.' . $this->escapeIdentifier($strPKName) . ' = source_.' . $this->escapeIdentifier($strPKName);
                }
            } else {
                $strMatchCondition = 'target_.' . $this->escapeIdentifier($strPKNames) . ' = source_.' . $this->escapeIdentifier($strPKNames);
            }
        }
        $strTable = $this->EscapeIdentifierBegin . $strTable . $this->EscapeIdentifierEnd;
        $strSql = sprintf('MERGE INTO %s AS target_ USING %s AS source_ ON %s WHEN MATCHED THEN UPDATE SET %s WHEN NOT MATCHED THEN INSERT (%s) VALUES (%s)',
            $strTable, $strTable,
            $strMatchCondition, $strUpdateStatement,
            implode(', ', $strColumns),
            implode(', ', array_values($strEscapedArray))
        );
        $this->executeNonQuery($strSql);
    }