Stored Procedure vs User Defined Function for Error Handling - tsql

My ERP database uses non-nullable datetime fields. However, it enters '' for the datetime when one isn't available and returns ‘1900-01-01 00: 00: 00.000’ as the value.
I want to suppress the 1900 dates while stripping the Date only from the Datetime field. I created the following UDF to do that:
CREATE FUNCTION ExtractDate(#DirtyDate DATETIME)
RETURNS VARCHAR(10) AS
BEGIN
DECLARE #CleanDate VARCHAR(10)
SELECT #CleanDate =
CASE
WHEN #DirtyDate = '' THEN ''
ELSE CONVERT(VARCHAR(10), #DirtyDate, 101)
END
RETURN #CleanDate
END
This works, but I wanted to add error handling in case a user used it on something other than a datetime field. After some Googling, I found out that this isn't possible with UDF.
However, if I write this as a stored procedure, would I still be able to call it in a select statement? Can someone point me in the right direction?

No, you can't call a stored proc in a select statement.
I applaud your ambition in wanting to include error handling, but your best bet is to check for that on the app side - don't allow people to use the function on non-date fields.

Related

Changing the format of my parameter specifically

in my Pentaho Data Integration program I enter a parameter DATE, e.g. 2016-03-15 (or differently, doesn't matter for me).
Now i want to use this parameter in a Call DB Procedure step, so i need the parameter in the format PL/SQL uses it. The PL/SQL Procedure looks like this: start_test(key_date date, name varchar2)
I have tried to solve it with the select values step but it didn't work so far...
What do i need to change so my parameter works with Call DB Procedure?
Thanks.
I'm not familiar with Pentaho so I'm not sure what is the context you'll call a PL/SQL procedure but I hope you'll find the following helpful.
date is a native Oracle data type. If you have a string presenting a date you have to convert it to a "real" date with to_date function:
begin
start_test(
key_date => to_date('2016-03-15', 'YYYY-MM-DD')
,name => 'a clever test name'
);
end;
The second to_date parameter is a format model that have to match the date string (the first parameter).

Oracle stored procedure an INTO clause is expected in this SELECT statement

I am having a stored procedure mentioned below.
create or replace
PROCEDURE example(
in_start_date IN VARCHAR2,
in_svc_provider IN a_message.msg_service_provider%type,sell OUT number)
IS
BEGIN SELECT COUNT(*) as sell
FROM a_message b1 WHERE TO_CHAR(b1.msg_when_created,'YYYY-MM-DD') = in_start_date
AND b1.msg_trans_type = 'SELL'
AND b1.msg_service_provider = in_svc_provider;
end;
While executing the stored procedure I am getting following error.
Error(11,1): PLS-00428: an INTO clause is expected in this SELECT statement
Can you please provide me the resolution for this issue.while executing the same command in sql it is working fine but in stored procedure compilation error is occurring it means in stored procedure INTO replacing AS will give the same output please clarify.
The error message is fairly self-explanatory; the PL/SQL version of a SELECT requires an INTO clause so the result of your query has somewhere to go. You already have an OUT parameter to put the value into:
create or replace
PROCEDURE example(
in_start_date IN VARCHAR2,
in_svc_provider IN a_message.msg_service_provider%type,
sell OUT number)
IS
BEGIN
SELECT COUNT(*) INTO sell
FROM a_message b1
WHERE TO_CHAR(b1.msg_when_created,'YYYY-MM-DD') = in_start_date
AND b1.msg_trans_type = 'SELL'
AND b1.msg_service_provider = in_svc_provider;
end;
The SELECT is now INTO your OUT parameter, and its value will be available to whoever calls your procedure.
This only works if your query will always return exactly one row. If it doesn't return anything then you'll get a no-data-found exception; if it returns more than one row you'll get a too-many-rows exception. And you need to have a variable for each column your query returns - only one in this case. You can also declare a local variable (between IS and BEGIN) to hold temporary values that you will manipulate within the procedure, but you don't need that here either.
When you compiled your procedure it would have said it compiled with warnings, because of that syntax error. If you created it in SQL*Plus or SQL Developer, and maybe some other tools, you could have seen the error straight away by issuing the command show errors, or at any time by querying the user_errors view. When you called the procedure it was invalid and was automatically recompiled, which just regenerated the same error as nothing had changed; that's when you saw the PLS-00428 message. It's better to look for errors at compile time than wait for recompilation at execution time.
Incidentally, it's generally better to convert a fixed value into the data type used by your table, rather than the other way round. When you do this:
WHERE TO_CHAR(b1.msg_when_created,'YYYY-MM-DD') = in_start_date
... every column in your table has to have its msg_when_created DATE value converted to a string to be compared to the in_start_date string, which would prevent an index on that column being used. It's preferable to do:
WHERE b1.msg_when_created = TO_DATE(in_start_date, 'YYYY-MM-DD')
or if your column has a time component:
WHERE b1.msg_when_created >= TO_DATE(in_start_date, 'YYYY-MM-DD')
AND b1.msg_when_created < TO_DATE(in_start_date, 'YYYY-MM-DD') + INTERVAL '1' DAY
It would be even better to make your caller convert the value to a DATE so you don't have to worry about matching a passed format:
...
in_start_date IN a_message.msg_when_created%TYPE,
...
WHERE b1.msg_when_created >= TRUNC(in_start_date)
AND b1.msg_when_created < TRUNC(in_start_date) + INTERVAL '1' DAY
use into function
example: select count(*) into cnt_length from Table

Error catching a function error in TSQL

I am working with a SQL Server 2005 database table that is currently storing dates as varchars. This is outside of my control. For ease of reporting, I would like to create a view that converts these varchar dates to datetime fields.
The varchar dates are formatted for the most part, except for the occasional typing error.
DateString
----------
2001/01/02 -- most of the fields
2002/0601 -- typo, missing slash between month and day
2004/02/30 -- typo, no 30th of February
Because the dates are already formatted, I'm using the cast function to convert them to datetime.
cast(DateString as datetime)
The problem is when the cast function comes across an incorrect date, the query ends in error.
Is there are way to wrap just the function in a try...catch block? I see it is possible to wrap an entire query in a try...catch block, but the full query has multiple casts that must be done, and any combination could have typing errors.
I would use the built-in ISDATE() function. You can then write a CASE statement within your SELECT statement to either return the parsed date or either a null or some other result. Or, you can place it directly in the WHERE clause to only return those rows where there is a valid date.
A possible solution with the ISDATE() function in the SELECT list may look like:
select case
when ISDATE(DateString) = 1 then cast(DateString as datetime)
else null --or other error result
end as CastedDate
from TableName
If the logic is complicated (e.g. you want to try to correct the errors, such as missing slash, or nearest day in the case of 30th FEB), then one option is to create a user-defined function that contains the date parsing logic (string to date) logic in it, complete with error handling (e.g. scenario checking before casting). Then in the query, call the user defined function.
An outline:
CREATE FUNCTION udf_ParseDateString
(
#DateString nvarchar(20)
)
RETURNS DateTime
AS
BEGIN
DECLARE #returnDateTime datetime
-- Do any string checking, and date casting here
-- #DateString -> #returnDateTime
return #returnDateTime
END
Note that you won't be able to use TRY-CATCH in a UDF.
Alternatively, if your logic is simple, you could just use a cast inline, as suggested here.
SET DATEFORMAT ymd;
-- Incorporate this into query.
SELECT CASE WHEN ISDATE(#yourParameter) = 1
THEN CAST(#yourParameter AS DATETIME)
ELSE YourDefaultValue
END
If you were using SQL Server 2012, you could use the TRY_CAST function.

t-sql conditional date processing

I have a stored procedure which returns data used in a report. There are numerous paramters the user can specify, two of which are a start and end date. I can use a WHERE create_date BETWEEN #arg_start AND #arg_end statement to filter on the dates.
What I dont know how to do is to handle the situation where the user doesnt supply any dates. CASE doesnt support anything like WHERE create_date = CASE #arg_start WHEN NULL THEN create_date ELSE BETWEEN #arg_start AND #arg_end.
I've done a lot of research on google, msdn, and here and I haven't find out to handle conditional null datetime processing. Although I know its bad form, I can pass programatically pass in a magic date, such as 1/1/1900, to test instead of a null, but that doesn't really help in conditional date processing.
Make it a multi-part condition:
WHERE
(#argstart IS NULL AND #argend IS NULL)
OR (#argend IS NULL AND create_date > #Argstart)
OR (#argstart IS NULL AND create_date < #argend)
OR (Createdate BETWEEN #Argstart AND #Argend)
Something like this:
where (create_date >= #arg_start or #arg_start is null) and
(create_date <= #arg_end or #arg_end is null)
If you are on SQL Server 2008 you should use OPTION (RECOMPILE). Ref: Dynamic Search Conditions in T-SQL
Version for SQL 2008 (SP1 CU5 and later).
Otherwise you might be better of using the answer provided by JNK.
I would make the default values for the stored procedure parameters the "magic dates":
CREATE PROC usp_report
#StartDate datetime = '1900-01-01',
#EndDate datetime = '9999-12-31'
AS
SELECT *
FROM MyTable
WHERE DateField BETWEEN #Startdate AND #EndDate
In your application, if the user has not specified a date, don't pass that parameter to the stored proc.
This would keep your application code clean, and give you the data you need.

make a column in sybase default to the current date/time of row insertion

I have a sybase 15 DB and for one of my tables, I want to make a column default to the current date/time of the row insert. Is this possible?
In a sybase text, the following is said:
ALTER TABLE sales_order
MODIFY order_date DEFAULT CURRENT DATE
On my DB this doesn't do anything, as CURRENT DATE is not recognized.
using getDate() is a valid solution, you must have had a syntax error. Try it like this:
create table test_tbl (
date_data DATETIME default getDate() NOT NULL
)
Try using getDate() instead
... DEFAULT GETDATE() is correct. the case is irrelevant; mixed case may indicate a Java method, but it is a straight TSQL Function. Please post the exact error msg if you want further assistance.
Also, the ALTER TABLE method sets the Default for future INSERTS; if you want the existing data changed, you need to UPDATE (good for small tables) or unload/reload the table (demanded for the large).
Watch the NULL/NOT NULL: you do not want to change that without understanding. Again, the existing/future issue needs address. NOT NULL prevents NULL being explicitly passed as an INSERT VALUE.
CURRENT_DATE is a SQL standard that isn't universally adopted.
As noted elsewhere the getdate() T-SQL function should be used instead.