PLSQL - Find two values are equal when they are NULL - oracle

I'm using a IF condition to check whether 2 values are equal or not. In one scenario all the values that I use are NULL, but it does not recognize as they are equal.
IF training_event_rec_.training_fee = course_rec_.course_fee AND training_event_rec_.training_fee_unit = course_rec_.course_fee_unit AND training_event_rec_.currency = course_rec_.currency AND training_evaluation_temp_ = course_evaluation_temp_ THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
In here all the variables that is compared are NULL but it always hit the ELSE part.
How Can I compare values in this kind of situations.

Use IS NULL:
IF (training_event_rec_.training_fee = course_rec_.course_fee OR
(training_event_rec_.training_fee IS NULL AND course_rec_.course_fee IS NULL))
AND (training_event_rec_.training_fee_unit = course_rec_.course_fee_unit OR
(training_event_rec_.training_fee_unit IS NULL AND course_rec_.course_fee_unit IS NULL))
AND (training_event_rec_.currency = course_rec_.currency OR
(training_event_rec_.currency IS NULL AND course_rec_.currency IS NULL))
AND (training_evaluation_temp_ = course_evaluation_temp_ OR
(training_evaluation_temp_ IS NULL AND course_evaluation_temp_ IS NULL))
THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
NOTE:
You can also compare Nulls like NVL(COLUMN_A,'X') = NVL(COLUMN_B,'X') only if you are sure that COLUMN_A & COLUMN_B will not contain value 'X'. So that is not recommended approach.

I presume there might be different combinations of non-null and null values. One option is to check them all, or - maybe simpler - use NVL, such as:
IF nvl(training_event_rec_.training_fee, 0) = nvl(course_rec_.course_fee, 0)
AND nvl(training_event_rec_.training_fee_unit, 0) = nvl(course_rec_.course_fee_unit, 0)
AND nvl(training_event_rec_.currency, 0) = nvl(course_rec_.currency, 0)
AND nvl(training_evaluation_temp_, 0) = nvl(course_evaluation_temp_, 0)
THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
Depending on datatypes, you might need to use something else, not 0. For example, currency might be USD or EUR or something like that, so you'd use
nvl(training_event_rec_.currency, 'x')

Related

drools input validation and stop execution

I have to validate some elements for null and then stop execution if they are null.
I have few rules like below which checks for some null values and adds errors
rule "Require begin date for Service Period"
salience 100
when
$servicePeriod : ServicePeriod(beginDate == null)
// check this to avoid the infinite loop
eval(!$servicePeriod.getValidationErrors().contains("Begin date is required."))
then
$servicePeriod.getValidationErrors().add("Begin date is required.");update($servicePeriod);
end
I have some rules like below which first checks 'validationErrors.size() == 0'. Even though validation errors size is greater than zero, it continues to check other validation and fails as they are null. Please let me know how I can modify these rules to avoid exception.
// Rules for Firefighter deduction calculation
rule "Firefighter Annual Salary Deposit Calculation"
salience 50
when
$servicePeriod : ServicePeriod(validationErrors.size() == 0 , periodType.name == "DEPOSIT" , payType.name == "ANNUAL SALARY" , serviceType.name == "FIREFIGHTER" )
then
calculateDeduction($servicePeriod, 0.075);
end
I suspect that you're thinking that in Java, such constraints are evaluated from left to right, so if the first constraint checks for 0 or null, then further constraints are safe. However, this is not the case in Drools comma-separated constraints.
I think that you might be able to switch to a more Java-style expression:
ServicePeriod(
validationErrors.size() == 0,
periodType != null && periodType.name == "DEPOSIT",
payType != null && payType.name == "ANNUAL SALARY",
serviceType != null && serviceType.name == "FIREFIGHTER" )
I'm not totally sure without testing though.

How to pass an external parameter to LINQ where clause in CRM

I have a LINQ query which works fine as for stand alone lists but fails for CRM
var lst = new List<bool?>();
lst.Add(null);
lst.Add(true);
lst.Add(false);
bool IsWet = false;
var newlst = from exch_HideVoiceSignature in lst where
(((exch_HideVoiceSignature!=null && exch_HideVoiceSignature==false
|| exch_HideVoiceSignature== null) )&& !IsWet) select exch_HideVoiceSignature;
newlst.Dump();
var question = from q in exch_questionSet where ((q.exch_HideVoiceSignature != null
&& q.exch_HideVoiceSignature.Value == 0 )|| q.exch_HideVoiceSignature == null )
&& !IsWet select q.exch_HideVoiceSignature;
question.FirstOrDefault().Dump();
As you can see I can pass the variable IsWet to LINQ query for a standard list fine and get values for first list. But when I execute the same for second list, I get the following error
Invalid 'where' condition. An entity member is invoking an invalid property or method
The CRM LINQ provider won't support the evaluation you attempting. It only supports evaluation of where criteria is evaluating an entity field.
That's not a problem. Since you want the LINQ query to only use the where clause if IsWet is false (correct me if I'm wrong on that.) So we simply do the evaluation to determine if the where clause should be added or not. Then execute your query.
var question = from q in exch_questionSet
select q.exch_HideVoiceSignature;
if (!IsWet)
{
question.Where(x => ((x.exch_HideVoiceSignature != null
&& x.exch_HideVoiceSignature.Value == 0) || x.exch_HideVoiceSignature == null));
}
question.FirstOrDefault().Dump();
I am constantly confronted with that problem.
Try to "detach" (for example call .ToArray()) your query (while it is "clear") from CRM and then filter query using external parameter. This should help.
var question =
(from q in exch_questionSet
where (
(q.exch_HideVoiceSignature != null && q.exch_HideVoiceSignature.Value == 0 ) ||
q.exch_HideVoiceSignature == null )
select q.exch_HideVoiceSignature
).ToArray().Where(q => !IsWet);
question.FirstOrDefault().Dump();
UPDATE
If you are using IsWet flag to control blocks of conditions (enable and disable them from the one point in the code) then probably you may be interested in class named PredicateBuilder which allows you to dynamically construct predicates.
Just because I had an existing query with lot of other joins etc. and I wanted to pass this additional parameter to it I ended up using a var statement which dumps the rows to a list and applies the where clause in the same statement
bool IsWet =true ;
var question = ...existing query ...
select new {
...existing output ...,
Wet =q.exch_HideVoiceSignature != null &&
q.exch_HideVoiceSignature.Value == 119080001,
Voice = q.exch_HideVoiceSignature == null ||
(q.exch_HideVoiceSignature != null &&
q.exch_HideVoiceSignature.Value == 119080000) ,
}
;
var qq = IsWet ?
question.ToList().Where(X=> X.Wet ) :
question.ToList().Where(X=> X.Voice );
qq.FirstOrDefault().Dump();

Passing null as Contains() within "linq to sql" query

I have a problem with Contains in linq to sql query as below:
public IAuditRecord[] Fetch(SearchConditions searchConditions)
{
IAuditRecord[] searchedList = (from rows in _dbContex.AuditTrails
where
(searchConditions.Owner == null || searchConditions.Owner == 0) ? true : rows.Owner == searchConditions.Owner
&&
/*This line cannot compile when ActionIDs array is empty*/
(searchConditions.ActionIDs != null && searchConditions.ActionIDs.Length != 0) ? searchConditions.ActionIDs.Contains(rows.UserActionID) : true
&& ((searchConditions.StartDate != null && searchConditions.EndDate != null) ? (rows.TimeStamp >= searchConditions.StartDate && rows.TimeStamp <= searchConditions.EndDate)
: (searchConditions.StartDate != null && searchConditions.EndDate == null) ? rows.TimeStamp >= searchConditions.StartDate : (searchConditions.StartDate == null && searchConditions.EndDate != null) ? (rows.TimeStamp <= searchConditions.EndDate)
: true)
select rows).ToArray();
return searchedList;
}
This query executes perfectly if searchCondition.ActionIDs array is not null or empty,
but when i pass the ActionIDs array as null the query cannot be compiled.
So the main question is Why contains cannot work when ActionIDs array is null?
You're building an IQueryable, which defines how to query for something, not actually doing it. To do this it builds an Expression, which defines all the query intents and can later be called to actually get the data. If you were using LINQ-to-Objects, this would likely work since it would likely call searchConditions.ActionIDs != null first, then know that it doesn't have to attempt to execute the second portion. Linq-to-Entities/SQL, etc. don't have that benefit.
Long story short, you can either do:
searchConditions.ActionIDs = searchConditions.ActionIDs ?? new int[];
Or do a different query if its null, like:
var query = _dbContext.AuditTrails;
if(searchConditions.ActionIDs != null && searchCondition.ActionIDs.Length != 0)
{
query = // Further filtered query where ActionIDs are taken into account.

Linq with Logic

I have simple Linq statement (using EF4)
var efCars = (from d in myentity.Cars
where d.CarName == inputCar.CarName
&& d.CarIdNumber == inputCar.IdNumber
&& d.Make == inputCar.Make
select d.Car);
I want it to be smarter so that it will only query across one or more of the 3 fields IF they have values.
I can do a test before, and then have a separate linq statement for each permutation of valyes for inputcar
(i.e. one for all 3, one for if only carname has a value, one for if carname AND CarIdNumber has a value etc etc)
but there must be a smarter way
Thanks!
If "has no value" means null then you can use the null coalescing operator ?? to say take the first value if populated, otherwise take the second:
var efCars = (from d in myentity.Cars
where d.CarName == (inputCar.CarName ?? d.CarName
&& d.CarIdNumber == (inputCar.IdNumber && d.CarIdNumber)
&& d.Make == (inputCar.Make && d.Make)
select d.Car);
This basically says if a value exists it must match, otherwise treat it as matching
However if instead you're saying "when a special value (empty string) ignore it, otherwise match" then you can do one of two approaches (or possibly more!):
where (inputCar.CarName == "" || d.CarName == inputCar.CarName)
where (string.IsNullOrEmpty(inputCar.CarName) || d.CarName == inputCar.CarName)
For performance (when dealing with database queries) it can sometimes be beneficial to let EF generate queries based on the filters, instead of using one generic query. Of course you will need to profile whether it helps you in this case (never optimize prematurely), but this is how it would look if you dynamically build your query:
var efCars =
from car in myentity.Cars
select car;
if (inputCar.CarName != null)
{
efCars =
from car in efCars
where care.CarName == inputCar.CarName
select car;
}
if (inputCar.IdNumber != null)
{
efCars =
from car in efCars
where care.CarIdNumber == inputCar.IdNumber
select car;
}
if (inputCar.Make != null)
{
efCars =
from car in efCars
where care.Make == inputCar.Make
select car;
}
where (inputCar.CarName != null || d.CarName == inputCar.CarName) &&...

Unpassable Where Clauses LINQ-to-SQL

As I'm struggling to learn LINQ I’ve managed to generate a SQL statement with "AND (0 = 1)" as part of the where clause. I'm just wondering if this result is common in poorly written queries and is a known issues to try and avoid or if I am doing something totally backwards to end up with this.
Update
public static IEnumerable<ticket> GetTickets(stDataContext db,string subgroup, bool? active)
{
var results = from p in db.tickets
where
( active == null || p.active == active )
/*(active == null ? true :
((bool)active ? p.active : !p.active))*/ &&
p.sub_unit == db.sub_units.Where(c=>subgroup.Contains(c.sub_unit_name))
select p;
return results;
}
If I ignore the active part and just run
public static IEnumerable<ticket> GetTickets1(stDataContext db,string subgroup, bool? active)
{
return db.tickets.Where(c => c.sub_unit.sub_unit_name == subgroup);
}
It returns the groups of tickets I want ignoring the active part.
I'd pull the processing out of the ternary operators.
where ( active == null || p.active == active )
EDIT
The rest of the where clause looks funky too... why is it not just doing
&& p.sub_unit.sub_unit_name == subgroup
or
&& subgroup.Contains(p.sub_unit.sub_unit_name)
?
That is some pretty heavy abuse of the ternary operator.
This expression:
(active == null ? true :
((bool)active ? p.active : !p.active))
Is equivalent to the following logic:
bool result;
if (active == null)
{
result = true;
}
else
{
if ((bool)active)
{
result = p.active;
}
else
{
result = !p.active;
}
}
result &= ...
Think carefully about what this is doing:
If active is null, you're fine, it skips to the next condition.
If active is true, result is true at the end of the conditional.
If active is false, result is false at the end of the conditional.
In the last case, the query can never return any rows!
#Tanzelax has already supplied a simple rewrite. The main idea is that you want to compare p.active to active, not actually evaluate the condition as p.active.
This is probably caused by a null value in one you the columns you have declared as non-nullable. LINQ2SQL makes all columns non-nullable by default. Go back to the designer and change the fields to allow values to be null. Unfortunately this feature is By Design (see connect.microsoft.com link below.)
(linq) incorrect sql generated for row.column == localVar when localVar is null (should be "is null" check)

Resources