Checking for inequality against string variable fails - oracle

I have the code like this:
var query = repository.Where(item => item.UserId == userId && item.LoanNumber != loanNumber)
which is transformed to SQL (repository is IQueryable).
loanNumber is a string parameter in the method. The problem is that checking against inequality fails (ignored). If instead of variable I use constant with its value, it works properly.
What the... ?

A number should be a NUMBER DATA TYPE, and not a string. It violates normalization rules. So please tell what are the data type of the values being compared on both sides of the expression in predicate.
If you compare similar data types, you would get correct results as you don't and should not rely on implicit conversion.
So make sure you have the correct data type.

Related

SSRS - Filtering an Integer With Both a String and a Boolean Parameter

I have a Boolean parameter called WLH where if True then it should ignore everything but if False then it should show a 0 for every craft textbox in a row that has the word "LABORER" in it. This is the expression that I am using but it doesn't seem to be doing anything. Can I get help on making it work? What am I doing wrong?
=IIF(Parameters!WLH.Value = false AND ReportItems!craft.Value LIKE "*laborer*", 0, ---main calculation for the else statement---)
Two things I see with this expression that need closer attention.
Parameters!WLH.Value = CBool("false"): The false side of the equality test needs to be converted to a boolean type with the CBool (conver to boolean) function.
ReportItems!craft.Value.IndexOf("laborer") >= 0: SSRS doesn't support LIKE in expressions but we can test for the existance of a substring in this manner. What this is doing is looking for the index (where the string "laborer" starts) in the field value and checking for a value greater than 0. This would mean that "laborer" was found while a value other than a positive integer means that the string "laborer" was not found.
I don't have SSRS installed on this machine to double check so post a comment if you still need help. Also note that IndexOf is case sensitive and that if you want to match to "Laborer" as well, you will have to do a case conversion prior to the IndexOf.
Full expression:
=IIF(Parameters!WLH.Value = CBool("false") AND ReportItems!craft.Value.IndexOf("laborer") >= 0, 0, ---main calculation for the else statement---)
EDIT: To deal with case sensitivity
Use "UCase()" to convert your field to upper case and then test only against "LABORER".
=IIF(Parameters!WLH.Value = CBool("false") AND UCase(ReportItems!craft.Value).IndexOf("LABORER") >=0, 0, ---main calculation for the else statement---)

How to use CASE statement and a parameter in the WHERE clause?

I have an SSRS report where there is a parameter that asks the user to include records where revenue is greater than zero, or records with revenue values that are just zero.
Since the query is not a stored procedure and it is not an option to put it into a procedure, I need to use some case logic for the embedded query. I need to do this in the where clause in the end.
I am trying to do something like this:
SELECT * FROM TABLE
WHERE MY_DATE BETWEEN D_START AND D_END
AND
CASE
WHEN :REVENUE = 1 THEN REV != 0
WHEN :REVENUE = 2 THEN REV = 0
END
However, when I run this query I get the following error:
ORA-00905: missing keyword
Is what I am doing not possible? Or is there an error that someone can see and help me with?
Please help. Thanks!
UPDATE: Just to clarify, the user is passing a value of 1 or 2. And the query should filter the data according to what value is passed to it. If 1 is passed in the parameter, then filter out all revenue not equal to zero. Else if two is passed, then filter so that only records where revenue is zero is returned.
You can write it better with a bit of boolean logic:
SELECT * FROM TABLE
WHERE MY_DATE BETWEEN D_START AND D_END
AND (
(:REVENUE = 1 AND REV != 0)
OR
(:REVENUE = 2 AND REV = 0 )
)
CASE is meant to extract different values based on conditions, so you can use it to check conditions, but you need to use it as a value to check against a condition
It's not necessary to use a CASE expression to get this particular result.
But it is possible to make use of one.
The problem in the original query is that Oracle is more strict than other databases (like MySQL) in that Oracle doesn't implicitly convert a boolean expression to a value, or convert a value into boolean.
I suspect that Oracle is choking in a couple of places. The error message is only showing us one of those.
The CASE expression returns a value, and Oracle is balking that he won't evaluate the value as a boolean.
To get that value evaluated as a boolean, we could do a comparison of the value to some other value.
If we fix that, I think Oracle is still going to choke on the expression following THEN. Oracle is expecting to return a value, and it's finding a comparison, which evaluates to a boolean.
Okay, so we know the CASE expression needs to return a value, and we need to use that in a boolean expression. If we move that conditional test into the WHEN part, and specify a value to be returned in the THEN, we can compare the return from the CASE expression to another value.
(As an aside... I strongly recommend that you qualify the column references in the SQL statement. That makes the intent more clear. Looking at the statement, it looks like MY_DATE, D_START and D_END are all column references. That's perfectly valid, it just seems a bit odd to me.)
As an example, we could do something like this with the CASE expression:
SELECT t.*
FROM TABLE t
WHERE t.MY_DATE BETWEEN t.D_START AND t.D_END
AND CASE
WHEN ( :REVENUE = 1 AND t.REV != 0 ) THEN 1
WHEN ( :REVENUE = 2 AND t.REV = 0 ) THEN 1
ELSE NULL
END = 1
The parens inside the CASE aren't necessary; I just included them to highlight the part that Oracle is evaluating in a boolean context.
So, does that work? If the value passed in for :REVENUE is 2, the condition in the first WHEN won't evaluate to TRUE (the result of first comparison is guaranteed to be FALSE). The condition in the second WHEN may evaluate to TRUE (first comparison will yield TRUE, the result from second comparison will depend on the value in the REV column.)
That CASE expression is either going to return a value of 1 or NULL. (We could just as easily use a 0 or a -1, or 999 in place of NULL if we wanted.)
Once the CASE expression is evaluated, the value returned will be compared to a literal value, as if we wrote e.g. val = 1. That comparison is evaluated as boolean. If it evaluates to TRUE, the row will be returned...
To get Oracle to behave similarly to other databases (like MySQL), we would need to make the conversion from boolean to value and value to boolean explicit. We would still need the return from the CASE compared to 1, like we did above. In place of REV != 0 we could use another CASE expression. I'm not recommending this, just shown here for illustration, converting a boolean to a value.
WHERE CASE
WHEN ( :REVENUE = 1 )
THEN CASE WHEN ( t.REV != 0 ) THEN 1 ELSE NULL END
WHEN ( :REVENUE = 2 )
THEN CASE WHEN ( t.REV = 0 ) THEN 1 ELSE NULL END
ELSE
NULL
END = 1
Note that the return from the outermost CASE expression is being compared to a value, so we get a boolean (where Oracle expects a boolean.)
All of the ELSE NULL in the statements above can be omitted for an equivalent result, since that's the default when ELSE is omitted.)
Again, it's not necessary to use a CASE expression. You can get equivalent results without it. For example:
SELECT t.*
FROM TABLE t
WHERE t.MY_DATE BETWEEN t.D_START AND t.D_END
AND ( ( :REVENUE = 1 AND t.REV != 0 )
OR ( :REVENUE = 2 AND t.REV = 0 )
)
In these queries that all return an equivalent result, the CASE expression doesn't buy us anything. But in some circumstances, it can have some advantages over a regular OR, because the CASE expression stops evaluation when a condition in a WHEN clause evaluates to TRUE.
The problem is that Oracle SQL does not have the boolean data type, so you cannot have columns of type boolean, pass boolean parameters to a query, have boolean expressions etc. So they have the somewhat unnatural concept of "condition" which is something that goes into logical conditions (like in the WHERE clause). Unfortunately, when they introduced the case EXPRESSION, which can be used wherever any other expression can be used (but this excludes boolean), they DID NOT introduce a "case CONDITION" - which could be used where other conditions can be used. This omission is odd, since the code for a case condition would probably use 95% of the code for the case expression. All the more weird since PL/SQL does have the boolean type, and the case expression there works seamlessly for Booleans.

F# enum to string conversion

I have a following F# enum
type DataType = AUCTION|TRANSACTION
I would like to use DataType as a parameter to a function, so that the values of the parameter is restricted to string AUCTION and TRANSACTION,
is that possible to convert the items in this enum to string, or is there a better way to contraint the value of a parameter to a set of string?
First of all, as several people have mentioned in the comments, the type you have defined is not an Enumeration, it's a Discriminated Union.
Enumerations are effectively just a label given to an integer and, in F#, are declared using this syntax:
type DataType =
|Auction = 1
|Transaction = 2
Using this syntax, you've got a relationship between the value and the associated integer, you can use the integer to get the value of an Enumeration, e.g.
let transaction = enum<DataType>(2) // Transaction
Note that there is nothing stopping you from saying enum<DataType>(3537), even though we haven't defined that case.
For more details on Enumerations, see: https://msdn.microsoft.com/en-us/library/dd233216.aspx
Discriminated Unions are much more flexible than Enumerations. Let's take a look at yours:
type DataType =
|Auction
|Transaction
This version is now actually a Standard .NET class with two case identifiers: Auction and Transaction. You can think of Auction and Transaction as two type constructors for DataType.
Discriminated Unions are not restricted to just simple cases, you could store additional data, e.g.
type DataType =
/// An auction with a list of bids
|Auction of Bid list
/// A transaction with some price in GBP
|Transaction of decimal<GBP>
With Disciminated Unions, there is no implicit relationships with integers, if we want to construct a particular case, we have to use the appropriate case identifier.
e.g. let auction = Auction (bidlist)
For more details on Discriminated Unions, see: https://msdn.microsoft.com/en-us/library/dd233226.aspx
In both cases, converting to a specific string for each case can be achieved using pattern matching.
For the Discriminated Union:
let datatypeToString datatype =
match datatype with
|Auction -> "AUCTION"
|Transaction -> "TRANSACTION"
And for the Enumeration:
let datatypeToString datatype =
match datatype with
|DataType.Auction -> "AUCTION"
|DataType.Transaction -> "TRANSACTION"
Notice that when you use Enumerations, F# will give you a compiler warning telling you that pattern matches cases aren't complete. This is because Enumerations are just ints and there are many ints besides just 1 and 2, this means that the match cases aren't exhaustive.
I therefore recommend you stick to Discriminated Unions and keep your exhaustive pattern matching.
P.S. If you want to go in the other direction, from string to DataType, I recommend using a tryCreateDataType function which would look something like this:
let tryCreateDataType str =
match str with
|"AUCTION" -> Some Auction
|"TRANSACTION" -> Some Transaction
|_ -> None
This returns an Option, so it will allow you to safely match against the function being successful or it failing due to an invalid string.

Comparing values of type Text with values of type True/False

I have a data column of strings containing a lead status. I only want to count if the lead is qualified or nurture. I have this expression:
Is Qualified = If('Lead'[Status] = OR("Qualified", "Nurture"),1,0)
But I am getting this error:
DAX comparison operations do not support comparing values of type Text
with values of type True/False. Consider using the VALUE or FORMAT
function to convert one of the values.
I'm new with DAX and haven't been able to fix this one. Any help would be great, thanks.
OR() returns a boolean value. I assume 'Lead'[Status] is a text field, in which we will find some strings with the values "Qualified" or "Nurture". If this is the case you want to do the following:
IsQualified =
IF(
'Lead'[Status] = "Qualified"
|| 'Lead'[Status] = "Nurture"
,1
0
)
This is performing two tests, and combining them with a logical or ( || - the double pipe is DAX's or operator ).

Explain the below Linq Query?

results.Where(x=>x.Members.Any(y=>members.Contains(y.Name.ToLower())
I happened to see this query in internet. Can anyone explain this query please.
suggest me a good LINQ tutorial for this newbie.
thank you all.
Edited:
what is this x and y stands for?
x is a single result, of the type of the elements in the results sequence.
y is a single member, of the type of the elements in the x.Members sequence.
These are lambda expressions (x => x.whatever) that were introduced into the language with C# 3, where x is the input, and the right side (x.whatever) is the output (in this particular usage scenario).
An easier example
var list = new List<int> { 1, 2, 3 };
var oddNumbers = list.Where(i => i % 2 != 0);
Here, i is a single int item that is an input into the expression. i % 2 != 0 is a boolean expression evaluating whether the input is even or odd. The entire expression (i => i % 2 != 0) is a predicate, a Func<int, bool>, where the input is an integer and the output is a boolean. Follow? As you iterate over the query oddNumbers, each element in the list sequence is evaluated against the predicate. Those that pass then become part of your output.
foreach (var item in oddNumbers)
Console.WriteLine(item);
// writes 1, 3
Its a lambda expression. Here is a great LINQ tutorial
Interesting query, but I don't like it.
I'll answer your second question first. x and y are parameters to the lambda methods that are defined in the calls to Where() and Any(). You could easy change the names to be more meaningful:
results.Where(result =>
result.Members.Any(member => members.Contains(member.Name.ToLower());
And to answer your first question, this query will return each item in results where the Members collection has at least one item that is also contained in the Members collection as a lower case string.
The logic there doesn't make a whole lot of sense to me with knowing what the Members collection is or what it holds.
x will be every instance of the results collection. The query uses lambda syntax, so x=>x.somemember means "invoke somemember on each x passed in. Where is an extension method for IEnumerables that expects a function that will take an argument and return a boolean. Lambda syntax creates delegates under the covers, but is far more expressive for carrying out certain types of operation (and saves a lot of typing).
Without knowing the type of objects held in the results collection (results will be something that implements IEnumerable), it is hard to know exactly what the code above will do. But an educated guess is that it will check all the members of all the x's in the above collection, and return you an IEnumerable of only those that have members with all lower-case names.

Resources