在开始介绍之前,先给出文章里用到的所有PL/SQL代码:

(类型定义)

CREATE OR REPLACE TYPE T_Nested_Tab_Str IS TABLE OF VARCHAR2(25);
--
CREATE OR REPLACE TYPE T_Object IS OBJECT
(
 employee_id number(6),
 last_name varchar2(25)
);
--
CREATE OR REPLACE TYPE T_VARRAY_STR IS VARRAY(10) OF VARCHAR2(25);
--
CREATE OR REPLACE TYPE T_Nested_Tab_Obj IS TABLE OF T_Object;

(包的声明)

CREATE OR REPLACE PACKAGE pkg_odp_dotnet IS
 TYPE T_Ref_Cursor IS REF CURSOR;
 TYPE T_Asso_Array_Num IS TABLE OF employees_bk.employee_id%TYPE INDEX BY PLS_INTEGER;
 TYPE T_Asso_Array_Str IS TABLE OF employees_bk.last_name%TYPE INDEX BY PLS_INTEGER; 
 --
 PROCEDURE proc_ref_cursor(p_ref_cursor OUT T_Ref_Cursor);
 PROCEDURE proc_sys_refcursor(p_sys_refcursor OUT SYS_REFCURSOR);
 --
 PROCEDURE proc_asso_array_num_in(p_asso_array_num    IN T_Asso_Array_Num);
 PROCEDURE proc_asso_array_num_out(p_asso_array_num OUT T_Asso_Array_Num);
 PROCEDURE proc_asso_array_str_out(p_asso_array_str OUT T_Asso_Array_Str);
 --
 PROCEDURE proc_nested_tab_str_in(p_nested_tab_str IN T_Nested_Tab_Str);
 PROCEDURE proc_nested_tab_str_out(p_nested_tab_str OUT T_Nested_Tab_Str);
 --
 PROCEDURE proc_obj_in(p_obj IN T_Object);
 --
 PROCEDURE proc_nested_tab_obj_in(p_nested_tab_obj IN T_Nested_Tab_Obj);
 --
 PROCEDURE proc_varray_str_in(p_varray_str IN T_Varray_Str);
END;

(包体)

CREATE OR REPLACE PACKAGE BODY pkg_odp_dotnet IS
 /*This proc is invoked by .NET to test the ref cursor
    Retrieve the employees whose id less than 105*/
 PROCEDURE proc_ref_cursor(p_ref_cursor OUT T_Ref_Cursor)
 IS
 BEGIN
    OPEN p_ref_cursor FOR
    SELECT employee_id,first_name,last_name FROM employees_bk WHERE employee_id<105;
 END;
 
 ---------------------------------------------------------------------------------------------------------------------------------
 /*This proc is invoked by .NET to test the pre-defined sys_refcursor
    Retrieve the employees whose id less than 105*/
 PROCEDURE proc_sys_refcursor(p_sys_refcursor OUT SYS_REFCURSOR)
 IS
 BEGIN
    OPEN p_sys_refcursor FOR
    SELECT employee_id,first_name,last_name FROM employees_bk WHERE employee_id<105;
 END;
 
 ---------------------------------------------------------------------------------------------------------------------------------
 /*This proc is invoked by .NET to test the input parameter with the type of associative array, 
    and the type of the collection element is number
    Loop through each employee id in the given associative array, then update its salary*/
 PROCEDURE proc_asso_array_num_in(p_asso_array_num    IN T_Asso_Array_Num)
 IS
    idx PLS_INTEGER;
 BEGIN
    idx:=p_asso_array_num.FIRST;
    WHILE(idx IS NOT NULL) LOOP
      UPDATE employees_bk SET salary=salary+1 WHERE employee_id=p_asso_array_num(idx);
      idx:=p_asso_array_num.NEXT(idx);
    END LOOP;
    COMMIT;
 END;
 
 ---------------------------------------------------------------------------------------------------------------------------------
 /*This proc is invoked by .NET to test the output parameter with the type of associative array, 
    and the type of the collection element is varchar2
    Retrieve the employees whose id less than 105*/
 PROCEDURE proc_asso_array_str_out(p_asso_array_str OUT T_Asso_Array_Str)
 IS
 BEGIN
    SELECT last_name BULK COLLECT INTO p_asso_array_str FROM employees_bk WHERE employee_id<105;
 END;
 
 ---------------------------------------------------------------------------------------------------------------------------------
 /*This proc is invoked by .NET to test the output parameter with the type of associative array, 
    and the type of the collection element is number
    Retrieve the employees whose id less than 105*/
 PROCEDURE proc_asso_array_num_out(p_asso_array_num OUT T_Asso_Array_Num)
 IS
 BEGIN
    SELECT employee_id BULK COLLECT INTO p_asso_array_num FROM employees_bk WHERE employee_id<105;
 END;
 
 ---------------------------------------------------------------------------------------------------------------------------------
 /*This proc is invoked by .NET to test the input parameter with the type of nested table, 
    and the type of the collection element is number
    Loop through each last name in the given nested table, then update its salary*/
 PROCEDURE proc_nested_tab_str_in(p_nested_tab_str IN T_Nested_Tab_Str)
 IS
 BEGIN
    FORALL i IN p_nested_tab_str.FIRST..p_nested_tab_str.LAST
     UPDATE employees_bk SET salary=salary+1 WHERE last_name=p_nested_tab_str(i);
    COMMIT;
 END;
 
 ---------------------------------------------------------------------------------------------------------------------------------
 /*This proc is invoked by .NET to test the output parameter with the type of nested table, 
    and the type of the collection element is varchar2
    Retrieve the employees whose id less than 105*/
 PROCEDURE proc_nested_tab_str_out(p_nested_tab_str OUT T_Nested_Tab_Str)
 IS
 BEGIN
    SELECT last_name BULK COLLECT INTO p_nested_tab_str FROM employees_bk WHERE employee_id<105;
 END;
 
 ---------------------------------------------------------------------------------------------------------------------------------
 /*This proc is invoked by .NET to test the output parameter with the type of VARRAY, 
    and the type of the collection element is varchar2
    Loop through each last name in the given varray, then update its salary*/
 PROCEDURE proc_varray_str_in(p_varray_str IN T_Varray_Str)
 IS
 BEGIN
    FORALL i IN p_varray_str.FIRST..p_varray_str.LAST
      UPDATE employees_bk SET salary=salary+1 WHERE last_name=p_varray_str(i);
    COMMIT;
 END;
 
 ---------------------------------------------------------------------------------------------------------------------------------
 /*This proc is invoked by .NET to test the output parameter with the type of object
    Update the last_name according to two fields last_name, employee_id in the given object*/
 PROCEDURE proc_obj_in(p_obj IN T_Object)
 IS
 BEGIN
    UPDATE employees_bk SET last_name=p_obj.last_name WHERE employee_id=p_obj.employee_id;
    COMMIT;
 END;
 
 ---------------------------------------------------------------------------------------------------------------------------------
 /*This proc is invoked by .NET to test the output parameter with the type of nested table, 
    and the type of the collection element is object
    Loop through each object in the given nested table, then update the last name of employee*/
 PROCEDURE proc_nested_tab_obj_in(p_nested_tab_obj IN T_Nested_Tab_Obj)
 IS
 BEGIN
    FORALL idx IN p_nested_tab_obj.FIRST..p_nested_tab_obj.LAST
      UPDATE employees_bk SET last_name=p_nested_tab_obj(idx).last_name WHERE employee_id=p_nested_tab_obj(idx).employee_id;
    COMMIT;
 END;
END;

1.引用游标(REF Cursor

引用游标作为输出参数的情况十分常见。相较于MS SQL Server,Oracle存储过程无法直接返回结果集,而需要借助REF Cursor。REF Cursor实际上是指向服务器内存的指针,也就是说客户端调用获取的是一个指针,它指向服务器内存中的结果集数据。

虽然可能令熟悉MS SQL Server平台的开发者困惑,但是使用REF Cursor带来两个明显的好处:1)它可以延迟数据的交付,客户端获取的只是指针,数据只有在被请求时才传递;2)使用REF Cursor在存储过程之间传递结果集,可以最小化对性能影响,毕竟传递的只是指针而不是真实数据。

(使用DataReader

cmd.CommandText = "pkg_odp_dotnet.proc_ref_cursor";
cmd.CommandType = CommandType.StoredProcedure;
//
OracleParameter op = new OracleParameter();
op.ParameterName = "p_ref_cursor";
op.Direction = ParameterDirection.Output;
op.OracleDbType = OracleDbType.RefCursor;
cmd.Parameters.Add(op);
OracleDataReader odr = cmd.ExecuteReader();
//
if (odr.HasRows)
{
    while (odr.Read())
    {
        string s = odr.GetDecimal(odr.GetOrdinal("employee_id")) + " "
            + odr.GetString(odr.GetOrdinal("first_name")) + " "
            + odr.GetString(odr.GetOrdinal("last_name"));
        Console.WriteLine(s);
    }
}

(使用DataAdapter

cmd.CommandText = "pkg_odp_dotnet.proc_ref_cursor";
cmd.CommandType = CommandType.StoredProcedure;
//
OracleParameter op = new OracleParameter();
op.ParameterName = "p_ref_cursor";
op.Direction = ParameterDirection.Output;
op.OracleDbType = OracleDbType.RefCursor;
cmd.Parameters.Add(op);
OracleDataAdapter oda = new OracleDataAdapter(cmd);
DataSet ds = new DataSet();
oda.Fill(ds);
//
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
    string s = ds.Tables[0].Rows[i]["employee_id"] + " "
            + ds.Tables[0].Rows[i]["first_name"] + " "
            + ds.Tables[0].Rows[i]["last_name"];
    Console.WriteLine(s);
}

注意上面的Tables[0],如果有多个输出参数是REF Cursor,则可以使用Tables[0]、Tables[1],以此类推。DataReader似乎无法在有多个输出的REF Cursor有情况下使用。

方便起见,可以使用Oracle预定义的SYS_REFCURSOR,这样可以省去TYPE定义。在用法上与自定义的REF Cursor相同,就不再举具体的实例了。

2.关联数组(Associative array

关于PL/SQL中的集合类型,已经在上一篇文章《ORACLE HANDBOOK系统之三:PL/SQL中的集合类型(COLLECTIONS IN PL/SQL)》中介绍了(http://www.cnblogs.com/KissKnife/archive/2011/04/07/2008158.html),这里介绍C#与Oracle交互时如何使用关联数组。

(作为输入参数)

cmd.CommandText = "pkg_odp_dotnet.proc_asso_array_num_in";
cmd.CommandType = CommandType.StoredProcedure;
//
OracleParameter op = new OracleParameter();
op.ParameterName = "p_asso_array_num";
op.Direction = ParameterDirection.Input;
op.OracleDbType = OracleDbType.Decimal;
//
op.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
op.Value = new decimal[] { 100, 101, 102 };
//
cmd.Parameters.Add(op);
cmd.ExecuteNonQuery();

相应的,如果定义的Associative array的元素是Varchar2,则OracleParameter.OracleDbType就是OracleDbType.Varchar2,为OracleParameter.value赋值要使用string[]。

(作为输出参数)

using Oracle.DataAccess.Types;

cmd.CommandText = "pkg_odp_dotnet.proc_asso_array_str_out";
cmd.CommandType = CommandType.StoredProcedure;
//
OracleParameter op = new OracleParameter();
op.ParameterName = "p_asso_array_str";
op.Direction = ParameterDirection.Output;
op.OracleDbType = OracleDbType.Varchar2;
//
op.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
//
op.Size = 12;
int[] iArray = new int[op.Size];
for (int i = 0; i < iArray.Length; i++)
{
    iArray[i] = 25;
}
op.ArrayBindSize = iArray;
//
cmd.Parameters.Add(op);
cmd.ExecuteNonQuery();
//
OracleString[] osArray = (OracleString[])op.Value;
for (int i = 0; i <= osArray.GetUpperBound(0); i++)
{
    Console.WriteLine(osArray[i].Value + ",");
}

OracleParameter.Size,如果给定的Size比实际查询所得的行数小,则会报ORA-06513错误,所以如果无法确定实际返回的集合长度,需要往大了取。

OracleParameter.ArrayBindSize,这里集合元素是变长的VARCHAR2,因此需要为每个元素指定其长度,由于表中last_name的长度是25,所以这里定义成了25,比25小不会报错,但是可能导致字符串被截断。如果要返回的集合元素是NUMBER,则可以不指定ArrayBindSize,

OracleString,不要天真地以为可以使用string[]数组来接收返回的集合,NO!需要OracleString[],使用string[]将导致转化出错。如果要返回的集合元素是NUMBER,通常用OracleDecimal[]而不能直接用decimal[]。

通常来说,以集合类型作为输出参数类型的情况相对较少,对于结果集,使用REF Cursor是更好的选择。

3.嵌套表(Nested table

对于Nested table,有两种方案可以选择,1)直接映射成C#中的数组,2)映射成C#的自定义类型。

第一种方案,需要首先声明一个Factory类并实现IOracleArrayTypeFactory接口,并使用OracleCustomTypeMappingAttribute(schema.type_name)指定需要映射的Nested table的名称,schema.type_name需要大写。

可以看到我们使用了OracleDbType.Array,并且指定了参数的UdtTypeName。赋值时直接使用了string[]。

[OracleCustomTypeMappingAttribute("HR.T_NESTED_TAB_STR")]
public class Nested_Tab_Mapping_To_Array_Factory : IOracleArrayTypeFactory
{
    public Array CreateArray(int i)
    {
        return new string[i];
    }
    //
    public Array CreateStatusArray(int i)
    {
        return new OracleUdtStatus[i];
    }
}

(作为输入参数)

cmd.CommandText = "pkg_odp_dotnet.proc_nested_tab_str_in";
cmd.CommandType = CommandType.StoredProcedure;
//
OracleParameter op = new OracleParameter();
op.ParameterName = "p_nested_tab_str";
op.Direction = ParameterDirection.Input;
op.OracleDbType = OracleDbType.Array;
op.UdtTypeName = "HR.T_NESTED_TAB_STR";
op.Value = new string[] { "King", "Olsen" };
//
cmd.Parameters.Add(op);
cmd.ExecuteNonQuery();

(作为输出参数,同样需要上面的Factory类)

cmd.CommandText = "pkg_odp_dotnet.proc_nested_tab_str_out";
cmd.CommandType = CommandType.StoredProcedure;
//
OracleParameter op = new OracleParameter();
op.ParameterName = "p_nested_tab_str";
op.Direction = ParameterDirection.Output;
op.OracleDbType = OracleDbType.Array;
op.UdtTypeName = "HR.T_NESTED_TAB_STR";
//
cmd.Parameters.Add(op);
cmd.ExecuteNonQuery();
//
if (op.Value != DBNull.Value)
{
    string[] result = (string[])op.Value;
    foreach (string s in result)
    {
        Console.WriteLine(s);
    }
}

对比而言,第一种方案中将Nested table映射成C#数组的做法更简洁。下面我们介绍第二种方案,稍微繁杂一点,除了需要Factory类(需要同时实现IOracleArrayTypeFactory与IOracleCustomTypeFactory两个接口)外,它还需要一个自定义类型:

[OracleCustomTypeMappingAttribute("HR.T_NESTED_TAB_STR")]
public class Nested_Tab_Mapping_To_Object_Factory : IOracleCustomTypeFactory, IOracleArrayTypeFactory
{
    public IOracleCustomType CreateObject()
    {
        return new Nested_Tab_Mapping_To_Object();
    }
    //
    public Array CreateArray(int i)
    {
        return new String[i];
    }
    //
    public Array CreateStatusArray(int i)
    {
        return new OracleUdtStatus[i];
    }
}
 
public class Nested_Tab_Mapping_To_Object : IOracleCustomType, INullable
{
    [OracleArrayMapping()]
    public string[] container;
    //
    private OracleUdtStatus[] statusArray;
    public OracleUdtStatus[] StatusArray
    {
        get
        {
            return statusArray;
        }
        set
        {
            statusArray = value;
        }
    }
    //
    private bool isNull;
    public bool IsNull
    {
        get
        {
            return isNull;
        }
    }
    //
    public static Nested_Tab_Mapping_To_Object Null
    {
        get
        {
            Nested_Tab_Mapping_To_Object nt = new Nested_Tab_Mapping_To_Object();
            nt.isNull = true;
            return nt;
        }
    }
    //
    public void ToCustomObject(OracleConnection conn, IntPtr pUdt)
    {
        object outStatusArray;
        container = (string[])OracleUdt.GetValue(conn, pUdt, 0, out outStatusArray);
        statusArray = (OracleUdtStatus[])outStatusArray;
    }
    public void FromCustomObject(OracleConnection conn, IntPtr pUdt)
    {
        OracleUdt.SetValue(conn, pUdt, 0, container, statusArray);
    }
}

(作为输入参数)

cmd.CommandText = "pkg_odp_dotnet.proc_nested_tab_str_in";
cmd.CommandType = CommandType.StoredProcedure;
//
OracleParameter op = new OracleParameter();
op.ParameterName = "p_nested_tab_str";
op.Direction = ParameterDirection.Input;
op.OracleDbType = OracleDbType.Object;
op.UdtTypeName = "HR.T_NESTED_TAB_STR";
Nested_Tab_Mapping_To_Object nt = new Nested_Tab_Mapping_To_Object();
nt.container = new string[] { "King", "Olsen" };
op.Value = nt;
//
cmd.Parameters.Add(op);
cmd.ExecuteNonQuery();

(作为输出参数)

cmd.CommandText = "pkg_odp_dotnet.proc_nested_tab_str_out";
cmd.CommandType = CommandType.StoredProcedure;
//
OracleParameter op = new OracleParameter();
op.ParameterName = "p_nested_tab_str";
op.Direction = ParameterDirection.Output;
op.OracleDbType = OracleDbType.Object;
op.UdtTypeName = "HR.T_NESTED_TAB_STR";
//
cmd.Parameters.Add(op);
cmd.ExecuteNonQuery();
//
if (op.Value != DBNull.Value)
{
    Nested_Tab_Mapping_To_Object o = (Nested_Tab_Mapping_To_Object)op.Value;
    foreach (string s in o.container)
    {
        Console.WriteLine(s);
    }
}

4.动态数组(VARRAY

与Nested table用法相同。

5.对象(Object

Oracle中Object类型的定义可以参见文章开头的T_Object。遇到T_Object时,处理起来类似于第4节中将Nested table映射成自定义对象的情况,同样需要一个自定义类型以及一个Factory类。

[OracleCustomTypeMappingAttribute("HR.T_OBJECT")]
public class Ora_Object_Factory : IOracleCustomTypeFactory
{
    public virtual IOracleCustomType CreateObject()
    {
        Ora_Object o = new Ora_Object();
        return o;
    }
}
 
public class Ora_Object : IOracleCustomType, INullable
{
    private bool isNull;
    private int employeeId;
    private string lastName;
    //
    public bool IsNull
    {
        get
        {
            return this.isNull;
        }
    }
    //
    public static Ora_Object Null
    {
        get
        {
            Ora_Object mo = new Ora_Object();
            mo.isNull = true;
            return mo;
        }
    }
    //
    [OracleObjectMappingAttribute("EMPLOYEE_ID")]
    public int EmployeeId
    {
        get
        {
            return employeeId;
        }
        set
        {
            employeeId = value;
        }
    }
    //
    [OracleObjectMappingAttribute("LAST_NAME")]
    public string LastName
    {
        get
        {
            return lastName;
        }
        set
        {
            lastName = value;
        }
    }
    //
    public void FromCustomObject(Oracle.DataAccess.Client.OracleConnection conn, System.IntPtr pUdt)
    {
        OracleUdt.SetValue(conn, pUdt, "EMPLOYEE_ID", this.EmployeeId);
        OracleUdt.SetValue(conn, pUdt, "LAST_NAME", this.LastName);
    }
    public void ToCustomObject(Oracle.DataAccess.Client.OracleConnection conn, System.IntPtr pUdt)
    {
        this.EmployeeId = ((int)(OracleUdt.GetValue(conn, pUdt, "EMPLOYEE_ID")));
        this.LastName = ((string)(OracleUdt.GetValue(conn, pUdt, "LAST_NAME")));
    }
}

(作为输入参数)

cmd.CommandText = "pkg_odp_dotnet.proc_obj_in";
cmd.CommandType = CommandType.StoredProcedure;
//
OracleParameter op = new OracleParameter();
op.ParameterName = "p_obj";
op.Direction = ParameterDirection.Input;
op.OracleDbType = OracleDbType.Object;
op.UdtTypeName = "HR.T_OBJECT";
//
Ora_Object mo = new Ora_Object();
mo.EmployeeId = 100;
mo.LastName = "abcd";
op.Value = mo;
//
cmd.Parameters.Add(op);
cmd.ExecuteNonQuery();

作为输出参数的情况很简单,这里就不重复了。

6.对象集合(Object collection

来到终极篇,所谓对象集合,这里指的是本身是个集合类型,并且集合元素是Oracle的Object,例如我们在最开始定义的T_Nested_Tab_Obj。

由于它是Nested table,则我们可以按照第3节中的作法将其转化成C#中的Array,于是,我们需要一个Factory类并实现IOracleArrayTypeFactory接口:

[OracleCustomTypeMappingAttribute("HR.T_NESTED_TAB_OBJ")]
public class Nested_Tab_Obj_Mapping_To_Array_Factory : IOracleArrayTypeFactory
{
    public Array CreateArray(int i)
    {
        return new Ora_Object[i];
    }
    //
    public Array CreateStatusArray(int i)
    {
        return new OracleUdtStatus[i];
    }
}

又由于集合的元素是Oracle的Object类型,仿照第5节中的做法,我们分别需要一个自定义类型以及一个Factory类,由于集合元素也是使用的T_Object,所以这两个类与第5节中相同,这里不再重复写了。下面我们看看具体的调用代码:

cmd.CommandText = "pkg_odp_dotnet.proc_nested_tab_obj_in";
cmd.CommandType = CommandType.StoredProcedure;
//
OracleParameter op = new OracleParameter();
op.ParameterName = "p_nested_tab_obj";
op.Direction = ParameterDirection.Input;
op.OracleDbType = OracleDbType.Array;
op.UdtTypeName = "HR.T_NESTED_TAB_OBJ";
//
Ora_Object mo = new Ora_Object();
mo.EmployeeId = 100;
mo.LastName = "00000";
Ora_Object mo2 = new Ora_Object();
mo2.EmployeeId = 102;
mo2.LastName = "00000";
op.Size = 2;
op.Value = new Ora_Object[] { mo, mo2 };
//
cmd.Parameters.Add(op);
cmd.ExecuteNonQuery();

作为输出参数的情况也很容易写,这里就不举例子了,VARRAY的情况与Nested table基本一样,也不举例了。到这里,关于在C#中如何处理几类主要的复杂参数类型,已经基本介绍完了,对于一些更为复杂的,比如Object中包含Object等等情况,不太常见,就不介绍了。

PS,虽然Associative array中的元素也可以是Object,但在与C#类型做映射时似乎不能成功,可能根Associative array是PL/SQL类型(即不能通过CREATE TYPE创建独立的类型)有关,还没有找到相关的文档。

ORACLE HANDBOOK系列之六:ODP.NET与复杂的PL/SQL数据类型(Using ODP.NET To Deal With Complex PLSQL Data Types)...相关推荐

  1. ODP.NET与复杂的PL/SQL数据类型(Using ODP.NET To Deal With Complex PLSQL Data Types)

    ODP.NET与复杂的PL/SQL数据类型(Using ODP.NET To Deal With Complex PLSQL Data Types) 在开始介绍之前,先给出文章里用到的所有PL/SQL ...

  2. 视频教程-赵强老师:Oracle数据库从10g到11g(4)PL/SQL编程基础-Oracle

    赵强老师:Oracle数据库从10g到11g(4)PL/SQL编程基础 毕业于清华大学,拥有超过13年的工作经验. Oracle认证讲师,拥有6年以上授课经验.精通Oracle数据库.中间(Weblo ...

  3. oracle 比对数据库表和数据表数据(PL\SQL)

    开发测试时我们经常会遇到:需要对比两个表的表结构和表数据是否一致.以达到数据同步及历史数据迁移的需要.在此我们可以通过已下方式实现数据库表及数据的比对工作 一台安装oracle数据库的操作系统 PL\ ...

  4. ORACLE HANDBOOK系列之十:字符集、编码以及Oracle的那些事

    第一部分字符集与编码常识 字符集: 人们根据需要把某些字符收集到一处,并赋以名称,于是便有了某某字符集. 编码: 当前面收集的工作完成以后,为了让只认识数字的"愚蠢"的计算机也能够 ...

  5. oracle客户端免安装配置、64位机器PL/SQL和VS自带的IIS连接问题

    一.oracle客户端免安装配置 1.到oracle官网下载Oracle InstantClient, 把它解压缩到单独目录,例如C:\OracleClient, 2. 添加环境变量 ORACLE_H ...

  6. oracle 赋值表数据类型,PL/SQL数据类型及操作符

    标量(scalar)数据类型 标量(scalar)数据类型没有内部组件,他们大致可分为以下四类: . number . character . date/time . boolean 表1显示了数字数 ...

  7. Oracle入门(十四.4)之在PL / SQL中使用变量

    一.变量的使用 (1)使用变量的原因 •临时存储数据 •储存值的操作 •可重用性 (2)处理PL / SQL中的变量 变量是: •在声明部分声明并初始化 •在可执行部分中使用并分配新值 变量可以是: ...

  8. Oracle入门(十四.3)之创建PL / SQL块

    一.PL / SQL块结构 一个PL / SQL块由三部分组成. PL / SQL块结构部分 二.PL / SQL编译器 用高级编程语言(C,Java,PL / SQL等)编写的每个程序都必须经过检查 ...

  9. oracle数据库提示无监听,【原创】PL/SQL连数据库提示无监听程序

    一.问题描述: 安装好ORACLE服务器端后,利用PL/SQL连数据,提示无监听程序. 二.解决步骤: 1.检查防火墙. 将防火墙关闭. 2.查看监听服务. 在管理工具->服务中查看监听服务是否 ...

最新文章

  1. 【C#小知识】C#中一些易混淆概念总结(三)---------结构,GC,静态成员,静态类...
  2. WiFi行业9大趋势解析
  3. 网吧ARP双绑定详细策略   -限制P2P绝密版
  4. Hadoop HA+Federation 高可用联邦模式搭建指南
  5. [置顶] mkdir函数-linux
  6. 文件2. 文件重命名
  7. [Ural1099]工作安排 带花树
  8. JSP的九大内置对象
  9. 怎样设置计算机安全模式,电脑怎样进入安全模式
  10. 【nmon】nmon :服务器监控数据采集
  11. Emacs指北(做一个搬运工好累)
  12. mybatis简单查询
  13. Vue watch 监听复杂对象变化,oldvalue 和 newValue 一致的解决办法。
  14. 死锁预防之银行家算法
  15. 说说数据结构中的几种树
  16. 【C语言编程4】输入年份输出全年日历
  17. 虚拟服务器的磁盘合并,磁盘管理怎么合并分区
  18. Oracle11g下载地址Oracle下载
  19. 【算法】动态规划 ④ ( 动态规划分类 | 坐标型动态规划 | 前缀划分型动态规划 | 前缀匹配型动态规划 | 区间型动态规划 | 背包型动态规划 )
  20. 认识控制台-什么是控制台?

热门文章

  1. macos下载的安装包在哪里_macbook任意降级,为您带来mac os完美降级教程
  2. Linux的开源免费办公软件,开源免费Office办公套件(LibreOffice)
  3. 鸟哥的linux私房菜简答题答案,《鸟哥的Linux私房菜》7章 Linux文件与目录管理 习题答案...
  4. 2020idea插件怎么同步_VScode 插件整理
  5. android应用对于内存的大小是有限制的,Android 的内存限制
  6. 自动化运维之–Cobbler
  7. Annotation processing seems to be disabled for the project microservicecloud
  8. HDFS体系架构介绍
  9. 你会先写PRD,还是先画原型?
  10. 互联网晚报 | 9月11日 星期六 | 魅蓝宣布正式回归;黑石集团终止收购SOHO中国;“小酒馆第一股”海伦司正式登陆港交所...