0

私は独学で Pro*C を学んでおり、(おそらく) カーソルを使用してデータベース内のレコードを処理し、コンパイルして実行するプログラムを持っています。問題は、変数が印刷されたときにメモリにあったジャンクを取得していることです(カーソルを使用して読み込まれたもの)。

SQL execステートメントをいくつかの異なる方法で分割しようとしましたが、これは役に立ちませんでした。また、さまざまな場所でSQLを開いたり閉じたりしようとしましたが、これも役に立ちませんでした。私は本当に長いデバッグ プロセスの最後にいます。この時点で、私は非常に初心者の間違いを犯していると確信しています。ここにいる Oracle プログラマーの中で少し時間を割いても構わないという人がいれば、ここで軌道に戻る方法について少しフィードバックをいただければ幸いです。

印刷するはずです:

Enter a Guest_ID(type 0 to terminate)>>

1

Charge Summary for: Firstname Lastname Guest-ID: 1

Sales_Item: 1 – Room (Taxable)

Hotel-Id Hotel-Name Trans-Date Quantity Unit-Price Extended-Price

Hotel-Id Hotel-Name Trans-Date Quantity Unit-Price Extended-Price

Hotel-Id Hotel-Name Trans-Date Quantity Unit-Price Extended-Price

Sales Item Total Quantity Extended-Price

それは実際に印刷します:

Enter a Guest_ID(type 0 to terminate)>>

3

Charge Summary for: l▒   Guest_ID: 3

カーソルを完全に台無しにしているように感じますが、Pro*C での変数の宣言方法と使用方法にまだ慣れていないため、問題がどこにあるかを正確に特定することはできません。また、C プログラムは通常デバッグされますが、これはリモート サーバー上で実行され、デバッグは非常に制限されており、dbx コマンドさえありません。

コード:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
exec sql include sqlca;

// OK - Here we GO
void main()
{
    // First, create all the variables that we will need to communicate between 
    // the "C" program and the database
    exec sql begin declare section;
        //VARCHAR sLastName[51], sFirstName[51], sHotelName[51], sCheckInDate[12], sRoom[11];
        VARCHAR sLastName[51], sFirstName[51], sHotelName[51], sTransDate[11];
        //int nDays, nGuest_ID, nCount;
        int nGuest_ID, nQuantity, nUnitPrice, nCount, nHotelID, nItemID;
        //VARCHAR sInCity[11];
        VARCHAR sItemName[31], sTaxable[11];
        VARCHAR sUserID[21], sPassword[21];
    exec sql end declare section;

        // Now define the cursor we will use to get all of the charges that the guest incurred at all hotels
    exec sql declare dbGuest cursor for
        Select G.Guest_ID, G.Last_Name, G.First_Name, C.Item_ID, C.Item_Name, C.Quantity, C.Unit_Price, C.Trans_Date, H.Hotel_Name, H.Hotel_ID, SI.Taxable
        From Hotel H, Charge C, Stay S, Guest G, Sales_Item SI Where
        C.Stay_ID=S.Stay_ID And H.Hotel_ID=S.Hotel_ID And G.Guest_ID=S.Guest_ID
            And SI.Item_ID=C.Item_ID
        Group By S.Guest_ID;

    // Set up the user-id and password to access my database
    // Because we are using the local database on this server
    // we don't need to use any database location or SID
    strcpy(sUserID.arr,"myuserid"); 
    strcpy(sPassword.arr,"mypassword");  
    sUserID.len=strlen(sUserID.arr);
    sPassword.len=strlen(sPassword.arr);
    exec sql connect :sUserID identified by :sPassword;

    // sqlca.sqlcode is a variable that is set based on the last command sent in to the database
    // a value anything other than zero for what we just did (connect to the database) indicates
    // a error.
    if(sqlca.sqlcode !=0)
       {
        //printf("Sorry, cannot connect to server, pgm aborted %s\n",sqlca.sqlcode); //correction 2/5/14
        printf("Sorry, cannot connect to server, pgm aborted %d\n",sqlca.sqlcode); //change to %d
        exit(1);
       }
    //we made it here, so we were able to open the database correctly
    exec sql SELECT COUNT(*) INTO :nCount FROM Guest;
    printf ("There are %d Guests.\n",nCount);
    for(;;){
        // Read in through stdio the Guest we want to query, then set it up do we can use it
        printf("Enter a Guest_ID(type 0 to terminate)>>\n");
        scanf("%d",&nGuest_ID);
        //Guest_ID.len= strlen(Guest_ID.arr);
        if(nGuest_ID==0)
        {
            printf("BYE\n");
            exit(0);
        }
        printf("%s %s %s %s %d\n","Charge Summary for:", sFirstName.arr, sLastName.arr, " Guest_ID:", nGuest_ID);
        //printf("I do not work yet (type exit to terminate)>>\n");
                // Open our cursor and begin reading records
        exec sql open dbGuest;
        for(;;)
        {
            //exec sql fetch dbGuest into :nGuest_ID, :sLastName, :sFirstName, :sHotelName, :sCheckInDate, :nDays, :sRoom;
            exec sql fetch dbGuest into :sLastName, :sFirstName, :nItemID, :sItemName, :nQuantity, :nUnitPrice, :sTransDate, :sHotelName, :nHotelID;
            if(sqlca.sqlcode !=0)  // If anything went wrong or we read past eof, stop the loop
            {
                break;
            }
            printf("%s %s %s %s %d\n","Charge Summary for:", sFirstName.arr, sLastName.arr, " Guest_ID:", nGuest_ID);
            // Do the crazy stuff to end the C-Strings
            sLastName.arr[sLastName.len] = 0;
            sFirstName.arr[sFirstName.len] = 0;
            sItemName.arr[sItemName.len] = 0;
            sTransDate.arr[sTransDate.len] = 0;
            sHotelName.arr[sHotelName.len] = 0;

            // Print out the information for this guest
            printf("%s %d %s %s \n", "Sales_Item: ", nItemID, " - ", sItemName.arr);

            printf("%d %s %s %d %d \n", nHotelID, " ", sHotelName.arr, " ",sTransDate.arr, " ", nQuantity, " ", nUnitPrice);
        }
        // close the cursor and end the program
        exec sql close dbGuest ;
    }
    exit(0);
}

通常、C プログラムはデバッガーで実行されますが、これは Pro C であり、Oracle Pro C のデバッグ全体に戸惑っています (リモート データベースで実行されているため)。

これらを試しましたが、役に立ちませんでした:

Oracle のネストされたカーソルでの奇妙な動作

Oracle ProC INSERT INTO VALUES ( (select ...) )

Oracle Pro*C でカーソルを使用してテーブルを更新できませんでした

VARCHAR 変数は別の方法で宣言する必要があると言われましたが、他の方法ではエラーがスローされるようです。

4

2 に答える 2

1

値を にフェッチする前であってもsFirstName、それらを出力します。まず、初期化していないため、ガベージ値が出力されます。また、カーソルのフェッチが中断されたと感じた場合は、LOOP を *break* する前に、sqlca の sqlerrm を使用してエラー メッセージを出力します。お気に入りsqlca.sqlerrm.sqlerrmc

次に、OPEN CURSORクエリに構文エラーがあるため、呼び出しは失敗します。そのため、以下のようにカーソルを変更するか、クエリを正しく変更する必要があります。

OPEN cursor続行する前にのステータスを確認する必要がありますFETCH。そうしないと、再び失敗し、結果が予測不能になる可能性があります。そのため、電話のsqlca.sqlcodeたびに確認してください。EXEC SQL

また、インジケータ変数が使用されていない場合は、クエリでNULL使用できるを処理する必要がありますNVL()

   exec sql declare dbGuest cursor for
        Select G.Guest_ID,
               G.Last_Name,
               G.First_Name,
               C.Item_ID,
               C.Item_Name,
               C.Quantity,
               C.Unit_Price,
               C.Trans_Date,
               H.Hotel_Name,
               H.Hotel_ID,
               SI.Taxable
        From Hotel H, Charge C, Stay S, Guest G, Sales_Item SI
        Where C.Stay_ID=S.Stay_ID 
          And H.Hotel_ID=S.Hotel_ID 
          And G.Guest_ID=S.Guest_ID
          And SI.Item_ID=C.Item_ID;

集計されていない列は、集計関数でのみ使用できます。したがって、グループ化を削除するか、MAX()他の列に追加してください。

以下を宣言に追加します

int temp_sales_id = -999;
int first_iter = 1;
int total_nQuantity = 0;
float total_nUnitPrice = 0.0;

それで、

exec sql open dbGuest;

    /* Lets check the status of the OPEN statement before proceeding , else exceptions would be suppressed */
    if(sqlca.sqlcode !=0)  // If anything went wrong or we read past eof, stop the loop
     {
        printf("Error while opening Cursor <%d><%s>\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
        break;
     }

for(;;)
    {
        //exec sql fetch dbGuest into :nGuest_ID, :sLastName, :sFirstName, :sHotelName, :sCheckInDate, :nDays, :sRoom;
        exec sql fetch dbGuest into :sLastName, :sFirstName, :nItemID, :sItemName, :nQuantity, :nUnitPrice, :sTransDate, :sHotelName, :nHotelID;

        /* Check for No DATA FOUND */
        if(sqlca.sqlcode == 100 || sqlca.sqlcode == 1403)  // If anything went wrong or we read past eof, stop the loop
        {
            printf("CURSOR is empty after all fetch");
            break;
        }
        /* Check for other errors */
        else if(sqlca.sqlcode != 0)
        {
             printf("Error while fetching from Cursor <%d><%s>\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
             break;
        }

        if(first_iter) {
           printf("%s %s %s %s %d\n","Charge Summary for:", sFirstName.arr, sLastName.arr, " Guest_ID:", nGuest_ID);
           first_iter = 0;
        }
        // Do the crazy stuff to end the C-Strings
        sLastName.arr[sLastName.len] = 0;
        sFirstName.arr[sFirstName.len] = 0;
        sItemName.arr[sItemName.len] = 0;
        sTransDate.arr[sTransDate.len] = 0;
        sHotelName.arr[sHotelName.len] = 0;

        if(temp_sales_id == -999 || temp_sales_id != nItemID)
        {
          /* First Item or Sales Item has Changed (next sales id)*/
          temp_sales_id = nItemID;
          // Print out the information for this guest
          printf("%s %d %s %s \n", "Sales_Item: ", nItemID, " - ", sItemName.arr);

          printf("%d %s %s %d %d \n", nHotelID, " ", sHotelName.arr, " ",sTransDate.arr, " ", nQuantity, " ", nUnitPrice);

          total_nQuantity += nQuantity;
          total_nUnitPrice += nUnitPrice;
        }
        if (temp_sales_id != nItemID) {
            /* Printing total for Current Sale id */
            /* If you want to Sum all the sale id together take this finally */
            printf("Total Quantity <%d> Total Extended Price <%g>\n",total_nQuantity,total_nUnitPrice);
            total_nUnitPrice = 0;
            total_nQuantity = 0;
        }

        if(temp_sales_id == -999 || temp_sales_id == nItemID) {
          printf("%d %s %s %d %d \n", nHotelID, " ", sHotelName.arr, " ",sTransDate.arr, " ", nQuantity, " ", nUnitPrice);
        }
    }
    // close the cursor and end the program
    exec sql close dbGuest ;
于 2014-02-20T00:35:16.370 に答える