Is there any way we can use DateTime.TryParse in U-SQL WHERE condition?
I am creating a stored procedure in Azure U-SQL catalog.
Simple U-SQL script supports C# functions.
For stored procedure, the script is not adding any assembly reference to my custom C# code OR if adding it's not being used while calling the stored procedure.
Yes this is possible using in-line functions. This article shows how to do that. Here is a simple example:
#input = SELECT *
FROM (
VALUES
( (int)1, (string)"1/1/2017" ),
( (int)2, (string)"1/2/2017" ),
( (int)3, (string)"bad date" )
) AS x ( rn, someString );
// inline function example
#output =
SELECT *
FROM
(
SELECT *,
(
(Func<string, DateTime?>)
(dateString => // input_paramater
{
DateTime dateValue;
return DateTime.TryParse(dateString, out dateValue) ? (DateTime?)dateValue : (DateTime?)null;
}
)
) (someString) AS someDate
FROM #input
) AS x
WHERE someDate IS NOT NULL;
OUTPUT #output TO "/output/output.csv"
USING Outputters.Csv(quoting:false);
If you want to use the assembly you have created as a U-SQL Class project and registered then you can just reference it in the stored procedure using REFERENCE ASSEMBLY:
DROP PROCEDURE IF EXISTS dbo.usp_testCleanDate;
CREATE PROCEDURE dbo.usp_testCleanDate()
AS
BEGIN
REFERENCE ASSEMBLY USQLCSharpProject1;
#input = SELECT *
FROM (
VALUES
( (int)1, (string)"1/1/2017" ),
( (int)2, (string)"1/2/2017" ),
( (int)3, (string)"bad date" )
) AS x ( rn, someString );
#output =
SELECT *,
USQLCSharpProject1.Class1.tryParseDate(someString) AS x
FROM #input;
OUTPUT #output
TO "/output/output.csv"
USING Outputters.Csv(quoting : false);
END;
Using Function dt_TryParse_USQL
Using above code-behind and calling function. Function consumes a string and attempts to convert the string to a DateTime value using DateTime.TryParse. Using the Code-Behind above.
#employees =
SELECT * FROM
( VALUES
(1, "Noah", "2/16/2008"),
(2, "Sophia", "2/16/2008 12:15:12 PM"),
(3, "Liam", "16/02/2008 12:15:12"),
(4, "Amy", "2017-01-11T16:52:07"),
(5, "Justin", "")
) AS T(EmpID, EmpName, StartDate);
#result =
SELECT
EmpID,
EmpName,
ReferenceGuide_Examples.MyClass.dt_TryParse_USQL(StartDate) AS validated_StartDate
FROM #employees;
OUTPUT #result
TO "/Output/ReferenceGuide/DDL/Functions/dt_TryParse_USQL.csv"
USING Outputters.Csv(outputHeader: true);
https://msdn.microsoft.com/en-us/azure/data-lake-analytics/u-sql/u-sql-functions
Additional information: Click here
To answer this part of the question:
For stored procedure, the script is not adding any assembly reference to my custom C# code OR if adding it's not being used while calling the stored procedure.
U-SQL Functions and Procedures carry their own static context and do not inherit the static name context from the invocation context. That allows to understand the semantics of the function/procedure independently from where it is being called.
Thus in order to refer to assembly code, you will need to register the assembly in the catalog and explicitly reference it inside the procedure with REFERENCE ASSEMBLY. Code-behind is not meant to be used within a procedure (since the procedure is stored for future use).
Related
Hi I am working on a web app that uses postgres and some of the sql is in stored procedure/functon. If a function returns a cursor, how can we retrieve and process the resultset in nodejs? I am using pg (node-postgres). Following is the code for the test procedure that I would like to call from nodejs code.
drop table if exists tmp;
create table tmp
(
x integer
);
drop function if exists t1;
create or replace function t1( p_value integer)
returns refcursor
language plpgsql
as $$
declare
ref refcursor;
begin
--insert into tmp(x) values(p_value);
open ref for select x from tmp;
return ref;
end
$$;
This is not how this is done in Postgres. Change it to a set-returning function:
create or replace function t1(p_value integer)
returns table (x integer) --<< adjust here for the real column list
language sql
as $$
insert into tmp(x) values(p_value)
returning x; --<< adjust here for the real column list
$$;
Then use it as part of a SELECT statement:
select *
from t1(42);
Obviously the 42 can be a parameter from your programming language.
In MariaDB I have a table that looks as follows:
CREATE TABLE `REFERENCE_MANAGEMENT_REQUESTS` (
.. stuff ..
UNIQUE KEY `REFERENCE_MANAGEMENT_REQUESTS_key_UN` (`rmr_key`),
.. more stuff ..
)
From this, jOOQ generates:
public static Index REFERENCE_MANAGEMENT_REQUESTS_REFERENCE_MANAGEMENT_REQUESTS_KEY_UN = Internal.createIndex("REFERENCE_MANAGEMENT_REQUESTS_key_UN", ReferenceManagementRequests.REFERENCE_MANAGEMENT_REQUESTS, new OrderField[] { ReferenceManagementRequests.REFERENCE_MANAGEMENT_REQUESTS.RMR_KEY }, true);
If I than do dslContext.ddl(schema) it generates this:
create table REFERENCE_MANAGEMENT_REQUESTS (
.. stuff ..
constraint KEY_REFERENCE_MANAGEMENT_REQUESTS_REFERENCE_MANAGEMENT_REQUESTS_key_UN unique (rmr_key)
)
which results in:
java.sql.SQLException: Identifier name 'KEY_REFERENCE_MANAGEMENT_REQUESTS_REFERENCE_MANAGEMENT_REQUESTS_key_UN' is too long.
Is there a way to modify the behaviour of either the generator (have it generate a shorter constant name) or the ddl function (have it use the actual name rather than the variable name)?
edit
oops.. not read it carefully enough. The actual error mentions this one:
public static final UniqueKey<ReferenceManagementRequestsRecord> KEY_REFERENCE_MANAGEMENT_REQUESTS_REFERENCE_MANAGEMENT_REQUESTS_KEY_UN = Internal.createUniqueKey(ReferenceManagementRequests.REFERENCE_MANAGEMENT_REQUESTS, "KEY_REFERENCE_MANAGEMENT_REQUESTS_REFERENCE_MANAGEMENT_REQUESTS_key_UN", ReferenceManagementRequests.REFERENCE_MANAGEMENT_REQUESTS.RMR_KEY);
Is it possible to use interfaces with objects in plsql?
For example say I have a bunch of objects and want to sort them by date with a generic function. Could I have something like the following?
create or replace interface DateInterface
(
member function get_date return date
)
/
create or replace type TypeA implements DateInterface
(
my_date date,
member function get_date return date
)
/
create or replace type body TypeA is
member function get_date return date is
begin
return my_date;
end;
end;
/
create or replace type dateTable as table of DateInterface;
/
function EarliestDate (dates dateTable) returns date is
l_earliestDate date;
begin
l_earliestDate := dates(1);
for i in dates.first .. dates.last
loop
if l_earliestDate.get_date > dates(i).get_date then
l_earliestDate := dates(i);
end if;
end loop;
return l_earliestDate;
end;
I know I could have them inherit a class, but is there anything for doing this with an interface which would be more flexible?
Oracle supports interfacing external sources like Java and C languages within its procedures and functions using the LANGUAGE clause in them. Implement the date sorting logic of the objects in a procedure or a function and interface with other programming languages.
For reference, see Oracle's documentation
I'm late to the party but Oracle has sort of OO support now in PLSQL:
https://docs.oracle.com/en/database/oracle/oracle-database/18/adobj/inheritance-in-sql-object-types.html#GUID-A5FE7A3B-7C1C-430A-8095-76AE955119C9
You have inheritance etc. with that. So you could do sort of an interface for PLSQL Object Type Objects
But it comes with problems. Eg. storing in tables.
See https://oracle-base.com/articles/8i/object-types
This thread gives a number of ways to provide a parameter to a stored procedure.
None of them are working for me.
This works:
this.PayrollContext.Database.SqlQuery<CSRRateEntity>("ord_getCSRRate #csr_num = '4745', #ord_pay_period_id = 784").ToList();
This does not:
return this.PayrollContext.Database.SqlQuery<CSRRateEntity>("Exec ord_getCSRRate #csr_num, #ord_pay_period_id",
new SqlParameter("csr_num", "4745"),
new SqlParameter("ord_pay_period_id", 784)
).ToList();
The Error message is that parameter is not supplied.
Have tried all the variations I can think of and still get that same error message.
This is using Code First, so no import is required. The SP is found, it is just missing the parameters.
Did you import the stored procedure into the edmx?
In the implementation that we have for the stored procedure it creates parameters like this:
var inputIdParameter = inputId.HasValue ?
new ObjectParameter("InputId", inputId) :
new ObjectParameter("InputId", typeof(int));
The result of the stored procedure function is given like this
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<T>("[SP_NAME]", inputIdParameter);
The solution turned out to be to change the order of the parameters in the stored procedure so that optional parameters come after the required parameters (like in c#).
Works:
ALTER procedure [dbo].[ord_GetCSRRate]#ord_pay_period_id int,#csr_num varchar(10) = null, #csr_id int = null, #update_csr_pay_flag bit = 0
Does not work:
ALTER procedure [dbo].[ord_GetCSRRate]#csr_num varchar(10) = null, #ord_pay_period_id int, #csr_id int = null, #update_csr_pay_flag bit = 0, #recursion_flag bit = 0
Here is what I am working with:
CREATE OR REPLACE PROCEDURE SPROCLABPROCEDURE (Dept in VARCHAR2 DEFAULT
'Administration', 'Marketing', 'Purchasing', 'Human Resources', 'Shipping', 'IT',
'Public Relations', 'Sales', 'Executive', 'Finance', 'Accounting',
Mgr in VARCHAR2 DEFAULT NULL) AS
vManager Varchar2(30) := Mgr;
vDepartment Varchar2(30) := Dept;
I want the default values to be that entire list of strings. Later in my code, I want the option to be able to specify a few managers, or a few departments, or not input anything, so that the entire list is returned:
WHERE m.first_name ||' ' || m.last_name IN (vManager) -- NULL if I don't input anything
OR d.department_name IN (vDepartment) -- All departments if I don't input anything
When I call the function, and don't input anything, I'm expecting to return all possible rows. That is the desired effect.
In order to be able to pass a list of strings as a parameter you should change the parameter to a list.
CREATE OR REPLACE TYPE t_departments IS TABLE OF VARCHAR2(30);
And then create your procedure based on that new type:
CREATE OR REPLACE PROCEDURE SPROCLABPROCEDURE (Dept IN t_departments DEFAULT t_departments('Administration', 'Marketing', 'Purchasing', 'Human Resources', 'Shipping', 'IT','Public Relations', 'Sales', 'Executive', 'Finance', 'Accounting'), Mgr IN VARCHAR2 DEFAULT NULL) AS
Later you could use MEMBER OF instead of IN to check if a certain value is in the table:
...
WHERE d.department_name MEMBER OF Dept
...
Alternatively, if you can't change the type of the procedure parameters, you could just use variables:
CREATE OR REPLACE PROCEDURE SPROCLABPROCEDURE (Dept IN VARCHAR2 DEFAULT NULL, Mgr IN VARCHAR2 DEFAULT NULL) AS
TYPE t_departments IS TABLE OF VARCHAR2(30);
v_all_departments t_departments := t_departments('Administration', 'Marketing', 'Purchasing', 'Human Resources', 'Shipping', 'IT','Public Relations', 'Sales', 'Executive', 'Finance', 'Accounting');
vManager VARCHAR2(30);
vDepartment t_departments;
BEGIN
IF Dept IS NULL THEN
vDepartment := v_all_departments;
ELSE
vDepartment := t_departments(Dept);
END IF;
...
WHERE d.department_name MEMBER OF vDepartment
...
END;
I think something is unclear here...
First, this is a procedure - not a function, therefor it will not return a thing.
A varchar is not an array.
When you are getting or returning a varchar2 - there is only one possible string to pass back and forth... If you want to use a list - you should check the array types PL/SQL offers.
http://docs.oracle.com/cd/A97630_01/appdev.920/a96624/05_colls.htm
Third - if you have constant values, in a database the place for it is within a table, not as constants in a procedure.
I would recommend you to check out Temporary tables - they're a great data facilitator for "within session" communication for a list that you would like to return. http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:5824706700346810645
These would be a great "in session"/"in connection" joins, like the one you described above (select ... where last_name in (select manager from temptable) for example).
Another thing - using the last name for identifying records in the DB is not the way you wanna go. You can use unique identifiers for that, and foreign keys. (if you are unfamiliar with the terms - What are database constraints? .
If I did not answer your question (or pointed you out to the answer) - please clarify your question, since I am not sure (probably as many others) what exactly you want to do (logically).
It's a quite unclear what you're asking but here is a minimal example how you can pass a list of values that can be used as a part of a SQL query to a PL/SQL subprogram:
-- SQL type so that can be used in SQL context (the select-statement)
create or replace type strlist_t is table of varchar2(4000);
/
create or replace procedure foo(p_owners in strlist_t default strlist_t('JANI')) is
begin
for i in (select * from all_tables
where owner in (select * from table(p_owners)))
loop
dbms_output.put_line(i.owner || '.' || i.table_name);
end loop;
end;
/
show errors
begin
-- define your own criteria
foo(strlist_t('SYS', 'JANI'));
-- use the default criteria
foo;
end;
/
Hope this helps !