On my SSRS report I have a multi-value parameter which contains 250+ uniqueidentifier data type values. This works fine with a small selection of values in the parameter dropdown, but when user chooses (select all), they get this error:
An error occurred during local report processing.
String or binary data would be truncated.
Each uniqueidentifier field is 36 characters long, which means 250 of them added together result in a 9000 character string. This is what causes the truncation to occur.
What approach should I take to handle this situation?
Edit:
Couple snapshots of the stored procedure:
ALTER PROCEDURE [dbo].[spReport]
#StartDate as datetime
,#EndDate as datetime
,#LocationId uniqueidentifier
,#UserIds uniqueidentifier
#UserIds is the multi-value parameter. It is used in the where clause of the query:
WHERE (U.UserId IN (#UserIds) OR #UserIds IS NULL)
You can't use an SSRS multi-value parameter with a stored procedure like that. You'll need to join the values in the report, pass them as a varchar(max), and then split them in the stored procedure:
https://stackoverflow.com/a/9862901/124386
http://www.codeulike.com/2012/03/ssrs-multi-value-parameters-with-less.html
SSRS does have a limit on the size of multi-value parameters. I can't remember what it is off the top of my head, but I think you are well beyond it. (SSRS converts the multi-value parameter to a comma separated string and replaces the occurances of the variable name in the query with the string.)
So as mentioned in the comments, you've got two problems:
SP's can't take multi-value parameters directly from SSRS. You'll need to do some manipulation.
Your overall parameter length. This may require a little bit of creativity to solve. Some options:
Can you supply either a separate parameter or a special value in your existing parameter for <All Users> and then check for this in the SP, returning all values in that case. If the query is directly in SSRS (instead of a SP) something like this would work:
...WHERE ( U.UserId in ( #UserIds) OR '<All Users>' in ( #UserIds ) )
...
Can you filter the number of items in your parameter, based on earlier parameters? Such as have the user select a date range and/or department, and only return UIDs that match that range?
Another approach is to create a user defined table type and use that instead of a varchar to pass in the selected values.
Related
I have a table with a field District which is VARCHAR(5)
When I create a computed field:
ALTER TABLE
Postcode
ADD
DistrictSort1
AS
(dbo.fn_StripCharacters(District, '^A-Z'))
PERSISTED;
The computed field DistrictSort1 is added as NVARCHAR(MAX)
Is it possible to change the NVARCHAR to anything other than (MAX)?
Are there any performance issues?
The obvious answer would be to CAST/CONVERT the value explicitly in your computed column:
ALTER TABLE dbo.Postcode
ADD DistrictSort1 AS CONVERT(varchar(5),(dbo.fn_StripCharacters(District, '^A-Z')) PERSISTED;
I would, however, suggest looking at your function fn_StripCharacters, which is currently set up to return an nvarchar(MAX). User defined functions, unlike those built into SQL Server, cannot return different data types based on their input parameter(s). As a result, whenever you reference your function, you will get an nvarchar(MAX) back.
As a result, sometimes it's best to have multiple similar versions of the same function. For one like this, form example, you might want 4, that return varchar and nvarchar values in non-MAX and MAX lengths.
I have the following sql:
--DECLARE #absent nvarchar(20)
--SET #absent = 'Y' -- Not needed in sql as we are setting this in ssrs
SELECT *
FROM Employee
WHERE Absent in #Absent
Here is the employees table.
Employee
Name Absent
Dan Y
Laura N
Ross N
James Y
I want to be able to filter between Y and N and both.
This is working fine for me in SSRS when I pass #absent both Y and N. However, when i convert to a stored procedure and run in SSRS, I now get an issue. I longer get any results.
ALTER PROCEDURE usp_GetEmployees
#Absent nvarchar(20)
SELECT *
FROM Employee
WHERE Absent in #Absent
I've tried the line =join(parameters!Absent.value,",") in the parameter properties but no luck. I believe the issue is with the data type that is being passed in. It is just odd that it works before i converted to a usp.
Any help is much appreciated :)
Assuming you had a typo in your question and you meant to write
SELECT *
FROM Employee
WHERE Absent in (#Absent)
The reason that this WILL work when used directly in a dataset query is that SSRS will take your multi-valued parameter's selected options, convert them into a comma separated list and inject them into the SQL. So what will actually be executed will be, for example,
SELECT *
FROM Employee
WHERE Absent in ('Y', 'N')
This process is not the same when calling a stored procedure as SSRS cannot change the code inside your SP.
When passing multi-value parameters to a Stored Proc you would typically pass in an expression such as =JOIN(Parameters!myParam.Value, ",") . This passes in a string containing a comma separated list of your selected parameter values.
Inside the Stored Proc you would typically call a function to split this string back out into a table that you can join to.
There are plenty or articles describing this and providing a usable split function in case you don't have one. Check out the answers here https://social.msdn.microsoft.com/Forums/sqlserver/en-US/0ead7ceb-3fdd-4625-aa82-1d4195f984b1/passing-multivalue-parameter-in-stored-procedure-ssrs?forum=sqlreportingservices
Your original code wouldn't work directly in SQL. You can fix it using parentheses:
WHERE Absent in (#Absent)
This is exactly equivalent to:
WHERE Absent = #Absent
which is probably not what you intend. In the more recent versions of SQL Server, you can use:
WHERE Absent IN (SELECT value FROM string_split(#Absent, ','))
The ',' is my guess at the separator you are using. You can also use:
WHERE ',' + #Absent + ',' LIKE '%,' + Absent + ',%'
With SSRS, if using a Stored Procedure, the format Column IN (#Variable) doesn't work. That type of query only works if the SQL in directly in the SSRS Data Set's definition. Then SSRS will replace the value of #Variable and (apparently) securely inject the values in a delimited and quoted list.
For something as simple this, you are, in truth, better off likely just putting the below statement in the dataset in SSRS:
SELECT *
FROM Employee
WHERE Absent in (#Absent);
If not, and you need to use a Stored Procedure, then SSRS passes a delimited string as the parameter. In such cases you need to use a splitter. Considering you tag BIDS (visual-studio-2008) then you need to use a really old way of doing this. I also strongly recommend you look at upgrade paths ASAP.
For 2008, then I recommend delimitedsplit8K (or delimitedsplitN4K if using an nvarchar). Then your Procedure will look like this:
ALTER PROCEDURE usp_GetEmployees #Absent nvarchar(4000) AS
BEGIN
SELECT E.* --YOu should replace this with your actual columns
FROM Employee E
JOIN dbo.delimitedsplitN4K(#Absent,',') DS ON E.Absent = DS.item;
END;
I have a parameters #Year and #Month in my report, where month has assigned values like January(label): 1(values), February: 2, ...
My datased is feeded by stored procedure which has a filter
WHERE (cal.CalendarYear = #Year) AND (cal.MonthId = #Month)
When I check 'Allow multiply values' in parameter settings, it returns an error
Error converting data type nvarchar into int.
How can I select all values (by default)?
If you don't need to use a Stored Proc you can easily solve the problem.
Copy the SQL from your stored proc (excluding the PROC definition, just the main code) and paste it in as your dataset query.
Change your = #Year and = #Month to IN(#Year) and IN(#Month)
That's all there is to it, no joining, splitting or anything else.
SSRS will inject the parameter values as comma separated values correctly for you.
When you select multiple values, you pass the parameter to the procedure as an expression with Join().
Then in your procedure change your month parameter to be of type nvarchar(max).
Create a temp table and use a t-sql split string function (Google this, there are so many varieties but if you're stuck we can find one) to split the string into a table. Then inner join to your table in your procedure to filter on the selections.
Your error message about "nvarchar into int" suggests a data type mismatch between your SSRS parameter and your MonthId column. Check the Report Parameter Properties -> General -> Data type for the former and your table schema for the latter, and make sure they're either both text/varchar or both integers.
Allowing your query to handle multiple parameter values should be much simpler than needing to use joins and splits. Just use IN instead of =, and put your parameter name inside a set of brackets.
AND (cal.MonthId IN (#Month))
To set the defaults for your parameter, go to the Report Parameter Properties -> Default Values. Select the Specify values option, and add your numbers 1-12 as separate Value records.
I need to execute a simple query:
SELECT * FROM MyTable WHERE Id IN (:ids)
Obviously, it returns the set of records which have their primary key 'Id' in the given list. How can I pass an array of integer IDs into ADOQuery.Parameters for parameter 'ids'? I have tried VarArray - it does not work. Parameter 'ids' has FieldType = ftInteger by default, if it matters.
There is no parameter type that can be used to pass a list of values to in. Unfortunately, this is one of the shortcomings of parameterized SQL.
You'll have to build the query from code to either generate the list of values, or generate a list of parameters which can then be filled from code. That's because you can pass each value as a different parameter, like this:
SELECT * FROM MyTable WHERE Id IN (:id1, :id2, :id3)
But since the list will probably have a variable size, you'll have to alter the SQL to add parameters. In that case it is just as easy to generate the list of values, although parametereized queries may be cached better, depending on which DB you use.
The IN param just takes a comma separated string of values like (1,2,3,4,5) so I assume you set the datatype to ftstring and just build the string and pass that...? Not tried it but it's what I would try...
The question
Is it possible to ask SSIS to cast a value and return NULL in case the cast is not allowed instead of throwing an error ?
My environment
I'm using Visual Studio 2005 and Sql Server 2005 on Windows Server 2003.
The general context
Just in case you're curious, here is my use case. I have to store data coming from somewhere in a generic table (key/value structure with history) witch contains some sort of value that can be strings, numbers or dates. The structure is something like this :
table Values {
Id int,
Date datetime, -- for history
Key nvarchar(50) not null,
Value nvarchar(50),
DateValue datetime,
NumberValue numeric(19,9)
}
I want to put the raw value in the Value column and try to put the same value
in the DateValue column when i'm able to cast it to Datetime
in the NumberValue column when i'm able to cast it to a number
Those two typed columns would make all sort of aggregation and manipulation much easier and faster later.
That's it, now you know why i'm asking this strange question.
============
Thanks in advance for your help.
You could also try a Derived Column component and test the value of the potential date/number field or simply cast it and redirect any errors as being the NULL values for these two fields.
(1) If you just simply cast the field every time with a statement like this in the Derived Column component: (DT_DATE)[MYPOTENTIALDATE] - you can redirect the rows that fail this cast and manipulate the data from there.
OR
(2) You can do something like this in the Derived Column component: ISNULL([MYPOTENTIALDATE]) ? '2099-01-01' : (DT_DATE)[MYPOTENTIALDATE]. I generally send through '2099-01-01' when a date is NULL rather than messing with NULL (works better with Cubes, etc).
Of course (2) won't work if the [MYPOTENTIALDATE] field comes through as other things other than a DATETIME or NULL, i.e., sometimes it is a word like "hello".
Those are the options I would explore, good luck!
In dealing with this same sort of thing I found the error handling in SSIS was not specific enough. My approach has been to actually create an errors table, and query a source table where the data is stored as varchar, and log errors to the error table with something like the below. I have one of the below statements for each column, because it was important for me to know which column failed. Then after I log all errors, I do a INSERT where I select those records in SomeInfo that do not have an errors. In your case you could do more advanced things based on the ColumnName in the errors table to insert default values.
INSERT INTO SomeInfoErrors
([SomeInfoId]
,[ColumnName]
,[Message]
,FailedValue)
SELECT
SomeInfoId,
'PeriodStartDate',
'PeriodStartDate must be in the format MM/DD/YYYY',
PeriodStartDate
FROM
SomeInfo
WHERE
ISDATE(PeriodStartDate) = 0 AND [PeriodStartDate] IS NOT NULL;
Tru using a conditional split and have the records where the data is a date go along one path and the other go along a different path where they are updated to nullbefore being inserted.