Oracle Gotchas для опытного новичка - PullRequest
12 голосов
/ 31 июля 2009

Какие Oracle есть у кого-то, кто не знаком с платформой, но не знаком с реляционными базами данных (MySQL, MS SQL Server, Postgres и т. Д.) В целом.

Два примера того, что я ищу

  1. Многие продукты для реляционных баз данных создают ключ auto_increment для вас. Oracle не делает, вы должны вручную создать последовательность, а затем создать триггер

  2. При вставке данных через интерфейс SQL Developer необходимо вручную зафиксировать данные

Бонусные баллы за связанные с PHP ошибки, так как это платформа Я будет использовать этот гипотетический опытный новичок.

Ответы [ 8 ]

23 голосов
/ 31 июля 2009

Примечание: я объясняю здесь только ошибки, т.е. е. ситуации, когда Oracle ведет себя не так, как другие системы. Oracle имеет многочисленные преимущества перед другими RDBMS, но они не являются темой поста.

  • Вы не можете SELECT без FROM.

    SELECT  1
    

    не удастся, вам нужно:

    SELECT  1
    FROM    dual
    
  • Пустая строка и NULL - это одно и то же.

    SELECT  *
    FROM    dual
    WHERE   '' = ''
    

    ничего не возвращает.

  • Нет ни TOP, ни LIMIT. Вы ограничиваете свои результаты в предложении WHERE:

    SELECT  *
    FROM    (
            SELECT  *
            FROM    mytable
            ORDER BY
                    col
            )
    WHERE   rownum < 10
    

    именно так, используя подзапрос, так как ROWNUM оценивается до ORDER BY.

  • Вы не можете вкладывать коррелированные подзапросы глубиной более одного уровня. Этот не удастся:

    SELECT  (
            SELECT  *
            FROM    (
                    SELECT  dummy
                    FROM    dual di
                    WHERE   di.dummy = do.dummy
                    ORDER BY
                            dummy
                    )
            WHERE   rownum = 1
            )
    FROM    dual do
    

    Это проблема.

  • NULL значения не индексируются. Этот запрос не будет использовать индекс для заказа:

    SELECT  *
    FROM    (
            SELECT  *
            FROM    mytable
            ORDER BY
                    col
            )
    WHERE   rownum < 10
    

    , если col не помечен как NOT NULL.

    Обратите внимание, что это NULL значения , которые не проиндексированы, а не столбцы . Вы можете создать индекс для пустого столбца, и в индекс попадут не NULL значения.

    Однако индекс не будет использоваться, если условие запроса предполагает, что NULL значения могут его удовлетворить.

    В приведенном выше примере вы хотите, чтобы все значения были возвращены (включая NULL s). Тогда индекс не знает о не NULL значениях, следовательно, не может их получить.

    SELECT  *
    FROM    (
            SELECT  *
            FROM    mytable
            ORDER BY
                    col
            )
    WHERE   rownum < 10
    

    Но этот запрос будет использовать индекс:

    SELECT  *
    FROM    (
            SELECT  *
            FROM    mytable
            WHERE   col IS NOT NULL
            ORDER BY
                    col
            )
    WHERE   rownum < 10
    

    , поскольку не NULL значения не могут когда-либо удовлетворять условию.

  • По умолчанию NULL s сортируются последними, а не первыми (как в PostgreSQL, но в отличие от MySQL и SQL Server)

    Этот запрос:

    SELECT  *
    FROM    (
            SELECT  1 AS id
            FROM    dual
            UNION ALL
            SELECT  NULL AS id
            FROM    dual
            ) q
    ORDER BY
            id
    

    вернет

    id
    ---
    1
    NULL
    

    Для сортировки как в SQL Server и MySQL используйте это:

    SELECT  *
    FROM    (
            SELECT  1 AS id
            FROM    dual
            UNION ALL
            SELECT  NULL AS id
            FROM    dual
            ) q
    ORDER BY
            id NULLS FIRST
    

    Обратите внимание, что он нарушает порядок rownum, если последний не используется из подзапроса (как описано выше)

  • "MYTABLE" и "mytable" (двойные кавычки имеют значение) - это разные объекты.

    SELECT  *
    FROM    mytable -- wihout quotes
    

    выберет первое, а не второе. Если первое не существует, запрос не будет выполнен.

    CREATE TABLE mytable
    

    создает "MYTABLE", а не "mytable".

  • В Oracle все неявные блокировки (которые являются результатом операций DML) являются уровнями строки и никогда не увеличиваются. То есть строка, не затронутая транзакцией, не может быть неявно заблокирована.

    Писатели никогда не блокируют читателей (и наоборот).

    Чтобы заблокировать всю таблицу, вы должны выполнить явный оператор LOCK TABLE.

    Блокировки строк хранятся на страницах данных.

  • В Oracle нет "CLUSTERED indexes", есть "таблицы, организованные по индексам". По умолчанию таблицы организованы в кучу (в отличие от SQL Server и MySQL с InnoDB).

    В мире Oracle «кластеризованное хранилище» означает организацию нескольких таблиц таким образом, чтобы строки, имеющие общий ключ (из нескольких таблиц), также имели общую страницу данных.

    Одна страница данных содержит несколько строк из нескольких таблиц, что делает соединения по этому ключу очень быстрыми.

4 голосов
/ 31 июля 2009

SELECT 1 не будет работать, вместо этого выберите 1 из двойного.

Если вы работаете с иерархическими данными, подключение с помощью отлично.

2 голосов
/ 31 июля 2009

Один комментарий: вам не нужно создавать триггер для использования последовательностей, если только вы не непреклонны в отношении репликации поведения столбца IDENTITY Sybase / SQL Server. Я считаю более полезным просто использовать последовательность непосредственно в фактических операторах вставки, например,

INSERT
  INTO MyTable
     ( KeyCol
     , Name
     , Value
     )
SELECT Seq_MyTable.NextVal
     , 'some name'
     , 123
  FROM dual;

Вам не нужно беспокоиться о накладных расходах при выполнении триггера, и вы можете гибко вставлять строки в таблицу, не беспокоясь о назначении значений последовательности (например, при перемещении данных из схемы в другую) , Вы также можете предварительно выбрать значения из последовательности для вставки диапазонов данных и других методов, которые функция IDENTITY либо затрудняет, либо делает невозможными.

1 голос
/ 31 июля 2009

Временные таблицы

Вы создаете и индексируете их как обычные таблицы, но каждая сессия / транзакция видит только свои собственные данные. Это отличается от MS SQL.

Глобальные переменные

Они передаются по ссылке. Это означает, что если вы передадите глобальную переменную в процедуру в качестве параметра и измените глобальную переменную внутри вашей процедуры, значение параметра также изменится. Хотя не очень популярный метод.

Триггеры

До самых последних версий не было никакого способа определить способ, которым сработают подобные триггеры. Если вам действительно важно, какое «ПЕРЕД ОБНОВЛЕНИЕМ ДЛЯ КАЖДОГО РЯДА» было первым, вы можете поместить все это в один триггер.

1 голос
/ 31 июля 2009
1 голос
/ 31 июля 2009

Нет групповой конкатенации, как в MySQL. Если вам нужна агрегатная функция групповой конкатенации, вы должны написать свою собственную. Вот моя реализация:

drop type T_GROUP_CONCAT;

create or replace type GROUP_CONCAT_PARAM as object
(
  val varchar2(255),
  separator varchar2(10),
  numToConcat NUMBER,
  MAP MEMBER FUNCTION GROUP_CONCAT_PARAM_ToInt  return VARCHAR2
);

--map function needed for disctinct in select clauses
CREATE OR REPLACE TYPE BODY GROUP_CONCAT_PARAM IS
    MAP MEMBER FUNCTION GROUP_CONCAT_PARAM_ToInt return VARCHAR2 is 
      begin 
        return val; 
      end; 

end;


/

CREATE OR REPLACE TYPE T_GROUP_CONCAT 
AS OBJECT (

runningConcat VARCHAR2(5000),
runningCount NUMBER,

STATIC FUNCTION ODCIAggregateInitialize
  ( actx IN OUT T_GROUP_CONCAT
  ) RETURN NUMBER,

MEMBER FUNCTION ODCIAggregateIterate
  ( self  IN OUT T_GROUP_CONCAT,
    val   IN       GROUP_CONCAT_PARAM
  ) RETURN NUMBER,

MEMBER FUNCTION ODCIAggregateTerminate
  ( self             IN   T_GROUP_CONCAT,
    returnValue  OUT VARCHAR2,
    flags           IN   NUMBER
  ) RETURN NUMBER,

MEMBER FUNCTION ODCIAggregateMerge
  (self  IN OUT T_GROUP_CONCAT,
   ctx2 IN      T_GROUP_CONCAT
  ) RETURN NUMBER

);
/

CREATE OR REPLACE TYPE BODY T_GROUP_CONCAT AS

STATIC FUNCTION ODCIAggregateInitialize
  ( actx IN OUT T_GROUP_CONCAT
  ) RETURN NUMBER IS 
  BEGIN
    IF actx IS NULL THEN
      actx := T_GROUP_CONCAT ('', 0);
    ELSE
      actx.runningConcat := '';
      actx.runningCount := 0;
    END IF;
    RETURN ODCIConst.Success;
  END;

MEMBER FUNCTION ODCIAggregateIterate
  ( self  IN OUT T_GROUP_CONCAT,
    val   IN     GROUP_CONCAT_PARAM
  ) RETURN NUMBER IS
  BEGIN
    if self.runningCount = 0 then
        self.runningConcat := val.val;
    elsif self.runningCount < val.numToConcat then
        self.runningConcat := self.runningConcat || val.separator || val.val;
    end if;
    self.runningCount := self.runningCount + 1;
    RETURN ODCIConst.Success;
  END;

MEMBER FUNCTION ODCIAggregateTerminate
  ( self        IN  T_GROUP_CONCAT,
    ReturnValue OUT VARCHAR2,
    flags       IN  NUMBER
  ) RETURN NUMBER IS
  BEGIN
    returnValue := self.runningConcat;
    RETURN ODCIConst.Success;
  END;

MEMBER FUNCTION ODCIAggregateMerge
  (self IN OUT T_GROUP_CONCAT,
   ctx2 IN     T_GROUP_CONCAT
  ) RETURN NUMBER IS
  BEGIN
    self.runningConcat := self.runningConcat || ',' || ctx2.runningConcat;
    self.runningCount := self.runningCount + ctx2.runningCount;
    RETURN ODCIConst.Success;
  END;

END;
/

CREATE OR REPLACE FUNCTION GROUP_CONCAT
( x GROUP_CONCAT_PARAM
) RETURN VARCHAR2
--PARALLEL_ENABLE
AGGREGATE USING T_GROUP_CONCAT;
/

Чтобы использовать это:

select GROUP_CONCAT(GROUP_CONCAT_PARAM(tbl.someColumn, '|', 2)) from someTable tbl
1 голос
/ 31 июля 2009

Не забудьте использовать nvl (столбец) вокруг любого столбца в наборе строк, который может быть полностью заполнен нулевыми значениями. В противном случае столбец будет отсутствовать в наборе строк.

Правильно, полностью отсутствует!

Пример:

SELECT nvl(employeeName,'Archie'), nvl(employeeSpouse,'Edith') FROM Employee

Это гарантирует, что вы получите два столбца в вашем наборе строк, даже если все значения в обоих равны нулю. Вы просто увидите кучу значений «Арчи» и «Эдит». Если вы не используете nvl (), вы можете получить только один столбец или ни один обратно. Суть в том, что ваш код может нормально работать в вашей среде разработки и даже проходить QA, но когда он дойдет до производства, значения в таблице могут изменить структуру результатов!

Итак, короче говоря, всякий раз, когда вы выбираете столбец с нулем, обязательно используйте nvl ().

1 голос
/ 31 июля 2009

Кажется, я столкнулся с большим количеством баз данных Oracle, чувствительных к регистру объектов и данных схемы, чем в SQL Server .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...