Squeryl Where clause with Nullable Column has no effect - sql

I have a where clause that basically splits my table into two lists. One list where all the fields are "complete"(Not -1) and then one where any field is incomplete. The problem is that one of these fields is not only nullable, but I also only want to count it as incomplete if another field is true.
Where clause:
//l and p are my two tables(This is in a join)
//passed in an option incompletes. If incompletes is true, give back incomplete values
where(
//SHOW INCOMPLETES
(
p.attr1 === -1 or
p.attr2 === -1 or
p.attr3 === -1 or
//only need to check attr4 if this var is true
(p.attr4 === -1).inhibitWhen(!l.needToCheckAttr4) //I've also tried === Some(-1)
).inhibitWhen(!incompletes.isDefined) and
// SHOW COMPLETES
(
p.price <> -1 and
p.serverCost <> -1 and
p.depreciation <> -1 and
(p.attr4 <> -1).inhibitWhen(!l.needToCheckAttr4)
).inhibitWhen(incompletes.isDefined)
)
The attr4 lines seem to have no effect while the rest of the conditions all work correctly. That is as long as the other conditions are true it renders as complete.
EDIT : So it's definitely something to do with calling the inhibitWhen. Is there something wrong with using two different tables in the one line(l and p)?

Okay so I just gave up on the inhibitWhen and used
(p.attr4 === -1 and l.needToCheckAttr4 === true)
and...
((p.attr4 <> -1 and l.needToCheckAttr4 === true) or (l.needToCheckAttr4 === false))
which I probably should have done in the first place.

Related

Kotlin Exposed get number of rows updated

I am updating some table and I need to check if the update was successful. I am doing this
MyTable.update({ MyTable.name eq "abcd" }) {
it[col1] = "col1 value"
}
In the current state, if I try to update some value that does not exist in DB, even then the call succeeds (probably saying zero rows updated).
How do I know if there was actually a row to be updated or how do I get the number of rows updated?
It is pretty simple. The output of update call returns the count.
val numRowsUpdated = MyTable.update({ MyTable.name eq "abcd" }) {
it[col1] = "col1 value"
}
numRowsUpdated will have the count.

Correct search statement when applying filters

I have created a search function for my React-native app, however, I am not quite sure how to create the correct search statement. What I have now is as follows. You can open a filter screen where you can type a few search criteria (for vehicles) so make, model, color, license plate.
After saving the filters you are re-directed to a result page. On this page, I populate a const with Redux data (the vehicle database) and then filter this data before showing it in flatlist.
const vehicles = useSelector(state => state.uploadedVehicles.vehicles)
const filters = props.navigation.getParam('savedFilters')
const filteredVehicles = vehicles.filter(vehicle =>
vehicle.make === filters.makeFilter ||
vehicle.model === filters.modelFilter ||
vehicle.color === filters.licenseplateFilter ||
vehicle
.licenseplate === filters.licenseplateFilter
)
...return Flatlist with filteredVehicles here...
If I set a filter for a particular Make, only vehicles from this make are found. If I set a filter for a model, only vehicles from this model are found. However, if I set a filter for two statements it now shows vehicles with one matching search criteria. If I would search for a blue Dodge I would find vehicles matching the make Dodge, but also every blue vehicle that is uploaded.
How can I expand my search function so It will show vehicles matching 1 filter, but if 2 or more filters are added it will combine these filters to a more specific search function?
I like to take another approach to this, also using Redux. Here I show you an example code:
case SAVE_FILTERS: {
const appliedFilters = state.filters; // Here you have your filters that have to be
initialized in your state. They also have to be turned to true or false but you can
do it in another function (See next one)
// Here we check every condition
const updatedData = state.data.filter(data => {
if (appliedFilters.filter1 && !data.filter1) {
return false;
}
if (appliedFilters.filter2 && !data.filter2) {
return false;
}
if (appliedFilters.filter3 && !data.filter3) {
return false;
} else {
return true;
}
});
// and now you will return an updated array of data only for the applied filters
return {
...state,
displayData: updatedLocations,
};
The trick is to check every single condition inside of the action. In this particular case, we are checking by filters that are true or not, but you can expand to other conditionals.
The flow for the code above is:
If we have a filter applied AND the data HAS that filter, then we pass the conditional. WE do this for all conditionals. If we pass all of them, return true which means it will be added to the display data and the user will see it.
I hope it helps.
Maybe this isn't the most beautiful way of getting the filter to work. But I didn't quite get my filter working with MIPB his response bit it did push me in the right direction.
I am passing the filters in appliedFilters. Then I constantly checking every filter with the part of the vehicle that is filtered for.
Starting with the make of the vehicle. If the make filter is nog set (so "") I just return the vehicles array which contains every vehicle, else I return every vehicle that is matched with the appliedFilters.makeFilters.
This new makeFilterArray is checked with the modelFilter. If this is not set just set it to the makeFilter array to continue checking other filters, if it is set check the makeFilterArray for the matching model.
Maybe not the best/most elegant solution, but with my limited knowledge I got it working! :-)
case FILTER_VEHICLES:
const appliedFilters = action.setFilters;
console.log(appliedFilters)
console.log(appliedFilters.makeFilter)
console.log(appliedFilters.modelFilter)
console.log(appliedFilters.licenseplateFilter)
console.log(appliedFilters.colorFilter)
const makeFilterArray = appliedFilters.makeFilter === "" ? vehicles : state.vehicles.filter(vehicle => vehicle.make === appliedFilters.makeFilter)
const modelFilterArray = appliedFilters.modelFilter === "" ? makeFilterArray : makeFilterArray.filter(vehicle => vehicle.model === appliedFilters.modelFilter)
const licenseplateFilterArray = appliedFilters.licenseplateFilter === "" ? modelFilterArray : modelFilterArray.filter(vehicle => vehicle.licenplate === appliedFilters.licenseplate)
const filteredArray = appliedFilters.colorFilter === "" ? licenseplateFilterArray : licenseplateFilterArray.filter(vehicle => vehicle.color === appliedFilters.color)
// and now you will return an updated array of data only for the applied filters
return {
...state,
filteredVehicles: filteredArray
};

Adding a new column to a Dataframe by using the values of multiple other columns in the dataframe - spark/scala

I am new to spark SQL and Dataframes. I have a Dataframe to which I should be adding a new column based on the values of other columns. I have a Nested IF formula from excel that I should be implementing (for adding values to the new column), which when converted into programmatic terms, is something like this:
if(k =='yes')
{
if(!(i==''))
{
if(diff(max_date, target_date) < 0)
{
if(j == '')
{
"pending" //the value of the column
}
else {
"approved" //the value of the column
}
}
else{
"expired" //the value of the column
}
}
else{
"" //the value should be empty
}
}
else{
"" //the value should be empty
}
i,j,k are three other columns in the Dataframe. I know we can use withColumn and when to add new columns based on other columns, but I am not sure how I can achieve the above logic using that approach.
what would be an easy/efficient way to implement the above logic for adding the new column? Any help would be appreciated.
Thank you.
First thing, lets simplify that if statement:
if(k == "yes" && i.nonEmpty)
if(maxDate - targetDate < 0)
if (j.isEmpty) "pending"
else "approved"
else "expired"
else ""
Now there are 2 main ways to accomplish this
Using a custom UDF
Using spark built in functions: coalesce, when, otherwise
Custom UDF
Now due to the complexity of your conditions, it will be rather tricky to do number 2. Using a custom UDF should suit your needs.
def getState(i: String, j: String, k: String, maxDate: Long, targetDate: Long): String =
if(k == "yes" && i.nonEmpty)
if(maxDate - targetDate < 0)
if (j.isEmpty) "pending"
else "approved"
else "expired"
else ""
val stateUdf = udf(getState _)
df.withColumn("state", stateUdf($"i",$"j",$"k",lit(0),lit(0)))
Just change lit(0) and lit(0) to your date code, and this should work for you.
Using spark built in functions
If you notice performance issues, you can switch to using coalesce, otherwise, and when, which would look something like this:
val isApproved = df.withColumn("state", when($"k" === "yes" && $"i" =!= "" && (lit(max_date) - lit(target_date) < 0) && $"j" =!= "", "approved").otherwise(null))
val isPending = isApproved.withColumn("state", coalesce($"state", when($"k" === "yes" && $"i" =!= "" && (lit(max_date) - lit(target_date) < 0) && $"j" === "", "pending").otherwise(null)))
val isExpired = isPending.withColumn("state", coalesce($"state", when($"k" === "yes" && $"i" =!= "" && (lit(max_date) - lit(target_date) >= 0), "expired").otherwise(null)))
val finalDf = isExpired.withColumn("state", coalesce($"state", lit("")))
I've used custom udf's in the past with large input sources without issues, and custom udfs can lead to much more readable code, especially in this case.

Kotlin - Problems with while()

I was making a calculator in Kotlin and I'm having trouble solving an issue that I'm having with while().On this particular part of the code, I'm trying to find the first operator in the equation, but I need to exclude the ones that indicate whether a number is negative - (or positive +, optional), which need to be indicated between parentheses like so: (-5)
var charay = charArrayOf('+', '-', '*', '/')
var op = 0
var reference = 0
var bol = false
while( bol == false && op != -1){
println(op)
println(bol)
println(bol == false && op != -1)
op = input.indexOfAny(charay, reference)
if (!input.get(op - 1).equals('(')){
bol = true
}else{
reference = op + 1
}
println(op)
println(bol)
println(bol == false && op != -1)
}
To test a normal equation I entered the equation 4+4 and the console looks like this:
0
false
true
1
true
false
0
false
true
Exception in thread "main" java.lang.StringIndexOutOfBoundsException:
String index out of range: -2
at java.lang.String.charAt(String.java:658)
at CalculatorKt.CalculateValue(Calculator.kt:67)
at CalculatorKt.CalculateValue(Calculator.kt:108)
at CalculatorKt.main(Calculator.kt:119)
Like I suspected, for some reason, the variables reset at the end of the while(), which is the reason why it never leaves said while(). Can anyone tell me why?
Read the error. You're trying to read the character of a string at an index that doesn't exist with this statement:
input.get(op - 1)
You need to check what op is first to make sure it is found. indexOfAny returns -1 if not found in the string. Because we can't see what charay is, we can't help you further.

Why Are My Query Results Coming Back Randomly?

I am querying an SQL database but for some reason the result items are coming back randomly. Here's my code:
for items in searchFriendEmailArrayNew {
let query = table.query(with: NSPredicate(format: "email == '\(items)'"))
query.selectFields = ["isriding"]
query.read { (result, error) in
if let err = error {
print("ERROR ", err)
} else if let items = result?.items {
for item in items {
let theItem = item["isriding"] as! Bool
let newItem = String(theItem)
self.searchFriendIsRidingArray.add(newItem)
loopCount = loopCount+1
if loopCount == self.friendsArray.count {
self.tableView.reloadData()
self.activityIndicator.isHidden = true
self.activityIndicator.stopAnimating()
}
}
}
}
}
The searchFriendEmailArrayNew is an array of email addresses so that when I query the database table it uses the email to look up that user. The array is always consistent and in the same order:
user1#email.com
user2#email.com
user3#email.com
user4#email.com
And the query is always done in that order.
I then query the selected field of the user, in this case I am querying the 'isriding' field. This field is a bool returning true or false.
However, when I get to 'for item in items' the results come back in a random order. For example let's say user1 'is riding = true' but all the other users false, the items returned can look like this:
isriding false
isriding false
isriding true
isriding false
If I then run the code again it might look like this:
isriding true
isriding false
isriding false
isriding false
Can anyone advise as to why they might be coming back in a random order even though when the table is queried it is always queried in a specific order.
Thanks for any help.
You likely need to specify an order when you build the query, otherwise the order of the results is likely not going to be in the same order that you you provided.
The order of a query can be forced by using an 'Order by' Clause in
the statement. A SQL Database does not actually understand what order
you put things in, or store the data in a given order. This means that
you need to tell SQL what order you want the items in.
Why do results from a SQL query not come back in the order I expect?