IIF is giving me some hell. When I do this everything works:
=IIF (IsNothing(First(Fields!Temperature.Value, "ReportInfoDataSet")),"NULL","GOOD")
But when I want to actually use the value, I end up with #Error for the NULL values, and from what I've read it's because IIF evaluates everything at once, so the .ToString() argument fails for the "GOOD" condition even though it is not used.
This gives #Error when I have a null value:
=IIF(
IsNothing(First(Fields!Temperature.Value, "ReportInfoDataSet")),
"N/A",
First(Fields!Temperature.Value, "ReportInfoDataSet").ToString()
)
So how do I work around the fact that IIF wants to evaluate all terms? There is a TechNet article that shows nesting another IIF statement as the "GOOD" condition that helps with the NULL value, but I still get the error (doing this for example):
=IIF(
IsNothing(First(Fields!Temperature.Value, "ReportInfoDataSet")),
"N/A",
IIF(
IsNothing(First(Fields!Temperature.Value, "ReportInfoDataSet")),
"N/A",
First(Fields!Temperature.Value,"ReportInfoDataSet").ToString() & ChrW("&H00B0") & "F"
)
)
Here is the article that indicates this potential solution, but it seems that I am still missing something, or that something changed invalidating this solution.
One further bit of information: I put a breakpoint in just after I fill the datatable, thinking that I would just intercept the table fill and modify so that NULLs turn to 0 or something, and it seems that datatables are strongly typed and don't allow for nullable data types so there is an exception for the temperature column:
'(ReportInfoRow((new System.Linq.SystemCore_EnumerableDebugView((test.Table).Rows)).Items[0]))
.Temperature' threw an exception of type 'System.Data.StrongTypingException'
Any insights are valued . . . I'm pondering whether I just want to add an extension to the dataset and add a MyTemp parameter that fixes the value for the report.
To not have the .ToString() forced in the lack of short-circuit Boolean evaluation above, replace it with CSTR().
CSTR(First(Fields!Temperature.Value, "ReportInfoDataSet"))
Related
I'm not sure if something special has been done with the database that I am working with, but while optimizing old code, I came across the following (sanitized) query:
SELECT Code
FROM GovernmentThing
WHERE IsGovernment = 'True'
I checked the data type for IsGovernment, assuming that it was a varchar(5) or something similar, only to discover that it was a bit field.
I then assumed that the code was bad, and checked by running a query returning the IsGovernment field. To my great surprise, I discovered that the query was returning only rows where IsGovernment was set to 1! Since I then wondered what a check against a string literal 'False' would return, I tested, just to find that only zero values were returned!!
It is possible that I missed something somewhere in the TSQL updates, or that there is some tricky configuration that makes this work, but... I've never heard of this before.
Can someone please enlighten me - is this documented somewhere, or ???
SQL Server 2012
Here's the excerpt from the bit data type documentation that describes this behavior:
The string values TRUE and FALSE can be converted to bit values: TRUE
is converted to 1 and FALSE is converted to 0.
Entirely by accident today I was running a SQL statement to filter some items by date, for simplicity sake we'll say I used
SELECT *
FROM [TableName]
WHERE [RecordCreated] >+ '2016-04-10'
Only after the statement ran I realised I had used >+ instead of >=, now I was confused as I would have expected an error.
I tried a couple of other variations such as
>- -- Throws an error
<+ -- Ran successfully
<- -- Throws an error
The count of rows returned was exactly the same whether I used >= or >+
After searching online I couldn't find any documentation that covered this syntax directly, only when the two operators are used apart.
The RecordCreated column is a datetime.
Is this just a nicety in syntax for a possible common mistake or is it potentially trying to cast the date as a numeric value?
This seems to be a bug with '+' operator.
As per the updates from Microsoft team,
After some investigation, this behavior is by design since + is an
unary operator. So the parser accepts "+ , and the '+' is
simply ignored in this case. Changing this behavior has lot of
backward compatibility implications so we don't intend to change it &
the fix will introduce unnecessary changes for application code.
You can find a really good answer by RGO to his own question here.
The result shouldn't match with ">=" and "<=" but with ">" and "<". Just checked and the rowcound varies by 2 - the first and last item is removed.
when I do
SELECT SUM(some_field) FROM some_table
the result is a single record/field with a number in it. Additionally, there will be a message send to the client along the lines of Warning: Null value is eliminated by an aggregate or other SET operation. in case some_field has a NULL value in the table somewhere. Only when they all are NULL (or the table is empty) it will return NULL.
I'm currently in the process of writing my own SqlUserDefinedAggregate and although things work as expected, it does NOT show me this message when one of the values passed turns out to be NULL. The outcome of the function is still correct, but there is no warning. First I assumed I might have to pipe this manually in the Terminate() method, but alas, SQLCLR then throws me an InvalidOperationException saying Data acces is not allowed in this context.
Any hints?
If your aggregate is discarding NULLs then the IsInvariantToNulls property should definitely be set to true else you might get unexpected results sometimes, as stated on the MSDN page for SqlUserDefinedAggregateAttribute.IsInvariantToNulls:
Used by the query processor, this property is true if the aggregate is invariant to nulls. That is, the aggregate of S, {NULL} is the same as aggregate of S. For example, aggregate functions such as MIN and MAX satisfy this property, while COUNT(*) does not.
Incorrectly setting this property can result in incorrect query results. This property is not an optimizer hint; it affects the plan selected and the results returned by the query.
And a UDA is a function so there is no SqlContext.Pipe to use. And even if there was, the Terminate method isn't an appropriate place to handle this since it executes for every group. The warning you are seeing when using SUM, however, is an ANSI warning and is displayed once for the query, not per group.
So, if SQL Server isn't displaying the warning then there likely isn't anything you can do about it. I assume that SQL Server isn't using the IsInvariantToNulls property as a means of knowing if it should display the message or not because it is not guaranteed to be accurately set.
And personally, I find this to be a benefit since, in my opinion, the "Null value is eliminated by an aggregate" warning is entirely not helpful, yet if you want to get rid of it you need to use ISNULL() to inject a value that won't influence the result (e.g. 0 in the case of SUM), or turn off ALL ANSI warnings, in which case you disable some warnings that are sometimes helpful.
Is it possible to somehow create variable in rdlc report expression in 'online' manner?
For example, I have following expression:
=IIf(First(Fields!BillingAccount_billtostateprovince.Value, "Invoice") <> "",
First(Fields!BillingAccount_billtostateprovince.Value, "Invoice") + " ",
"")
I suppose that I'm evaluating following expression First(Fields!BillingAccount_billtostateprovince.Value, "Invoice") twice. I don't like it and it looks ugly... I would prefer to create variable in the scope of current expression and use it.
Is it possible?
As user3056839 said, Welcome to SSRS!
Anyway, what you want is not possible since what you are writing right now is not a script but it's just an expression. It's a single statement that returns a value, so you cannot declare variables, use loops or anything that is part of a script.
You have to use exactly what you are writing.
Also it's not rare to see an IIF expression like yours. The one I constantly see is IFF( IS NOT NULL, , 'N/A'). The field may actually be evaluated twice, but there's nothing you can do. It's ugly but it's the only way you can do that.
Just think about the CASE WHEN clause:
SELECT
CASE WHEN MyField IS NOT NULL THEN
MyField ELSE 0
END
You are evaluating the field twice, but there's nothing you can do :)
It is possible to do it in SQL Server 2008 and above. You can create a Report Variable which can be accessed through out your report.
Reference: sqlchick.com
Trying to run this query in LINQPad 4:
SELECT item_group_id as AccountID, IIF(ISNULL(t_item_group.description),'[blank]',t_item_group.description) AS Name
FROM t_item_group
WHERE active = TRUE
I get, "the isnull function requires 2 argument(s)."
I've tried moving the parens around, changing the "[blank]" to "[blank]" and "[blank]" , but none of it helps...
The queries (I have two similar ones (with IIF(ISNULL)) that LINQPad won't run for this reason, yet they run in actuality (in my Web API app) fine; so, LINQPad is more "picky" than it needs to be, perhaps, but what is it expecting, SQL syntax-wise?
ISNULL is already like a 'if' type statement.
You can just replace
IIF(ISNULL(t_item_group.description),'[blank]',t_item_group.description)
with
ISNULL(t_item_group.description, '[blank]')
The ISNULL uses the first parameter (the 'description'), unless that value is null in which case it will use the second parameter.
As an aside, one of the reasons I don't care for ISNULL is that it is poorly named. You'd assume that given its name it will return a bit - true if the parameter is null, false if not null - which you could use in an 'if' statement like you attempted. But that's not how it works.
The alternative is to use COALESCE. It provides much the same functionality, but the naming makes sense.
co·a·lesce ˌkōəˈles verb
1. come together and form one mass or whole.
To COALESCE two parameters is to force them into one non-nullable result. And the function is actually more powerful, as you can provide multiple parameters - COALESCE(i.description, i.name, '[blank]') is perfectly valid.