Php 甲骨文找到了一个有经验的新手

Php 甲骨文找到了一个有经验的新手,php,mysql,sql-server,oracle,postgresql,Php,Mysql,Sql Server,Oracle,Postgresql,对于刚接触该平台但对关系数据库(MySQL、MS SQL Server、Postgres等)并不陌生的人来说,Oracle有哪些普遍的收获 我正在寻找的这类东西的两个例子 许多关系数据库产品处理为您创建自动增量键的过程。Oracle没有,您必须手动创建序列,然后创建触发器 通过SQL Developer接口插入数据时,必须手动提交数据 PHP相关gotchas的额外积分,因为这是我将这个假设的有经验的新手将使用的平台 注意:我在这里只解释了哥特加,I。EOracle行为与其他系统不同的情况Ora

对于刚接触该平台但对关系数据库(MySQL、MS SQL Server、Postgres等)并不陌生的人来说,Oracle有哪些普遍的收获

我正在寻找的这类东西的两个例子

  • 许多关系数据库产品处理为您创建自动增量键的过程。Oracle没有,您必须手动创建序列,然后创建触发器

  • 通过SQL Developer接口插入数据时,必须手动提交数据

  • PHP相关gotchas的额外积分,因为这是我将这个假设的有经验的新手将使用的平台

    注意:我在这里只解释了哥特加,I。E
    Oracle
    行为与其他系统不同的情况
    Oracle
    比其他
    RDBMS
    有许多好处,但它们不是本文的主题。
    • 如果没有中的,则无法选择

      SELECT  1
      
      如果失败,您需要:

      SELECT  1
      FROM    dual
      
    • 空字符串和
      NULL
      是一回事

      SELECT  *
      FROM    dual
      WHERE   '' = ''
      
      不返回任何内容

    • 既没有
      顶部
      也没有
      限制
      。您可以在
      WHERE
      子句中限制结果:

      SELECT  *
      FROM    (
              SELECT  *
              FROM    mytable
              ORDER BY
                      col
              )
      WHERE   rownum < 10
      
      这是一个问题

    • 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
      
      会回来的

      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
      操作产生)都是行级别的,永远不会升级。也就是说,不能隐式锁定不受事务影响的行

      作者从不阻止读者(反之亦然)

      要锁定整个表,应该发出显式的
      locktable
      语句

      行锁存储在数据页上

    • Oracle
      中,没有“
      聚集的
      索引”,而是“索引组织的表”。默认情况下,表是堆组织的(与
      sqlserver
      MySQL
      以及
      InnoDB
      不同)

      在Oracleworld中,“集群存储”意味着组织多个表,以便共享公共键(来自多个表)的行也共享一个数据页

      一个数据页承载来自多个表的多行,这使得这个键上的连接超快速


    选择1不起作用,请改为从dual中选择1


    如果您使用分层数据,则“连接方式”非常好。

    与SQL Server相比,我似乎遇到了更多对架构对象和数据区分大小写的Oracle数据库。

    不要忘记在行集中可能完全填充空值的任何列周围使用nvl(列)。否则,该列将从行集中丢失

    没错,完全失踪了

    例如:

    SELECT nvl(employeeName,'Archie'), nvl(employeeSpouse,'Edith') FROM Employee
    
    这将保证在行集中有两列,即使这两列中的所有值都为null。你会看到一堆“阿尔奇”和“伊迪丝”的值。如果不使用nvl(),则可能只返回一列或两列都不返回。问题的关键在于,代码可以在开发环境中正常运行,甚至可以通过QA,但当它进入生产环境时,表中的值可能会改变结果的结构


    因此,简而言之,无论何时选择可为空的列,请确保使用nvl()。

    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;
    /
    

    我在这里写了一些不同之处:

    一条评论:使用序列不必创建触发器,除非您坚持复制Sybase/SQL Server IDENTITY列的行为。我发现直接在实际的insert语句中使用序列更有用,例如

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

    您不需要担心触发器执行的开销,并且可以灵活地处理向表中插入行的问题,而不必担心被分配的序列值(例如在将数据从模式移动到另一个模式时)。您还可以从序列中预先选择值,以插入数据范围,以及标识功能使其难以或不可能使用的其他技术。

    临时表

    您可以像创建普通表一样创建和索引它们,但每个会话/事务只能看到自己的数据。这与MS SQL不同

    全局变量

    它们是通过引用传递的。这意味着,如果将全局变量作为参数传递给过程,并在过程中修改全局变量,则参数值也将更改。不过,这不是一种非常流行的方法

    触发器


    直到最近的版本,还没有办法确定类似触发器的触发方式。如果你真的关心“每行更新前”是第一个,你就把它放在一个触发器中。

    你不需要触发器来更新序列-你使用sequence.nextvalgod信息,可能值得一个实际的答案(与注释相反),但它确实会导致可移植性较差的SQL,这会导致一些人(对或错)改为使用触发器。另外,第2点是一个可以在SQL Developer中打开的首选项(工具->首选项->数据库->工作表参数->SQL工作表中的自动提交)。谢谢你的提示steve。你需要解释一下。AFAIK select“”在DUAL中为NULL,将为false@
    SELECT nvl(employeeName,'Archie'), nvl(employeeSpouse,'Edith') FROM Employee
    
    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
    
    INSERT
      INTO MyTable
         ( KeyCol
         , Name
         , Value
         )
    SELECT Seq_MyTable.NextVal
         , 'some name'
         , 123
      FROM dual;