I'm creating a SSRS report from a stored procedure in SQL, when i add a dataset to the report i'm finding i'm having to add this to the top of my procedure in order for fields to be returned into my data set from the stored proc:
IF 1=2 SELECT '' as [Date], '' as [Portfolio ID], '' as [Portfolio Base Ccy], 0 as [All in Market Value Base], 0 as [All in Market Value Converted]
Why would I have to do this and why does SSRS not simply pick up:
SELECT [Date], [Portfolio ID], [Portfolio Base Ccy], [All in Market Value Base], [All in Market Value Converted]
FROM #Worktable
from the bottom of my procedure or
SELECT * FROM #Worktable
?
EDIT:
Ok i think i've narrowed down my issue in my procedure to the face that i have a debug parameter in my procedure. So if this parameter is set to 'Y' then i show each step of my procedure, which makes it easier for debugging (i can add an example if need be). Also at the end of my procedure i have an if statement for my final result set which says:
IF #ReportType IN ('SSD', 'TTD', 'STD')
BEGIN
SELECT.........
END
IF #ReportType IN ('SS', 'TT', 'ST')
BEGIN
SELECT.........
END
Could this be an issue as well?
I worked out my issue, all the way through my procedure i have a debug running for trouble shotting as below:
IF #Debug = 'Y'
BEGIN
SELECT #Section AS Section
SELECT * FROM #Worktable ORDER BY [Portfolio ID]
END
This caused ssrs to get confused as to what is the metadata for the report. I have now fixed my procedure to cause this not to occur and now i don't need the "IF 1=2 SELECT........"
Related
insert into
#resultSet
SELECT TOP (#topN)
field1,
field2
FROM
dbo.table1 DataLog
WHERE
DataLog.SelectedForProcessing is null
I'm passing 300 into #topN in the above sql, a value I've got configured in my app.config file, but this query running on 2 different servers has returned 304 rows in one instance and 307 rows in another instance.
I cant find anywhere that may be interfering with the 300, to turn it into 304 or 307, so I'm beginning to wonder whether SQL Server will just return a few extra rows sometimes? (Same code on another server IS returning the expected 300 rows)
Is this expected behaviour?
Test this
declare #topN int = 100;
select #topN ;
delete * from #resultSet;
insert into
#resultSet
SELECT TOP (#topN)
field1,
field2
FROM
dbo.table1 DataLog
WHERE
DataLog.SelectedForProcessing is null;
select count(*)
FROM
dbo.table1 DataLog
WHERE
DataLog.SelectedForProcessing is null;
select count(*) from #resultSet;
SQL Server will consistently return TOP N rows when N is a constant value - no wiggle room there.
I see two possibilities:
#topN is getting a different value on occasion
#resultSet is somehow not empty before having new values inserted
If #resultSet is a variable declared elsewhere in your scripts, check to see that no other INSERT INTO statements might be leaving unnecessary rows.
One easy way to implement this in run-time would be to simply add another command before this INSERT INTO statement:
DELETE #resultSet;
INSERT INTO
#resultSet
SELECT TOP (#topN)
field1,
field2
FROM
dbo.table1 DataLog
WHERE
DataLog.SelectedForProcessing IS NULL
;
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
I need to execute statements conditionally in DB2. I searched for DB2 documentation and though if..then..elseif will serves the purpose. But can't i use if without a procedure.?
My DB2 verion is 9.7.6.
My requirement is I have a table say Group(name,gp_id). And I have another table Group_attr(gp_id,value,elem_id). We can ignore ant the elem_id for the requirement now.
-> I need to check the Group if it have a specific name.
-> If it has then nothing to be done.
-> If it doesn't have I need to add it to the Group. Then I need to insert corresponding rows in the Group_attr. Assume the value and elem_id are static.
You can use an anonymous block for PL/SQL or a compound statement for SQL PL code.
BEGIN ATOMIC
FOR ROW AS
SELECT PK, C1, DISCRETIZE(C1) AS D FROM SOURCE
DO
IF ROW.D IS NULL THEN
INSERT INTO EXCEPT VALUES(ROW.PK, ROW.C1);
ELSE
INSERT INTO TARGET VALUES(ROW.PK, ROW.D);
END IF;
END FOR;
END
Compound statements :
http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0004240.html
http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.apdv.sqlpl.doc/doc/c0053781.html
http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0004239.html
Anonymous block :
http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.apdv.plsql.doc/doc/c0053848.html
http://www.ibm.com/developerworks/data/library/techarticle/dm-0908anonymousblocks/
Many ot this features come since version 9.7
I got a solution for the conditional insert. For the scenario that I mentioned, the solution can be like this.
Insert into Group(name) select 'Name1' from sysibm.sysdummy1 where (select count(*) from Group where name='Name1')=0
Insert into Group_attr(gp_id,value,elem_id) select g.gp_id,'value1','elem1' Group g,group_attr ga where ga.gp_id=g.gp_id and (select count(*) from Group_attr Ga1 where Ga.gp_id=g.gp_id)=0
-- In my case Group_attr will contain some data for sure if the group has exists already
Below is code that I built from an example I found online, I can't find the link, but the code is referenced in the answers on this stack overflow question: Passing multiple values for a single parameter in Reporting Services.
Here is the SQL code I am working with right now within my stored procedure, it was a long procedure so I summed it down to just the section I am working on, and added the DECLARE and SET for #EMPLOYEES, which are passed as a parameter from SSRS to make the code snippet run.
DECLARE #EMPLOYEES varchar(8000)
-- EMPLOYEES is a comma separated list of EMPLOYEE IDS
-- FROM SSRS Report Parameters. Each ID is 12 characters
-- And there are 806 Employees to choose from, which
-- when all are selected, the Comma separated string grows
-- to 11,193 characters, much longer than 8000
SET #EMPLOYEES = 'EMP000000001,EMP000000002,EMP000000003'
CREATE TABLE #EMPLOYEEIDS
(
EMPLOYEEID varchar(100) NOT NULL
)
DECLARE #CharIndex AS int
DECLARE #Piece AS varchar(100)
-- FILL THE #EMPLOYEEIDS TABLE WITH THE COMMA SEPARATED EMPLOYEE IDS
SELECT #CharIndex = 1
WHILE #CharIndex > 0 AND LEN(#EMPLOYEES) > 0
BEGIN
SELECT #CharIndex = CHARINDEX(',', #EMPLOYEES)
IF #CharIndex > 0
SELECT #Piece = LEFT(#EMPLOYEES, #CharIndex - 1)
ELSE
SELECT #Piece = #EMPLOYEES
INSERT INTO #EMPLOYEEIDS (EMPLOYEEID) VALUES (#Piece)
SELECT #EMPLOYEES = RIGHT(#EMPLOYEES, LEN(#EMPLOYEES) - #CharIndex)
END
SELECT * FROM #EMPLOYEEIDS
DROP TABLE #EMPLOYEEIDS
I had 6 sets of multi-values, all of them worked fine, until I found that the reports were missing much of the data for employees, to which I found that the VARCHAR(8000) was overflowed when selecting all the employees on the report parameters (there are over 800 of them). The Report would run, SQL would happily truncate the VARCHAR to 8000 characters, and a quarter of the IDS were not parsed.
So I tried to switch the VARCHAR to a text field, and none of the parsing functions would work when the field is set up as TEXT. I get errors like the following:
Msg 8116, Level 16, State 2, Procedure usp_QualityMonitoring_AllProfiles_SelectWithParameters, Line 89
Argument data type text is invalid for argument 1 of left function.
This is understandable, I know that many functions that work with VARCHAR will not work with TEXT. So, SQL is truncating everything after 8000 characters when I use a VARCHAR, and the procedure won't ever run if I switch it to TEXT.
What other options to I have to pass multi-valued parameters from SSRS to a SQL Server stored procedure that can support this many options?
OR is there a way to fix the code in the stored procedure to parse through TEXT instead of VARCHAR?
Note: I originally thought the SQL Server running the Stored Proc was 2005, but I have determined that it is not:
SELECT ##VERSION
-- Microsoft SQL Server 2000 - 8.00.2039 (Intel X86) May 3 2005 23:18:38 Copyright (c) 1988-2003 Microsoft Corporation Standard Edition on Windows NT 5.2 (Build 3790: Service Pack 2)
I wrote this very simple SP in SQL 2008:
Create procedure dbo.GetNextID
(
#TableName nvarchar(50),
#FieldName nvarchar(50)
)
AS
BEGIN
exec('select isnull(max('+#FieldName+'),0)+1 as NewGeneratedID from '+ #TableName);
END
When I execute this procedure in Visual Studio SQL Express and pass a table name and a field name, it works fine. But when I try to add this SP as a query in a QueryTableAdapter in my ADO DataSet, I receive this error before clicking on Finish button:
the max function requires 1 argument(s)
can anyone help me with this?
I guess that VS tries to determine a field list by executing the SP. But as it does not know what to pass to the SP, it uses empty parameters. Now, of course, your select statement fails.
You could try adding the following to your SP:
IF ISNULL(#TableName,'') = '' SET #TableName = '<Name of a test table>';
IF ISNULL(#FieldName,'') = '' SET #FieldName = '<Name of some field>';
Use the names of some field and table that do exist here (for example names that you'd use from your application, too).
Alternatively you could add the following above the exec:
IF (ISNULL(#TableName, '') = '') OR (ISNULL(#FieldName, '') = '')
BEGIN
SELECT -1 AS NewGeneratedId
RETURN 0
END
EDIT
On a side note, I'd like to warn you about concurrency issues that I see coming up from what your code does. If this code is supposed to return a unique ID for a new record in some table, I'd redesign this as follows:
Create a table NumberSeries where each row contains a unique name, a possible range for IDs and the current ID value.
Create a stored procedure that uses UPDATE ... OUTPUT to update the current ID for a number series and retrieve it in one step.
That way you can make sure that creating a new ID is a single operation that does not cause concurrency problems.