Identifying the Weekday for an Order Date in PL/SQL as stored function - sql

Code:
CREATE OR REPLACE FUNCTION DAY_ORD_SF
(
P_DATE_CREATED IN bb_basket.dtcreated%type
)
RETURN DATE AS
lv_date_created bb_basket.dtcreated%type;
BEGIN
SELECT to_char(to_date(P_DATE_CREATED,'yyyy-mm-dd'),'DAY') DAY_CREATED
INTO lv_date_created
FROM BB_BASKET
WHERE lv_date_created <= sysdate
ORDER BY lv_date_created ASC;
RETURN lv_date_created;
END DAY_ORD_SF;
/
SELECT IDBASKET, dtcreated date_created, to_char(DTCREATED,'DAY') DAY_CREATED, day_ord_sf(dtcreated) weekday_created
FROM BB_BASKET
order by DTCREATED asc;
This is my stored function I am working on as a task to practice stored function. I am really close to finishing this problem, but I am getting a no data found error. I'm not really understanding this error because when I run the code by itself it works. Basically this function is suppose to taking a date and return a varchar2 data type. I did have the "to_date(…,'yyyy-mm-dd'),.." gone before adding at that piece of code into the function.
First part of this task is to create a SELECT statement that lists the basket ID and weekday for every basket, and the second part of the task is to create a SELECT statement, using a GROUP BY clause to list the total number of baskets per weekday. Based on the results, what’s the most popular shopping day? Also I forgot to ask, if you can tell me why I am getting the "No data found" error that would be much appreciated!
Thanks for helping me out!

Well, there seems to be mutiple issues here.
Lets start with no data found problem. In case you use INTO within select statment and select returns no rows, you get an no data found exception. This can be handled via anonymouse begin end block with exception handler inside, but I believe this is not the case. As example:
declare
v_value number;
begin
select null
into v_value
from dual
where 1=2;
exception
when NO_DATA_FOUND then
null; -- Ignore exception and continue
end;
Condition 1=2 is never met and therefore the select always returns no rows, this will always produce no data found error. With exception handler we decide what to do next. Null will do nothing in this example.
Back to your function, your condition is if variable lv_date_created is less or equal to current date then do something. This will never work as lv_date_created will be at the moment of execution equal to null. It was just declared in your function and then used in your select. This will always lead to false and therefore select will always return no rows and no data found exception.
You also mentioned that you want the function to return varchar2 but your definition sais it returns date. Also variable lv_date_created is of type date and this is variable that is returned and you fill it with varchar2 value so apparently Oracle is doing some uncontroled conversion of the value of this is not throwing an exception about expected datatypes.
Also condition lv_date_created <= sysdate may indicate that select will find mutiple values and with INTO, this will cause too many rows exception if mutiple rows are found.
Now lets get to fixing this function. The main question is if you need to slect something in it or not. Selecting something like that usualy is used to check if entry in table exists and no data found exceptions would tell us that entry does not exist. If it is a general function to be used on mutiple places in your DB then I think select is not needed. I will include both solutions as example.
Note for this first one that you should no longer provide dtcreated colume on calling it but idbasket.
CREATE OR REPLACE FUNCTION DAY_ORD_SF
(
P_IDBASKET IN bb_basket.idbasket%type
)
RETURN VARCHAR2 AS
lv_date_created VARCHAR2(240);
BEGIN
SELECT to_char(dtcreated,'DAY') DAY_CREATED
INTO lv_date_created
FROM BB_BASKET
WHERE IDBASKET = P_IDBASKET;
RETURN lv_date_created;
END DAY_ORD_SF;
/
Or
CREATE OR REPLACE FUNCTION DAY_ORD_SF
(
P_DATE_CREATED IN bb_basket.dtcreated%type
)
RETURN VARCHAR2 AS
BEGIN
RETURN to_char(P_DATE_CREATED,'DAY');
END DAY_ORD_SF;
/

Related

No data found error in PL/SQL with the PROCEDURE

I am new with PLSQL and I have issue with this procedure.
I don't know what the error mean at the same time I am sure the table and data are created successfully.
the procedure should receive the start and end date with the invoice number to show the details
create or replace PROCEDURE Invoicedetails (Fromdate IN DATE , Todate IN DATE , InvoiceNum NUMBER)
IS
INV_info invoicetable%ROWTYPE;
BEGIN
SELECT *
INTO INV_info
FROM invoicetable
WHERE InvoiceNum = INV_info.InvoiceNum AND INV_info,InvoiceDate betwen Fromdate And Todate;
dbms_output.put_line('ID:'|| INV_info.InvoiceNum);
dbms_output.put_line('Amount:'|| INV_info.Invoiceamount);
dbms_output.put_line('Date:'|| INV_info.InvoiceDate);
END Invoicedetails;
When I call the procedure like this
BEGIN
Invoicedetails('01-JAN-2020','05-JAN-2020',200651)
END;
Error report
ORA-01403 :no data found
ORA-06512 : at "APPS.Invoicedetails",line 5
ORA-06512 : at line 2
01403. 00000 - "no data found"
If you say you are new then you have done a good job.
Let's dig into the problem,
If you are learning then put into TODO list, the next topic about exception in PLSQL and how to handle.
The error you get say ORA-01403 :no data found which is self explanatory and mean we are searching for something and whatever code you have written didn't find it as expected which leads us to the select statement,
SELECT *
INTO INV_info
FROM invoicetable
WHERE InvoiceNum = INV_info.InvoiceNum
AND INV_info,InvoiceDate betwen Fromdate And Todate;
In the above if you see,
First small problem is syntactical which is INV_info,InvoiceDate which should be INV_info.InvoiceDate (this is anyway not correct as per the expectations of result which I will clarify below)
Second and most important problem is you are trying to compare the value of InvoiceNum with the rowtype variable which is InvoiceNum = INV_info.InvoiceNum and you have to understand here INV_info.InvoiceNum is a variable and doesn't hold any value at this very time.
So you should compare the table value with the input you provided via parameter as WHERE invoicetable.InvoiceNum = invoiceNum. Left side is the table column and right side is the parameter you passed.
Similarly the condition AND INV_info,InvoiceDate betwen Fromdate And Todate should change to AND invoicetable.InvoiceDate betwen Fromdate And Todate.
Having said all these there are some things you also need to consider interms of naming convention of variables and also usage of alias for table. (Which can be seen what changes I made to the procedure below)
Accumulating all points the procedure can be further modified as,
create or replace procedure invoicedetails
(
p_fromdate in date
, p_todate in date
, p_invoicenum number)
is
inv_info invoicetable%rowtype;
begin
select *
into inv_info
from invoicetable i
where i.invoicenum = p_invoicenum
and i.invoiceDate between p_fromdate and p_todate;
dbms_output.put_line('ID:'|| inv_info.invoicenum);
dbms_output.put_line('Amount:'|| inv_info.invoiceamount);
dbms_output.put_line('Date:'|| inv_info.invoicedate);
end invoicedetails;
/
Here is db<>fiddle for your reference. I have to do a little trick by calling dbms.output to print the result while calling the procedure which you don't need when you try in your machine
First thing out of the chute, you declare to input parameters as DATE, but then when you call the procedure you supply a CHARACTER STRING. Just because the input looks like a date to you does not mean that oracle interprets as a DATE. DATE is an internal, binary data type. Where will the input values actually originate? As per your example, you need to convert the input string to a DATE:
create or replace PROCEDURE Invoicedetails (Fromdate IN VARCHAR2 , Todate IN VARCHAR2 , InvoiceNum NUMBER)
IS
v_fromdate date;
v_todate date;
INV_info invoicetable%ROWTYPE;
BEGIN
v_fromdate := to_date(fromdate,'dd-Mon-yyyy');
v_todoate := to_date(todate,'dd-Mon-yyyy');
Then, in the rest of your code, reference v_fromdate and v_todate instead of your input parms.
As an aside, you should also develop the habit of being consistent in your coding style. Unlike some other rdbms products, oracle really doesn't support MixedCaseNames. (Well, you can jump through some hoops to force it to, but that is going against the grain and you really don't want to go there.) Instead of MixedCaseNames, the oracle standard is underscore_separated_names.
You need to:
Not name the procedure's arguments the same as columns in your table; it's confusing to debug and can confuse the SQL parser into comparing the column to itself rather than comparing the column to the parameter's argument.
Handle the NO_DATA_FOUND exception.
Handle the TOO_MANY_ROWS exception.
Using something like this:
CREATE PROCEDURE InvoiceDetails (
p_FromDate IN InvoiceTable.InvoiceDate%TYPE, -- Use the types from the table
p_ToDate IN InvoiceTable.InvoiceDate%TYPE,
p_InvoiceNum IN InvoiceTable.InvoiceNum%TYPE
)
IS
inv_info invoicetable%ROWTYPE;
BEGIN
SELECT *
INTO INV_info
FROM invoicetable
WHERE InvoiceNum = p_InvoiceNum -- Don't have the same variable name as the
-- column name. One practice is to prefix the
-- parameter names with p_ to distinguish
-- that they were passed from outside the
-- procedure.
AND InvoiceDate BETWEEN p_FromDate AND p_ToDate;
dbms_output.put_line('ID: ' || INV_info.InvoiceNum);
dbms_output.put_line('Amount: ' || INV_info.InvoiceAmount);
dbms_output.put_line('Date: ' || TO_CHAR( INV_info.InvoiceDate, 'YYYY-MM-DD' ) );
EXCEPTION
WHEN NO_DATA_FOUND THEN -- Handle the exception when no rows are found.
dbms_output.put_line('No Invoices exist.');
WHEN TOO_MANY_ROWS THEN -- Handle the exception when multiple rows are found.
dbms_output.put_line('Multiple invices exist.');
END InvoiceDetails;
/
So, if you have the table:
CREATE TABLE invoicetable (
invoicenum NUMBER(10,0),
invoiceamount NUMBER(17,2),
invoicedate DATE
);
and then execute your anonymous PL/SQL block:
BEGIN
Invoicedetails( DATE '2020-01-01',DATE '2020-01-05',200651);
END;
/
There will be no rows to match and the NO_DATA_FOUND exception will be raised and you get the output:
No Invoices exist.
If you then insert a row:
INSERT INTO invoicetable (invoicenum, invoiceamount, invoicedate )
VALUES ( 200651, 200, DATE '2020-01-04' );
and run the same anonymous PL/SQL block, you now get the output:
ID: 200651
Amount: 200
Date: 2020-01-04
and, if you insert a second row:
INSERT INTO invoicetable (invoicenum, invoiceamount, invoicedate )
VALUES ( 200651, 300, DATE '2020-01-05' );
and run the anonymous PL/SQL block again, you get the output:
Multiple invices exist.
db<>fiddle here

check if oracle function value given as a parameter exist in the table

My table looks like this
Teacher(ID, Name, Surname)
I want to give the user an output.
In case the id given as parameter to the function does not exist in the ID column in the table.
How can I handle this inside a function and give an output:
"The id asked is not present in the table"
Create or replace function subjects
(
code_value IN Teacher.ID % TYPE
)
RETURN NUMBER
IS
id_value NUMBER
BEGIN
SELECT id
INTO id_value
FROM TEACHER
WHERE ID = code_value
END
END subjects;
With a function you wrote, you can not - it returns a NUMBER while the result you want is a string (VARCHAR2).
There is a way - to write an exception handler which will be executed when select you wrote doesn't return anything as it'll raise NO_DATA_FOUND, so:
begin
select ...
exception
when no_data_found then
raise_application_error(-20000, 'The id asked is not present in the table');
end;
This will cause your program to stop (an error is raised, right?) so - if you want to move on, either
change return datatype or
switch to a procedure which will have an OUT parameter (or two - one for the ID, another for possible error message). Its (procedure's) drawback is that you can't use it in SELECT statements but you'll need a piece of PL/SQL code.

Setting up a stored procedure in Oracle

I'm working to create a stored procedure that takes input of an id and a start and end date, then returns trips that fall within that range. I've been looking over the oracle documentation and I think I'm close, but getting a few errors yet:
CREATE or replace PROCEDURE chg_per_aircraft
(p_aircraft_id IN RCC_AIRCRAFT.aircraft_id,
p_start_date IN date,
p_end_date IN date,
p_ttl_chg_per_acft OUT INTEGER)
AS
BEGIN
SELECT RCC_AIRCRAFT.aircraft_id,
SUM(RCC_CHARTER.distance * RCC_MODEL.charge_per_mile) ttl_chg
INTO
p_aircraft_id,
p_ttl_chg_per_acft
FROM RCC_AIRCRAFT
full join RCC_CHARTER
on RCC_CHARTER.aircraft_id = RCC_AIRCRAFT.aircraft_id
left join RCC_MODEL
on RCC_MODEL.model_code = RCC_AIRCRAFT.model_code
Where RCC_CHARTER.trip_date > p_start_date and RCC_CHARTER.trip_date < p_end_date
group by RCC_AIRCRAFT.aircraft_id;
SYS.DBMS_OUTPUT.PUT_LINE(ttl_chg);
end;
Your first error is the parameter definition:
p_aircraft_id IN RCC_AIRCRAFT.aircraft_id
should be
p_aircraft_id IN RCC_AIRCRAFT.aircraft_id%TYPE
But then you're selecting INTO p_aircraft_id, which is declared as an IN parameter, so you can't set it to a new value. Is that a variable you want to pass in, or a value you want to get out? It makes more sense as something the caller supplies along with the dates, but then you'd need to use it as a filter in the select statement. If there was more than one aircraft ID - likely if it's only restricted by date - then you'd get multiple results back, which would be a too_many_rows error anyway.
Your output will only be visible to a session that is set up to handle it, so that would perhaps make more sense for the caller to do; but in any case should be:
DBMS_OUTPUT.PUT_LINE(p_ttl_chg_per_acft);
... as ttl_chg only exists as a column alias, not a PL/SQL variable.
If you are passing in the aircraft ID, you might want something like this:
CREATE or replace PROCEDURE chg_per_aircraft
(p_aircraft_id IN RCC_AIRCRAFT.aircraft_id%TYPE,
p_start_date IN date,
p_end_date IN date,
p_ttl_chg_per_acft OUT INTEGER)
AS
BEGIN
SELECT SUM(RCC_CHARTER.distance * RCC_MODEL.charge_per_mile) ttl_chg
INTO p_ttl_chg_per_acft
FROM RCC_AIRCRAFT
JOIN RCC_CHARTER
ON RCC_CHARTER.aircraft_id = RCC_AIRCRAFT.aircraft_id
JOIN RCC_MODEL
ON RCC_MODEL.model_code = RCC_AIRCRAFT.model_code
WHERE RCC_CHARTER.trip_date > p_start_date
AND RCC_CHARTER.trip_date < p_end_date
AND RCC_AIRCRAFT.aircraft_id = p_aircraft_id
GROUP BY RCC_AIRCRAFT.aircraft_id;
-- just to debug!
DBMS_OUTPUT.PUT_LINE(p_ttl_chg_per_acft);
END;
/
I've also changed to inner joins as it doesn't seem useful to make them outer joins. This would also make more sense as a function than a procedure; though wrapping a single query in a stored program may be unnecessary anyway - though this looks like an assignment.

ORACLE PL/SQL Variable Function Scope - Need Explanation

I just tripped over an answer to a problem I was having with a PL/SQL variable not being recognized by a function and I was hoping someone could explain to me why my solution worked and what is happening "underneath the hood".
Background
As part of an optimization project, I am trying to collect metrics on individual SQL scripts within a Stored Procedure. The Stored Proc that I am dissecting has an In-type date parameter that I need to define in order to run each individual SQL Script:
CREATE OR REPLACE myStoredProc (DATE_IN DATE, ERROR_OUT OUT VARCHAR2)
IS
BEGIN
--Truncate Temp Tables
--6 Individual SQL Scripts
EXCEPTION
--Error Handling
END;
To run each script individually, I decided to just drop each SQL statement into a PL/SQL block and feed the DATE_IN parameter in as a variable:
DECLARE
DATE_IN DATE := TO_DATE('16-JUL-2014','DD-MON-RR');
BEGIN
--Place individual script here
END;
The Problem
This approach worked fine for a couple of the queries that referred to this DATE_IN variable but one query with a reference to an outside function which takes DATE_IN as a parameter started throwing an ORA-00904 error:
DECLARE
DATE_IN DATE := TO_DATE('16-JUL-2014','DD-MON-RR');
BEGIN
insert into temp_table
SELECT table1.field1,
table1.field2,
table2.fieldA,
MyFunction(table1.field1, DATE_IN) --This was the problem line
FROM
table1,
table2
WHERE EXISTS (inner query)
AND table1.keys = table2.keys
AND table2.date <= DATE_IN
END;
Solution
At the advice of another Developer, I was able to get around this error by adding a colon (:) in front of the DATE_IN variable that I was passing into the function so that the problem line read MyFunction(table1.field1, :DATE_IN). As soon as I did that, my error disappeared and I was able to run the query without issue.
I was happy for the result but the other Developer wasn't able to explain why it was needed, only that it was necessary to call any functions or other stored procs from a PL/SQL statement. I assume this has something to do with scope but I would like to get a better explanation as to why this colon was necessary for the function to see the variable.
Questions
I've tried to do a little research looking over Oracle documentation on parameters, variables, binding/declaring and constants but my research has only given me more questions:
After reading up on variables, I now question if that is the correct term for what I have been using (since I didn't actually use the VARIABLE command and I'm passing in a date - which is not an allowable data type). If my DATE_IN DATE := statement is not a variable, then what is it?
Why were the rest of my references to DATE_IN recognized by the compiler but passing the value to the function was out of scope?
What exactly is the colon (:) doing here? Is this turning that into a bind variable?
Thanks in advance. I appreciate any guidance you can provide!
----------------------------------EDIT--------------------------------------
I was asked to provide additional information. My Db version is 11G, 11.2.0.2.0. The query that I was able to reproduce this error is below.
DECLARE
EXTRACT_DT_IN DATE := TO_DATE('16-JUL-2014','DD-MON-RR');
BEGIN
--This begins the pre-optimized query that I'm testing
insert into AELI_COV_TMP_2_OPT
SELECT /*+ ordered use_nl(CM MAMT) INDEX (CM CSMB_CSMB2_UK) INDEX (MAMT (MBAM_CSMB_FK_I) */
CM.CASE_MBR_KEY
,CM.pyrl_no
,MAMT.AMT
,MAMT.FREQ_CD
,MAMT.HOURS
,aeli$cov_pdtodt(CM.CASE_MBR_KEY, EXTRACT_DT_IN)
FROM
CASE_MEMBERS CM
,MEMBER_AMOUNTS MAMT
WHERE EXISTS (select /*+ INDEX(SDEF SLRY_BCAT_FK_I) */
'x'
from SALARY_DEF SDEF
where SDEF.CASE_KEY = CM.CASE_KEY
AND SDEF.TYP_CD = '04'
AND SDEF.SLRY_KEY = MAMT.SLRY_KEY)
AND CM.CASE_MBR_KEY = MAMT.CASE_MBR_KEY
AND MAMT.STAT_CD = '00'
AND (MAMT.xpir_dt is null or MAMT.xpir_dt > EXTRACT_DT_IN)
AND MAMT.eff_dt <= EXTRACT_DT_IN;
--This ends the pre-optimized query that I'm testing
END;
Here is the error I'm encountering when trying to run an Explain Plan on this statement. I am able to get past this error if I remove reference to line 13 or I add a colon (:) to the EXTRACT_DT_IN on that line.
----------------------EDIT 2-------------------
Here is the function signature of aeli$.cov_pdtodt. (I've replaced the owner for security reasons).
CREATE OR REPLACE function __owner__.aeli$cov_pdtodt
(CASE_MBR_KEY_IN IN NUMBER, EXTRACT_EFF_DT_IN DATE)
RETURN DATE IS
PDTODT DATE;
Your anonymous block is fine as it is, as long as you execute the whole block. If you try to execute just the insert, or its select, as a standalone command then it will indeed fail with ORA-00904.
That isn't quite a scope problem, it's a context problem. You're trying to refer to a PL/SQL variable in an SQL context, and that is never going to work.
In a PL/SQL context this would work:
declare
some_var dual.dummy%type := 'X';
begin
insert into some_table
select dummy from dual where dummy = some_var;
end;
/
... because the insert has access to the PL/SQL some_var.
In an SQL context this will error:
select * from dual where dummy = some_var;
... because it's looking for a column called SOME_VAR, and there isn't one.
If you do this instead:
select * from dual where dummy = :some_var;
... the some_var is now a client-managed bind variable. If you execute that you'll either be prompted for the bind value, or given a not-all-variables-bound error, or bind-variable-not-declared, or similar, depending on your client.
If you only do an explain plan of that though, e.g. with
set auto trace traceonly explain
select * from dual where dummy = :some_var;
... then the bind variable doesn't necessarily have to be populated for the plan to be calculated. Some clients may still complain and want a bind value, but the parser would be OK with it - enough to produce a plan anyway. Though not able to take advantage of bind variable peeking or histograms etc.
For example, SQL Developer happily produces a plan for your original sample query if both references are turned into bind variables, just the insert ... part of the block is selected, and you press Explain Plan (F10).
I'm not sure what you read, but you're mixed up on a few things here.
Your DATE_IN is a variable. You don't need to type 'VARIABLE' anywhere to declare a variable, all you need is the name of the variable and the datatype.
All of the below are legitimate variables in PL/SQL (although poorly named).
variable_1 NUMBER;
variable_2 VARCHAR2(100);
variable_3 DATE;
It's hard to tell what you're doing in your code without seeing it all. Do you have two DATE_IN variables declared within the same block? Is DATE_IN the name of a column in your table?
If you have a column named DATE_IN in table1 or table2, that's likely your problem. Oracle doesn't know if you want to use your variable or your column, and it will always default to the column name. Your function would be expecting a DATE and receiving a column, hence the error.

Why is no_data_found ORA-01403 an exception in Oracle?

If the SELECT INTO statement doesn't return at least one row, ORA-01403 is thrown.
For every other DBMS I know this is normal on a SELECT.
Only Oracle treats a SELECT INTO like this.
CREATE OR REPLACE PROCEDURE no_data_proc IS
dummy dual.dummy%TYPE;
BEGIN
BEGIN
SELECT dummy
INTO dummy
FROM dual
WHERE dummy = 'Y';
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('Why is this needed?');
END;
END no_data_proc;
Why?
In my opinion you don't need this exception really. It is too much overhead.
Sometimes it is handy but you have to write a whole BEGIN, EXCEPTION, WHEN, END Block.
Are there any essential reasons I don't see?
The exception block is not needed, you might use it or not, depending on the context.
Here you are actively ignoring the exception (the procedure will return successfully) but most of the time if you're doing a SELECT INTO you want it to fail if it doesn't return a row, consider:
PROCEDURE update_employee_salary (p_empno) IS
l_salary NUMBER;
BEGIN
SELECT sal INTO l_salary FROM emp WHERE empno = p_empno FOR UPDATE;
/* do something with emp data */
END;
Here I want my function to fail if it is called with an empno that doesn't exist in the EMP table. I might catch the exception to raise a meaningful error message (with raise_application_error) but most of the time I'm happy with the ORA-01403.
In general, the only exceptions you should catch are the expected exceptions (i.e. this should not be the standard to catch all ORA-01403, or all exceptions for that matter).
But we still need to answer the question of "why is an exception thrown in the case where a SELECT has no data to be retrieved".
I believe this is done because it's a common situation which might otherwise be overlooked. Writing code as though it always expects to find data is a common thing to do, and if we were supposed to put in error checks such as
SELECT <something...>
IF SQLCODE = 100 THEN -- No data found
<no-data handler>
END IF
it is likely IMHO that the check for SQLCODE = 100 would be skipped frequently. Having an exception raised rams it right up your nose that A) an important condition (no data found) occurred, and B) NO ALLOWANCE WAS MADE FOR THIS. IMO having the PL/SQL engine raise an exception is better than having the program continue merrily on its way under the assumption that data was retrieved when in fact it wasn't, which can lead to all sorts of other-than-merry problems.
Share and enjoy.
You can try use MIN for avoid use EXCEPTION clause.
SELECT MIN(dummy)
INTO dummy
FROM dual
WHERE dummy = 'Y';
then dummy variable will be NULL
Because you are doing SELECT INTO which requires exactly one row (more rows would also be an error).
If you can have one or no row, you can use a cursor.
It is not the database's job to decide for you that a missing row is not an error, and just set the value to null.
You can also use the sql MAX or MIN functions. If no row is return then these functions will return a NULL.
For example:
Select MAX(column1)
Into variable
From Table
Where Column1 = 'Value';
The MAX function will return the Maximum value or if no row is returned then it will return NULL.
MAX function works it does not throws error ORA-01403 works when NULL is returned by select INTO
Because it's not clear what the PL/SQL engine should do - should it exit the block? Should it press on with NULL in the variable? What if in the next block you try to insert that into a NOT NULL column, how should it report the location of the error? Making it an exception forces you to be explicit about it.