When ReturnCode=true, it should populate cfstoredproc.statusCode with the status code returned by the stored procedure.
But I can only see cached and executionTime.
Here is an example that I tested and works. Perhaps the issue is with the way the stored procedure is written or with the JDBC Driver you are using to connect with the database.
Another option you have at hand is to not use the tag to call the storedprocedure. You can also call stored procedures using the cfquery tag. This often gives more predictable results.
Here is the code for the test procedure:
CREATE PROCEDURE dbo.PTest
#Somename nvarchar(50) = NULL, -- NULL default value
#SomeResponse nvarchar(50) = NULL OUTPUT
AS
IF #Somename IS NULL
BEGIN
RETURN(1)
END
ELSE
SET #SomeResponse = 'Hello World:' + #Somename;
BEGIN
RETURN(2)
END
Then on the coldfusion side using the cfstoredproc tag:
<cfstoredproc datasource="yourdatasource" procedure="dbo.PTest" returncode="yes">
<cfprocparam type="in" variable="Somename" cfsqltype="cf_sql_varchar" value="John Smith">
<cfprocparam type="out" variable="SomeResponse" cfsqltype="cf_sql_varchar">
</cfstoredproc>
<cfoutput>
#SomeResponse#
<cfdump var="#cfstoredproc#">
</cfoutput>
Using cfquery this would look like this:
<cfquery name="qFoo" datasource="yourdatasource">
SET NOCOUNT ON
DECLARE #SomeResponse varchar(50), #return_code int;
EXECUTE #return_code = dbo.PTest 'John Smith', #SomeResponse = #SomeResponse OUTPUT
SET NOCOUNT OFF
SELECT #return_code as returnCode,
#SomeResponse as someResponse
</cfquery>
<cfoutput>
#qFoo.returnCode# | #qFoo.someResponse#
<cfdump var="#qFoo#">
</cfoutput>
Related
I'm trying to do a cross database query but my error suggest's that I can't even connect to my external data source.
My exact error message is the following:
Error retrieving data from shard [DataSource=xxxxxxxxxxxxxxxxxx Database=CRDMPointOfSale_Configuration]. The underlying error message received was: 'Login failed for user 'CRDMAdmin'.'.
Below is my 'Create Database Scoped Credential'.
CREATE DATABASE SCOPED CREDENTIAL CRDMCred
WITH IDENTITY = 'CRDMAdmin',
SECRET = 'xxxxxxxxxx';
GO
Below is my 'Create Extenal Data Source'.
CREATE EXTERNAL DATA SOURCE CRDM_Configuration
WITH (
TYPE=RDBMS,
LOCATION='xxxxxxxxxxxxxxxxxxxxx',
DATABASE_NAME='CRDMPointOfSale_Configuration',
CREDENTIAL = CRDMCred
);
Below you can see my execute remote statement is within a stored procedure. Which I've seen elsewhere online.
CREATE PROCEDURE [admin].[InsertThreadProcessingDataIntoLoadTable]
(
#ThreadID VARCHAR(100)
, #DataLoadSchemaID INT OUTPUT
, #DateFrom CHAR(8) OUTPUT
, #DateTo CHAR(8) OUTPUT
, #DatabaseName VARCHAR(100)
)
AS BEGIN
SET NOCOUNT ON
DECLARE #IsBatchLoad BIT
SET #IsBatchLoad = CASE 'NO' WHEN 'YES' THEN 1 ELSE 0 END
Exec sp_execute_remote #data_source_name = N'CRDM_Configuration',
#stmt = N'SELECT #DateFrom = CONVERT(CHAR(8),FromDate,112), #DateTo = CONVERT(CHAR(8),DATEADD(DAY,1,ToDate),112)
FROM [admin].[GetFromAndToDatesForDatabase] (#DatabaseName, #IsBatchLoad,NULL)',
#params = N'#DatabaseName VARCHAR(100), #IsBatchLoad BIT',
#DatabaseName = 'CRDMPointOfSale', #IsBatchLoad = 1;
END
As you can see above the execute remote contains a SELECT statement, the FROM is the result of a function being called ([admin].[GetFromAndToDatesForDatabase]) that is from a different database which is why i have a 'Exec sp_execute_remote' wrapped around.
Should I be specifying parameters when not directly calling a SP? Also what am i doing wrong?
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
I have a question regarding cfspreadsheet....So I'm using cfspreadshseet to create excel spreadsheets for reporting purposes. My page allows a user to select whatever columns from the database to include in the report. So here is an example:
The spreadsheet could look like this:
First Name---Last Name---Organization---Address---City---State---Zip---Concern
Joe Smith Sample 12 main denver co 80513 concerns go here
My question is this, if Joe has more than 1 concern I get multiple rows with joe's info...is there a way I can loop the concerns and only have 1 row for joe?
Thanks,
Steve
Using the "group" feature of cfoutput is perfectly fine for this task. Just to throw out another possibility, you could also generate the list within your database query.
For example, MySQL has the GROUP_CONCAT function. I do not know the structure of your tables, but say you have two tables User and UserConcern, you could use GROUP_CONCAT like so to concatenate the "Concern" values into a single string:
SQLFiddle
SELECT
u.UserID
, u.FirstName
, ... other columns
, GROUP_CONCAT( uc.Concern ) AS ConcernList
FROM UserTable u INNER JOIN UserConcern uc
ON uc.UserID = u.UserID
GROUP BY
u.UserID
, u.FirstName
, ... other columns
For SQL Server, a standard trick is to use XML Path:
SQLFiddle
SELECT
u.UserID
, u.FirstName
, ... other columns
, STUFF( ( SELECT ',' + uc.Concern
FROM UserConcern uc
WHERE uc.UserID = u.UserID
ORDER BY uc.Concern
FOR XML PATH('')
)
, 1, 1, ''
) AS ConcernList
FROM UserTable u
GROUP BY
u.UserID
, u.FirstName
, ... other columns
Then simply generate your spreadsheet as usual.
You need a unique row ID to do this safest, the outer group working with lastname, or something, could cause conflict. UserID is a placeholder variable. Make sure to replace it with an accurate ID name. Of course, a few of these variable names are just guessed.
<cfoutput query ="thequery" group="UserID">
<cfset cList="">
<cfoutput group="concern">
<cfset cList=ListAppend(cList,Concern)>
</cfoutput>
<cfset temp = spreadsheetAddRow(my_spreadsheet,"'#fn#','#ln#',...,'#cList#'">
</cfoutput>
Assuming you want separate lines for each comment, something like this would work:
<cfset current_id = "">
<cfloop query = "my_query">
<cfset next_id = user_id>
<!--- or whatever else forms the primary key --->
<cfif next_id neq current_id>
<cfset current_id = next_id>
<cfset SpreadsheetAddRow(my_spreadsheet, "#first_name#,#last_name#,etc, #comment#">
<cfelse>
<cfset SpreadsheetAddRow(my_spreadsheet, ",,#comment#">
</cfif>
</cfloop>
This is based on the information provided. If you have a unique ID the group attribute would work better.
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 !
I have a component "bulletin.cfc" which contains lots of functions.
My main page has two threads running on it using the cfthread tag.
Coming from .net I thought I would create two instrances of the component, and use one in each thread. This way they wouldnt mess with each other and I wouldnt need to worry about putting locks in the functions.
<cfset bullObj = new bulletin()>
<cfset bullObj2 = new bulletin()>
Is this correct?
EDIT:
Thanks for the answers so far, I still can't understand a problem that is happening with this though. I have the following code inside two seperate cfthread elements:
<cfset listCount = 1>
<cftry>
<cfquery name="ins" datasource="#datasourceVar#" >
INSERT INTO element_user_shown
(elementid, userid, date_shown)
(
<cfloop list="#elementIDList#" index="lcv">
SELECT #lcv#, #tmpuserid#, GETDATE()
<cfif listCount LT listlen(elementIDList)>
UNION ALL
</cfif>
<cfset listCount = listCount + 1>
</cfloop>
)
</cfquery>
This runs about 70,000 times a night but gets about 3-4 errors each time. Checking the sql that errors it looks like
INSERT INTO element_user_shown
(elementid, userid, date_shown)
(
SELECT 621, 267509, GETDATE()
UNION ALL
SELECT 586, 267509, GETDATE()
UNION ALL
SELECT 594, 267509, GETDATE()
UNION ALL
SELECT 613, 267509, GETDATE()
SELECT 622, 267509, GETDATE()
SELECT 599, 267509, GETDATE()
SELECT 602, 267509, GETDATE()
)
You are correct that your instances are passed by reference so the potential might be there to have a concurrency problem. But if your function arguments are properly paramed and you are not changing properties as a part of the instance (in other words this is an interface and not a bean) you can safely reuse the same instance. Each function call is it's own scope and variables within and returned are for the life of the function call.