Using a statically assigned application item as SQL in Oracle APEX - plsql

In my Oracle Apex 19.3 application I have a SQL statement that needs to be used on several pages and changes slightly based on the user that is logged in. So that I do not need to duplicate this code over and over on each page I generate this statement as an application item called: QUERY_BASED_ON_USER.
An application computation then statically sets it to SELECT j.* FROM table(pkg_jobstatus.report()) j WHERE j.id IN (:USERIDS)
(USERIDS is a separate application item)
I wish to use the application item QUERY_BASED_ON_USER as the sql statement for a table. When setting the data source to PL/SQL and using the following code,
BEGIN
return :QUERY_BASED_ON_USER;
END;
I get this error: PL/SQL function body did not return a value.
I tried debugging this by settings a static page region to: &QUERY_BASED_ON_USER. and it outputs the query correctly.
My assumption is that the code editor does not evaluate the application computation and thus it returns an empty string, which it then refuses to validate or save. But I do not know how to validate this or how to work around this.
How can I use the application item as the sql statement?

You need to set "Use Generic Column Names" to true, and specify the number of columns your query will return:
Then the query is not parsed until runtime, when the item value is available.

Related

Oracle APEX PL/SQL process to insert multi-select items into association table for m:m relationship failing silently

I am implementing a form on table that allows the end-user to create a new project. This form contains a shuttle that allows the user to select the disposal site(s)(1+) that the project pertains to. I would like to use the output of the shuttle values to populate an association table between projects and disposal sites which is a many to many relationship.
This is my approach so far:
Created an additional VARCHAR2(4000)in the projects table to store the shuttle output (called 'Shuttle'). The shuttle output in this column looks something like 'CA-AT-D109Z2:CA-AT-D115:CA-AT-D174Z2'.
Created a process to take separate based on ':' and then add the values to the association table using the PL/SQL code:
Declare
Cursor c_values
is
Select
t.column_value As disposal_sites
From
Table ( apex_string.split(:P28_SHUTTLE, ':') ) t
Where
t.column_value Is Not Null;
Begin
for c in c_values loop
insert into MP_MDB_PROJECT_2_DSITE (PROJECTIDFK,DISPOSALSITEIDFK)
values (:P28_PROJECTNUMBER,c.disposal_sites);
end loop;
End;
The process/code enters the values from the shuttle into the association table in a loop as expected for the the disposal site but remains blank for projectidfk (the key that is '1' in the 1:m relationship). The code doesn't throw an error so I am having trouble debugging.
I think perhaps the problem I am having is that project number is computed after submission based on the users selections.Therefore, when the process run it finds :P28_PROJECTNUMBER to be null. Is there a way to ensure the computation to determine :P28_PROJECTNUMBER takes places first and is then followed by the PL/SQL process?
All help appreciated
If the form you're implementing is a native apex form, then you can use the attribute "Return Primary Key(s) after Insert" in the "Automatic Row Processing - DML" process to ensure that the primary key page item contains inserted value for any processes execute after this process.
Just make sure the process that handles the shuttle data is executed after the DML process.

Cannot bind result of HTTPUtility method to session variables

I am using ASP.NET Web Forms. I am trying to bind some data from a previous page (including the URL and some specific figures stored in the URL) to session variables for use in a SQL insert statement to a SQL Server database.
An example of one of the assignments is below:
this.Session["URL"] = HttpUtility.ParseQueryString(Request.UrlReferrer.Query)["helpurl"];
The problem I am having is that on executing the SQL insert, the value does not seem to be present and the default value is recorded. SessionState is enabled. I am able to print the result of the HttpUtility method to a label, and I am also able to assign to session variables for a SQL statement if I assign them directly, eg:
this.session["Variable"] = Variable;
Any ideas why the result of the HttpUtility function may not be assigned to the session variable prior to the execution of the SQL insert statement?
It's ok - I placed the assignments inside an
if(!IsPostBack)
And they now work ok and are being recorded to the database. I also removed the 'this' keyword from them.
Thanks anyway

Object Not Found when ASP.NET app is trying to access a stored procedure using global temp table

I have an ASP.NET application accessing an Oracle 12 database. I have written a stored procedure using a global temp table to help.
The global temp table is created with 'ON COMMIT DELETE ROWS'.
Basically the stored procedure does the following:
Get some data. Add a char column. Insert to the global temp table.
Use a key (in each row) to call another stored procedure.
The stored procedure returns a 'Y' or 'N'.
The return value will be updated to the corresponding row in the global temp table.
Once done all rows, return like this: open refcursor for select * from global_temp_table
I test the stored procedure. It works fine.
I then in my ASP.NET project, add another function in web service (asmx). I try to involve, but it says: "object not found".
I have read some posts and say change to 'ON COMMIT PRESERVE ROWS'. I don't want to leave data around. Is there any way to fix this issue? I have searched for sometime already.
[Edit] Other team mates have added many other stored procedures in database. They don't have to grant any right to it. The stored procedures are correctly executed when calling from web service. Of course, their sp do not use global temp table.
I have searched the web. I have seen similar posts out there. Calling an Oracle stored procedure using global temp table within ASP.NET will show the same error - object not found.
Anyway, I have found a way round. That is to use the WITH clause. Here is a reference link: https://oracle-base.com/articles/misc/with-clause
[/Edit]

SQL: Best practice for inserting a record if it doesn't exist

I have an asp.net Gridview that handles insert operations into a SQL database. Records are only permitted to be inserted if they meet a uniqueness criteria, and this constraint is being enforced using unique indexes in SQL server. If the user attempts to insert a record that already exists, an error message is displayed.
I'm wondering what the best practice is for implementing this.
Check if the record exists SQL side, using IF EXISTS, and locking hints (updlock, holdlock, etc). Return an error code to ASP.net depending on whether the record was inserted
Perform the INSERT operation inside a SQL server try/catch block, relying on the unique index to prevent the insert from occurring if the record exists. Return an error code depending on whether an exception was thrown.
Perform the INSERT operation SQL side, but without SQL try/catch. Handle the PK violation exception inside ASP.net instead.
Normally I'd consider using exceptions to handle valid operations to be bad practice - i.e. software should not throw exceptions unless something is broken. However if the unique index on the table in SQL is going to implement the desired constraint, why bother performing a manual check for existence of the record?
I would make a separate call to check if the record already exists. If yes, show message to user, if no make insert. The reason I would do it this way is because I prefer keeping all the business logic in the application.
If you insist in making just one stored proc call:
I would check before I insert. I would also add an output parameter to the stored proc that returns a message if the insert was unsuccessful. In my application if I see a message in the output parameter, I will display that to the user.

MS Access CREATE PROCEDURE Or use Access Macro in .NET

I need to be able to run a query such as
SELECT * FROM atable WHERE MyFunc(afield) = "some text"
I've written MyFunc in a VB module but the query results in "Undefined function 'MyFunc' in expression." when executed from .NET
From what I've read so far, functions in Access VB modules aren't available in .NET due to security concerns. There isn't much information on the subject but this avenue seems like a daed end.
The other possibility is through the CREATE PROCEDURE statement which also has precious little documentation: http://msdn.microsoft.com/en-us/library/bb177892%28v=office.12%29.aspx
The following code does work and creates a query in Access:
CREATE PROCEDURE test AS SELECT * FROM atable
However I need more than just a simple select statement - I need several lines of VB code.
While experimenting with the CREATE PROCEDURE statement, I executed the following code:
CREATE PROCEDURE test AS
Which produced the error "Invalid SQL statement; expected 'DELETE', 'INSERT', 'PROCEDURE', 'SELECT', or 'UPDATE'."
This seems to indicate that there's a SQL 'PROCEDURE' statement, so then I tried
CREATE PROCEDURE TEST AS PROCEDURE
Which resulted in "Syntax error in PROCEDURE clause."
I can't find any information on the SQL 'PROCEDURE' statement - maybe I'm just reading the error message incorrectly and there's no such beast. I've spent some time experimenting with the statement but I can't get any further.
In response to the suggestions to add a field to store the value, I'll expand on my requirements:
I have two scenarios where I need this functionality.
In the first scenario, I needed to enable the user to search on the soundex of a field and since there's no soundex SQL function in Access I added a field to store the soundex value for every field in every table where the user wants to be able to search for a record that "soundes like" an entered value. I update the soundex value whenever the parent field value changes. It's a fair bit of overhead but I considered it necessary in this instance.
For the second scenario, I want to normalize the spacing of a space-concatenation of field values and optionally strip out user-defined characters. I can come very close to acheiving the desired value with a combination of TRIM and REPLACE functions. The value would only differ if three or more spaces appeared between words in the value of one of the fields (an unlikely scenario). It's hard to justify the overhead of an extra field on every field in every table where this functionality is needed. Unless I get specific feedback from users about the issue of extra spaces, I'll stick with the TRIM & REPLACE value.
My application is database agnostic (or just not very religious... I support 7). I wrote a UDF for each of the other 6 databases that does the space normalization and character stripping much more efficiently than the built-in database functions. It really annoys me that I can write the UDF in Access as a VB macro and use that macro within Access but I can't use it from .NET.
I do need to be able to index on the value, so pulling the entire column(s) into .NET and then performing my calculation won't work.
I think you are running into the ceiling of what Access can do (and trying to go beyond). Access really doesn't have the power to do really complex TSQL statements like you are attempting. However, there are a couple ways to accomplish what you are looking for.
First, if the results of MyFunc don't change often, you could create a function in a module that loops through each record in atable and runs your MyFunc against it. You could either store that data in the table itself (in a new column) or you could build an in-memory dataset that you use for whatever purposes you want.
The second way of doing this is to do the manipulation in .NET since it seems you have the ability to do so. Do the SELECT statement and pull out the data you want from Access (without trying to run MyFunc against it). Then run whatever logic you want against the data and either use it from there or put it back into the Access database.
Why don't you want to create an additional field in your atable, which is atable.afieldX = MyFunc(atable.afield)? All what you need - to run UPDATE command once.
You should try to write a SQL Server function MyFunc. This way you will be able to run the same query in SQLserver and in Access.
A few usefull links for you so you can get started:
MSDN article about user defined functions: http://msdn.microsoft.com/en-us/magazine/cc164062.aspx
SQLServer user defined functions: http://www.sqlteam.com/article/intro-to-user-defined-functions-updated
SQLServer string functions: http://msdn.microsoft.com/en-us/library/ms181984.aspx
What version of JET (now called Ace) are you using?
I mean, it should come as no surprise that if you going to use some Access VBA code, then you need the VBA library and a copy of MS Access loaded and running.
However, in Access 2010, we now have table triggers and store procedures. These store procedures do NOT require VBA and in fact run at the engine level. I have a table trigger and soundex routine here that shows how this works:
http://www.kallal.ca/searchw/WebSoundex.htm
The above means if Access, or VB.net, or even FoxPro via odbc modifies a row, the table trigger code will fire and run and save the soundex value in a column for you. And this feature also works if you use the new web publishing feature in access 2010. So, while the above article is written from the point of view of using Access Web services (available in office 365 and SharePoint), the above soundex table trigger will also work in a stand a alone Access and JET (ACE) only application.

Resources