Can anyone help me with the following task:
Create a procedure SectionCount(instructor_ID) that, according to the instructor's ID, displays the numbers of those of its sections with the largest number of students enrolled. Display appropriate messages if an instructor with such an ID does not exist or if there are no sections to lead. Add a block to handle the necessary exceptions.
my solution is the following..whether it is correct:
CREATE OR REPLACE FUNCTION your_function_name(i_student_id NUMBER)
RETURN NUMBER AS v_sections_count NUMBER;
BEGIN
SELECT COUNT(SECTION_ID) into v_sections_count FROM ENROLLMENT WHERE STUDENT_ID = i_student_id;
IF v_sections_count > 3 THEN
RETURN -1;
ELSE
RETURN v_sections_count;
END IF;
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('An error occured.');
RETURN -2;
END;
A suggestion or two, if I may.
always use table's alias when referencing columns. In your case, that's only one table but - often you have to "fix" a query and add yet another table, and then you don't know which column belongs to which table and have to add aliases anyway.
try to use only one RETURN per function (two, if there's an exception handling section - as in your function) because you might do something wrong in code logic and RETURN (i.e. terminate further execution) although you didn't actually want to do that. Instead, add a new variable which will be used to "calculate" the return value (such as retval in code I posted); then return its value
DBMS_OUTPUT.PUT_LINE is OK for debugging; nobody else will ever see it, because end users won't call that function from SQL*Plus (or other tools which are capable of displaying that message). For example, it (DBMS_OUTPUT.PUT_LINE) won't raise error in Oracle Apex or Oracle Forms, but you won't see anything.
Also, add SQLERRM which will actually show you which error happened. Info "an error occurred" isn't very descriptive
So:
CREATE OR REPLACE FUNCTION your_function_name (i_student_id NUMBER)
RETURN NUMBER
AS
v_sections_count NUMBER;
retval NUMBER;
BEGIN
SELECT COUNT(e.section_id)
INTO v_sections_count
FROM enrollment e
WHERE e.student_id = i_student_id;
retval := CASE WHEN v_sections_count > 3 then -1
ELSE v_sections_count
END;
RETURN retval;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('An error occured: ' || SQLERRM);
retval := -2;
RETURN retval;
END your_function_name ;
I have defined an expression in one of my cells from my dataset1. My Design window and I have to repeat for each month's cells but I'm getting an #ERROR when I click on the PREVIEW tab in SSRS.
My thought is if the ActivityMonth value = 1 and the Type value = "PIF" then display the value in the Data column.
=IIF(Fields!Activity_Month.Value = 1 AND Fields!Type.Value = "PIF", Fields!Data.Value, 0)
I got this WARNING from SSRS:
[rsRuntimeErrorInExpression] The Value expression for the textrun ‘Textbox1471.Paragraphs[0].TextRuns[0]’ contains an error: Input string was not in a correct format.
But it ran successfully.
From the comments and the edit history, it looks like you have used & mark which is used to concatenate strings instead of AND keyword. After editing the expression - for me - the following expression looks great:
=IIF(Fields!Activity_Month.Value = 1 AND Fields!Type.Value = "PIF", Fields!Data.Value, 0)
But i have two remarks:
It may cause an error due to the different data types returned by the expression (0 is integer, Data.Value has another data type:
If Fields!Data.Value is of type string then use the following expression:
=IIF(Fields!Activity_Month.Value = 1 AND Fields!Type.Value = "PIF", Fields!Data.Value, "0")
Another thing to mention is that if value contains null it may throw an exception, so you have to check if field contains null:
SSRS expression replace NULL with another field value
isnull in SSRS expressions
declare
curr_quantity number;
begin
select quantity
into curr_quantity
from stockrecord
where itemserialnumber = :p28_item_1
And inventoryid = :p28_inv_id;
if curr_quantity < :p28_quantity_1 then
return false;
else
return true;
end if;
end;
STOCKRECORD(itemserialnumber, inventoryid, quantity).
I am trying to validate my quantity at the front end in APEX Oracle with PL/SQL Function Body (Returning Boolean).
Suppose if I have a 500 quantity of an item in table and I set :p28_quantity_1 from 1-250 validation works fine but when i set it to 251 or so on the validation fails. I can't figure out the problem. Any help please.
Currently, I am a newbier of Apex. I create a page with 2 text box (YEAR and MONTH) and 1 button to submit value of 2 text box into PL/SQL script
DECLARE
count_files NUMBER;
BEGIN
select count(*) into count_files
from FAC_FILE_MANAGEMENT_VIEW
where FAC_MONTH = :P6_MONTH and FAC_YEAR = :P6_YEAR;
IF count_files = 0 THEN
-- insert something
END IF;
END;
The issue is the PL/SQl code does not work and I don't know how to print the value of 2 binding text box (:P6_MONTH and :P6_YEAR) to debug
Example:
htp.p('<script language="javascript">');
htp.p('alert("'||:P6_MONTH||'");');
htp.p('</script>');
It seems that the underlying nature of NAV is to resist requiring the populating of a field to be mandatory. In the case of our business logic, certain fields must be populated in order for the data to be valid. For example, a customer record must have at least a name and phone number. I've searched a number of places but have not found a suitable solution. So how can this be accomplished?
After struggling to find a succinct way to require certain fields on a card to be populated, I have come up with the following and it (so far) is working for me. I started to sense that NAV was not meant to have mandatory fields, but I need them for our business logic. Anyways, here we go...
Step One:
- We have a codeunit for various validation logic, in which I've added the function to read a custom table listing the tables and their fields that are mandatory. This function takes the table number, key field, and a "create mode". It returns a text "completion status" value. I find the table for the record I am validating. I loop through the mandatory fields, if the field is not populated, I add it to a list of incomplete fields. If the list of incomplete fields is empty, the completion status is "done". If the list of incomplete fields is populated, a message is displayed indicating the missing fields and allows the user an option to cancel the create of a new record or to stay on the (new or existing) record and enter the missing data, and the completion status is set to "delete" to cancel a create, or "return" to stay on the record. Logic follows:
CheckMadatoryFields(TableNumber : Integer;KeyField : Code[10];CreateMode : Boolean) Completion Status : Text[30]
// Read the 'LockoutFields' table to find the manditory fields for the table passed in.
LockoutFields.RESET;
LockoutFields.SETRANGE("Table No.", TableNumber);
LockoutFields.SETFILTER("Filter ID", 'MANDITORY_FIELD');
// Get a record reference for the table passed in
RecRef.OPEN(TableNumber);
RecRef.SETVIEW('WHERE("No." = FILTER(' + KeyField + '))');
// Set this to done, i.e. data is complete (don't delete by mistake).
CompletionStatus := 'done';
IF RecRef.FINDFIRST THEN BEGIN
// Check the record's manditory field(s) listed in the 'LockoutFields' table to see if they're blank.
IF LockoutFields.FINDSET THEN BEGIN
REPEAT
FldRef := RecRef.FIELD(LockoutFields."Field No.");
IF FORMAT(FldRef.VALUE) = '' THEN
FldList := FldList + ' - ' + FldRef.CAPTION + '\';
UNTIL LockoutFields.NEXT = 0;
END;
IF FldList <> '' THEN BEGIN
// If creating the record, add the 'Cancel Create' message, otherwise don't.
IF CreateMode THEN
DeleteRecord := CONFIRM(Text_ManditoryField + '\' + FldList + '\' + Text_CancelCreate, FALSE)
ELSE BEGIN
DeleteRecord := FALSE;
MESSAGE(Text_ManditoryField + '\' + FldList, FALSE);
END;
// Return a 'delete' status when deleting, or a 'return' status to stay on the record.
IF DeleteRecord THEN
CompletionStatus := 'delete'
ELSE
CompletionStatus := 'return';
END;
END;
RecRef.CLOSE;`
Step 2:
- On the card you want to check for mandatory fields, in my case the Customer card, I added a function to call the validation function in the codeunit described above. I also added logic to the
OnQueryClosePage trigger to call my local function. This all worked fine, as the user could not close the Customer card without completing the mandatory fields or cancelling the create of the customer, except if the user were to use Ctrl+PgUp or Ctrl+PgDn, which took them off the record. The trick was putting the the correct logic in the OnNextRecord trigger so that the validation was executed and the Ctrl+PgUp or Ctrl+PgDn still functioned (note: I found this bit somewhere on mibuso, many thanks!). Logic follows:
OnNextRecord(...)
IF CheckManditoryFields = TRUE THEN BEGIN
Customer := Rec;
CurrentSteps := Customer.NEXT(Steps);
IF CurrentSteps <> 0 THEN
Rec := Customer;
EXIT(CurrentSteps);
END;
OnQueryClosePage(...)
EXIT(CheckManditoryFields);
CheckMandatoryFields() ExitValue : Boolean
// Check for manditory fields on this table. If there are missing manditory
// fields, the user can cancel this create, in which case, a 'TRUE' value is
// returned and we'll delete this record.
ExitValue := TRUE;
IF Rec."No." <> '' THEN BEGIN // This is blank if user quits immediately after page starts.
CompletionStatus := HHValidation.CheckManditoryFields(18,Rec."No.",CreateMode);
IF (CompletionStatus = 'delete')
AND (CreateMode = TRUE) THEN // User cancelled create (not edit), delete the record and exit.
Rec.DELETE(TRUE)
ELSE
IF CompletionStatus = 'done' THEN // User completed manditory fields, OK to exit.
ExitValue := TRUE
ELSE
ExitValue := FALSE; //User did not complete manditory fields and wants to return and add them.
END;
I think that's about it. The details of the custom table are really up to how you want to code it. The validation code unit can be what you want it to be. Using a table allows the mandatory fields to added or removed without changing any logic, and this "generic" validation logic could be put on any page. The key is the two triggers on the card and having a common validation routine to call.
I used this code on a form (classic client) but there is one error in the OnNextRecord code.
OnNextRecord(...)
IF CheckManditoryFields = TRUE THEN BEGIN
Customer := Rec;
CurrentSteps := Customer.NEXT(Steps);
IF CurrentSteps <> 0 THEN
Rec := Customer;
EXIT(CurrentSteps);
END;
You should also cover the situation where CheckMandatoryFields returns FALSE. Otherwise when I request the next record it shows me an empty record.
It should be like this:
OnNextRecord(...)
IF CheckManditoryFields = TRUE THEN BEGIN
Customer := Rec;
CurrentSteps := Customer.NEXT(Steps);
IF CurrentSteps <> 0 THEN
Rec := Customer;
EXIT(CurrentSteps);
END ELSE
EXIT(Steps);
There is another error in the OnNextRecord function:
OnNextRecord(...)
IF CheckManditoryFields = TRUE THEN BEGIN
Customer := Rec;
CurrentSteps := Customer.NEXT(Steps);
IF CurrentSteps 0 THEN
Rec := Customer;
EXIT(CurrentSteps);
END ELSE
EXIT(Steps);
The filters set on the sourcetable of the page (or form) are not copied to the record on which the steps are taken. So you can navigate to a record that is not in your filterset.
Instead assigning the Rec to the Customer, you should copy it:
OnNextRecord(...)
IF CheckManditoryFields THEN BEGIN
Customer.COPY(Rec);
CurrentSteps := Customer.NEXT(Steps);
IF CurrentSteps 0 THEN
Rec := Customer;
EXIT(CurrentSteps);
END ELSE
EXIT(Steps);
Try using this code from the page trigger
OnQueryClosePage(CloseAction : Action None) : Boolean
Var
Begin
Rec.TESTFIELD(FieldName);
End;