Alias for an aggregate column - kotlin

I would like to get the average of a column using Kotlin Exposed.
object MyTable: IntIdTable("MyTable") {
val score = integer("score")
val result = MyTable.slice(
MyTable.score.avg().alias("avg_points")
).first()
How do I get the result?
For normal columns I would use
result[MyTable.score]
But now it is an aggregate with an alias. I've tried
result["avg_points"]
But that fails. I don't see many public methods on ResultRow.

Try this.
First save the average to a variable
val avgColumn = MyTable.score.avg().alias("avg_points")
Then get the results as such
val result = MyTable.slice(
avgColumn
).selectAll().first()
val avg = result[avgColumn]

Related

Update database row by id fails

I'm trying to update a specific row by ID :
fun updateEmployeeInfo(id:Int, firstName:String): Int {
val db = this.writableDatabase
var cv = ContentValues()
cv.put(COL_FIRSTNAME, firstName )
val result = db.update(TABLE_NAME, cv, COL_FIRSTNAME+"=?", arrayOf(firstName))
return result
}
Running this with an ID that already exists in the database it isn't updating.
screenshot of the database
You are saying update the rows with the provided (passed) first name by changing the first name to the very same first name (effectively doing nothing).
I believe that you want to use:-
val result = db.update(TABLE_NAME, cv, COL_ID+"=?", arrayOf(id.toString))
assuming that COL_ID holds the value of the id column name.
or you could use the more concise return db.update(TABLE_NAME, cv, COL_ID+"=?", arrayOf(id.toString))
This is then saying update the row where the id is the provided/passed id changing the first name, whatever it is, to the provided/passed first name.

Pass date values from dataframe to query in Spark /Scala

I have a dataframe having a date column and has values as below.
df.show()
+----+----------+
|name| dob|
+----+----------+
| Jon|2001-04-15|
| Ben|2002-03-01|
+----+----------+
Now i need to query a table in hive which has "dob" from above dataframe (both 2001-04-15, 2002-03-01).So I need to pass the values under dob column as a parameter to my hive query.
I tried to collect the values to a variable like below which give me array of string.
val dobRead = df.select("updt_d").distinct().as[String].collect()
dobRead: Array[String] = Array(2001-04-15, 2002-03-01)
However when i try to pass to the query i see its not substituting properly and get error.
val tableRead = hive.executeQuery(s"select emp_name,emp_no,martial_status from <<table_name>> where dateOfBirth in ($dobRead)")
org.apache.hadoop.hive.ql.metadata.HiveException: Failed to compile query: org.apache.hadoop.hive.ql.parse.ParseException: line 1:480 cannot recognize input near '(' '[' 'Ljava' in expression specification
Can you please help me how to pass date values to a query in spark.
You can collect the dates as follows (Row.getAs):
val rows: Array[Row] = df.select("updt_d").distinct().collect()
val dates: Array[String] = rows.map(_.getAs[String](0))
And then build the query:
val hql: String = s"select ... where dateOfBirth in (${
dates.map(d => s"'${d}'").mkString(", ")
})"
Option 2
If the number of dates in first DataFrame is too big, you should use join operations instead of collecting them into the driver.
First, load every table as DataFrames (I'll call them dfEmp and dfDates). Then you can join on date fields to filter, either using a standard inner join plus filtering out null fields or using directly a left_semi join:
val dfEmp = hiveContext.table("EmpTable")
val dfEmpFiltered = dfEmp.join(dfDates,
col("dateOfBirth") === col("updt_d"), "left_semi")

INSERT INTO SELECT in Slick that runs on the server. Is it possible?

I’m going to duplicate some records in table tbl.
It looks like
INSERT INTO tbl SELECT id+100, name FROM tbl
in plain SQL.
I expected that it could look like
db.run(
tableQuery.forceInsertQuery(
tableQuery.map{rec=>rec.copy(id=rec.id+100)}
))
in Slick, where
rec is an instance of Table[ScalaCaseClassForTbl]
with
val id = column[Int]("id", O.PrimaryKey)
val name = column[String]("name")
and
override def * : ProvenShape[ScalaCaseClassForTbl] =
But I do not understand how to make map.
Thank you for any ideas.
The problem with...
tableQuery.map{rec=>rec.copy(id=rec.id+100)}
...is that rec is not a case class, so there's not a copy.
What you can do is map to a tuple of the columns (the Rep[T]) values) and then convert that to a case class.
For example:
tableQuery.map{ rec =>
(rec.id+100, rec.name).mapTo[YourCaseClass]
}

Filter result from database where row is null

I want to display all rows from database where row at specified column is empty (data is not inserted). To do that, in my onCreateLoader I wrote following code:
override fun onCreateLoader(p0: Int, p1: Bundle?): Loader<Cursor> {
val projection = arrayOf(
WalletEntry._ID,
WalletEntry.KEY_TITLE,
WalletEntry.KEY_MONEY,
WalletEntry.KEY_LAST_DATE,
WalletEntry.KEY_LAST_EXPENSE,
WalletEntry.KEY_LAST_TRANSACTION_TITLE,
WalletEntry.KEY_LOCALES,
WalletEntry.KEY_CURRENCY
)
val selection = "${WalletEntry.KEY_CURRENCY} = ?"
val selectionArgs = arrayOf("")
return applicationContext?.let { context ->
CursorLoader(context,
WalletEntry.CONTENT_URI,
projection,
selection,
selectionArgs,
null)
}!!
}
Where I want to display all results where WalletEntry.KEY_CURRENCY has no signed value, is empty. I tried to specify selectionArgs as null but it neither worked. So, how am I suppose to write selectionArgs to display all results where given row is empty?
To make my situation more clear I'll provide an app target. I'm learning kotlin and decided to write something like "bank" application where you can add different wallets and specify currencies. If you add a new currency it's being instantly added to the database to the column WalletEntry.KEY_CURRENCY. Then I have a list containing all "wallets", in which after adding a new currency an empty extra wallet appears. To avoid that I want to filter results and display only those, which do not have value passed in WalletEntry.CURRENCY column.
If you're looking for NULL values in that database column, I think you might be looking for:
val selection = "${WalletEntry.KEY_CURRENCY} IS NULL"
val selectionArgs = null
If the selectionArgs argument is not nullable, try setting it to emptyArray<String>()

QueryDSL like operation SimplePath

Similarly to this question I would like to perform an SQL "like" operation using my own user defined type called "AccountNumber".
The QueryDSL Entity class the field which defines the column looks like this:
public final SimplePath<com.myorg.types.AccountNumber> accountNumber;
I have tried the following code to achieve a "like" operation in SQL but get an error when the types are compared before the query is run:
final Path path=QBusinessEvent.businessEvent.accountNumber;
final Expression<AccountNumber> constant = Expressions.constant(AccountNumber.valueOfWithWildcard(pRegion.toString()));
final BooleanExpression booleanOperation = Expressions.booleanOperation(Ops.STARTS_WITH, path, constant);
expressionBuilder.and(booleanOperation);
The error is:
org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [7!%%] did not match expected type [com.myorg.types.AccountNumber (n/a)]
Has anyone ever been able to achieve this using QueryDSL/JPA combination?
Did you try using a String constant instead?
Path<?> path = QBusinessEvent.businessEvent.accountNumber;
Expression<String> constant = Expressions.constant(pRegion.toString());
Predicate predicate = Expressions.predicate(Ops.STARTS_WITH, path, constant);
In the end, I was given a tip by my colleague to do the following:
if (pRegion != null) {
expressionBuilder.and(Expressions.booleanTemplate("{0} like concat({1}, '%')", qBusinessEvent.accountNumber, pRegion));
}
This seems to do the trick!
It seems like there is bug/ambiguity. In my case, I need to search by couple fields with different types (String, Number), e.g. SQL looks like:
SELECT * FROM table AS t WHERE t.name = "%some%" OR t.id = "%some%";
My code looks like:
BooleanBuilder where = _getDefaultPredicateBuilder();
BooleanBuilder whereLike = new BooleanBuilder();
for(String likeField: _likeFields){
whereLike = whereLike.or(_pathBuilder.getString(likeField).contains(likeValue));
}
where.and(whereLike);
If first _likeFields is type of String - request works fine, otherwise it throws Exception.