如何将表从存储过程返回到PHP

时间:2016-01-20 19:02:33

标签: php sql-server oracle stored-procedures

对于数据库项目,我需要实现一个存储过程。在我的情况下,我尝试获取指定订单的内容。我的存储过程如下所示:

create or replace PROCEDURE bestellinhalt (sbestellnr IN integer, rtable OUT sys_refcursor) IS
BEGIN
  OPEN rtable for SELECT beinhaltet.bestellnr,artikel.artikelname, artikel.artikelnr, beinhaltet.anzahl, artikel.preis FROM ARTIKEL, BEINHALTET WHERE ARTIKEL.ARTIKELNR = BEINHALTET.ARTIKELNR AND BEINHALTET.BESTELLNR = sbestellnr;
END;

在SQL Developer中,它还以表格形式返回所需的值:

Output of SQL Developer

但是现在我不知道如何将这张表放到我的PHP页面中。这就是我尝试的方式:

    <?php
     //Handle Stored Procedure
     if (isset($_GET['bestellnr']))
     {
        //Call Stored Procedure  
        $bestellnr = intval($_GET['bestellnr']);
        $sproc = oci_parse($conn, 'begin bestellinhalt(:in, :rtable); end;');
        $returntable = oci_new_collection($conn, 'RTABLE');
        //Bind variables, p1=input (nachname), p2=output (abtnr)
        oci_bind_by_name($sproc, ':in', $bestellnr);
        oci_bind_by_name($sproc, ':rtable', $returntable);
        oci_execute($sproc);
        $conn_err=oci_error($conn);
        $proc_err=oci_error($sproc);
        //If there have been no Connection or Database errors, print department
        if(!$conn_err && !$proc_err){
           echo("Erfolg" );  // prints OUT parameter of stored procedure
        }
        else{
          //Print potential errors and warning
          echo("Fehler!");
          print($conn_err);
          print_r($proc_err);
        }  
     }
     // clean up connections
     oci_free_statement($sproc);
     oci_close($conn);
    ?>

我总是最终得到以下错误:

  

PLS-00306:调用&#39; BESTELLINHALT&#39;错误的参数数量或类型ORA-06550

但是程序只需要一个输入,所以我现在有点困惑。另一个错误是&#34; RTABLE&#34;在index.php&#34;中找不到。我之前从未使用过php。我的方法是基于这个论坛条目@oracle:

https://community.oracle.com/thread/617612?tstart=0

1 个答案:

答案 0 :(得分:1)

请仔细阅读本页。我有你需要的所有答案。

http://www.oracle.com/technetwork/articles/fuecks-sps-095636.html

并从同一页面引用你的答案。

CREATE OR REPLACE PACKAGE BODY blog AS

    /*------------------------------------------------*/
    PROCEDURE latest(
        num_entries_in IN NUMBER,
        entries_cursor_out OUT cursorType
    ) AS

        BEGIN

            OPEN entries_cursor_out FOR
                SELECT * FROM blogs WHERE rownum < num_entries_in
                ORDER BY date_published DESC;

        END latest;

    /*------------------------------------------------*/
    PROCEDURE edit_entry(
        status_out OUT NUMBER,
        status_msg_out OUT VARCHAR2,
        id_inout IN OUT INTEGER,
        title_in IN VARCHAR2,
        text_out OUT CLOB,
        categories_in IN list_of_numbers
    ) AS

        ENTRY_NOT_FOUND EXCEPTION;
        entry_found INTEGER := 0;

        BEGIN

            /* Default status to success */
            status_out := 1;

            /* If id_inout has a value then attempt to UPDATE */
            IF id_inout IS NOT NULL THEN

                /* Check the id exists - raise ENTRY_NOT_FOUND if not */
                SELECT COUNT(*) INTO entry_found
                FROM blogs b WHERE b.id = id_inout;
                IF entry_found != 1 THEN RAISE ENTRY_NOT_FOUND; END IF;

                /* Update the blogs table returning the CLOB field */
                UPDATE blogs b SET b.title = title_in, b.text = EMPTY_CLOB()
                WHERE b.id = id_inout RETURNING b.text INTO text_out;

                /* Remove any existing relationships to categories
                   - new categories inserted below */
                DELETE FROM blogs_to_categories WHERE blog_id = id_inout;

                status_msg_out := 'Blog entry ' || id_inout || ' updated';

            /* id_inout was null so INSERT new record */
            ELSE

                INSERT INTO blogs b ( b.id, b.title, b.date_published, b.text )
                VALUES ( blog_id_seq.nextval, title_in, SYSDATE, EMPTY_CLOB() )
                RETURNING b.id, b.text INTO id_inout, text_out;

                status_msg_out := 'Blog entry ' || id_inout || ' inserted';

            END IF;

            /* Now handle assignment to categories.
               Loop over the categories_in collection,
               inserting the new category assignments */
            FOR i IN 1 .. categories_in.count
                LOOP
                    INSERT INTO blogs_to_categories (blog_id,category_id)
                    VALUES (id_inout,categories_in(i));
                END LOOP;

            status_msg_out := status_msg_out || ' - added to '
                              || categories_in.count || ' categories';

            EXCEPTION
                /* Catch the exception when id_inout not found */
                WHEN ENTRY_NOT_FOUND THEN
                    status_out := -1001;
                    status_msg_out := 'No entry found in table blogs with id = '
                                      || id_inout;
                /* Catch any other exceptions raised by Oracle */
                WHEN OTHERS THEN
                    status_out := -1;
                    status_msg_out := 'Error: ' || TO_CHAR (SQLCODE) || SQLERRM;

        END edit_entry;

END blog;
/

The underlying table structure the procedures are using is:

CREATE SEQUENCE blog_id_seq
    INCREMENT BY 1;
/
CREATE TABLE blogs (
    id NUMBER PRIMARY KEY,
    title VARCHAR2(200),
    date_published DATE,
    text CLOB
);
/
CREATE SEQUENCE category_id_seq
    INCREMENT BY 1;

CREATE TABLE categories (
    id NUMBER PRIMARY KEY,
    name VARCHAR2(30) UNIQUE
);
/
CREATE TABLE blogs_to_categories (
    blog_id INTEGER NOT NULL
    REFERENCES blogs(id),
    category_id INTEGER NOT NULL
    REFERENCES categories(id),
    PRIMARY KEY (blog_id, category_id)
);
/

Stored Procedures and Reference Cursors

Looking at the blog.latest procedure, you'll see it returns a reference cursor for iterating over the row in my blogs table.

To work with a cursor in PHP two additional steps are required, as compared to accessing rows directly from a SELECT statement. The first step is preparing a cursor resource in PHP, using the oci_new_cursor() function, which you then use to bind to the appropriate parameter. The second step, after you have executed the SQL statement, is calling oci_execute() on the cursor resource.

The following PHP script illustrates this procedure:

<?php
$conn = oci_connect('SCOTT','TIGER') or die;


$sql = 'BEGIN blog.latest(:num_entries, :blog_entries); END;';

$stmt = oci_parse($conn, $sql);

// Bind the input num_entries argument to the $max_entries PHP variable
$max_entries = 5;
oci_bind_by_name($stmt,":num_entries",$max_entries,32);

// Create a new cursor resource
$blog_entries = oci_new_cursor($conn);

// Bind the cursor resource to the Oracle argument
oci_bind_by_name($stmt,":blog_entries",$blog_entries,-1,OCI_B_CURSOR);

// Execute the statement
oci_execute($stmt);

// Execute the cursor
oci_execute($blog_entries);

print "The $max_entries most recent blog entries\n";

// Use OCIFetchinto in the same way as you would with SELECT
while ($entry = oci_fetch_assoc($blog_entries, OCI_RETURN_LOBS )) {
    print_r($entry);
}
?>