Query criteria for matching 3 of 6 fields - kotlin

I would like to select rows in the Corda (M14) database with a criteria that matches at least 3 of 6 fields and sort these results by matching fields.
Here is the SQL syntax to select fields:
WHERE (field1 = ?) + (field2 = ?) + (... = ?) > 3
and to order it:
ORDER BY ((field1 = ?) + (field2 = ?) + (... = ?)) DESC
Another way of doing it :
SELECT *, ((field1 = #inputFirst) + (field2 = #inputLast)) as Matches
FROM mytable
HAVING Matches > 1
ORDER BY Matches DESC
I started to create the criteria:
vaultCriteria
.or(QueryCriteria.VaultCustomQueryCriteria(field1))
.or(QueryCriteria.VaultCustomQueryCriteria(field12))
.or(QueryCriteria.VaultCustomQueryCriteria(field3))
But I am stuck now on how to GROUP theses results by fields' matching number and SORT these, any ideas ?
Thank you,
Loup

I haven't tested how far it's possible to take the API, but I've had success (on current Master) by writing custom SQL - e.g.
val session = services.jdbcSession()
val consensusQuery = """
SELECT COUNT(*) - COUNT(NULLIF(factObject, ?)), COUNT(*)
FROM submission_states
WHERE factSubject = ? AND factPredicate = ?
"""
val consensusStatement = session.prepareStatement(consensusQuery)
consensusStatement.setString(1, factConsensusQuery.factObject)
consensusStatement.setString(2, factConsensusQuery.factSubject)
consensusStatement.setString(3, factConsensusQuery.factPredicate)
log.info("SQL to execute: " + consensusStatement.toString())
val rs = consensusStatement.executeQuery()

For M14 release you have 2 options:
1) Get a jdbcSession directly from the DatabaseTransactionManager:
val jdbcSession1 = DatabaseTransactionManager.current().connection
2) Get a jdbcSession indirectly from a RequeryConfiguration object:
val jdbcSession2 = RequeryConfiguration(<dataSourceProperties>).jdbcSession()
where <dataSourceProperties> looks something like this:
private fun makePersistentDataSourceProperties(): Properties {
val props = Properties()
props.setProperty("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
props.setProperty("dataSource.url", "jdbc:h2:~/test/vault_query_persistence;DB_CLOSE_ON_EXIT=TRUE")
props.setProperty("dataSource.user", "sa")
props.setProperty("dataSource.password", "")
return props
}

For advanced custom SQL queries it is recommended you use a standard JDBCSession, obtainable from the ServiceHub.
Please see https://docs.corda.net/head/api-persistence.html?highlight=jdbcsession

Related

Entity Framework cast selected fields to varchar and concat them

I want do below query in Entity Framework
select
cast(p_min as varchar) + '' + cast(p_max as varchar)
from
user_behave_fact
where
beef_dairy_stat = 'True' and param_id = 2
group by
p_min,p_max
go
Since you have not mentioned a language, I am writing code in C#.
Try this:
using (var dbContext = new DatabaseContext())
{
var output = (
from fact in dbContext.user_behave_facts
where fact.beef_dairy_stat == "True" && fact.param_id == 2
group fact by new {fact.p_min, fact.p_max} in grp
select new
{
ColName = grp.Key.p_min.ToString() + " " + grp.Key.p_max.ToString()
}
).ToList();
}
.ToList() can be changed according to your expectations

How to write the HAVING clause with SQL COUNT(DISTINCT column_name) function in Codeigniter Active Record?

I am using Codeigniter and am trying to use the Active Record Class for all my database operations.
However, I did run into problems when trying to convert the last bid of the following (working) query into Active Record code.
$sql = ("SELECT ac.cou_id
FROM authorcourse ac
INNER JOIN course c
ON ac.cou_id = c.cou_id
WHERE cou_name = ? // ? = $cou_name
AND cou_number = ? // ? = $cou_number
AND cou_term = ? // ? = $cou_term
AND cou_year = ? // ? = $cou_year
AND FIND_IN_SET (ac.aut_id, ?) //? = $aut_ids_string
GROUP BY ac.cou_id
HAVING COUNT(DISTINCT ac.aut_id) = ? //? = $aut_quantity
AND COUNT(DISTINCT ac.aut_id) = (SELECT COUNT(DISTINCT ac2.aut_id)
FROM authorcourse ac2
WHERE ac2.cou_id = ac.cou_id)");
$query = $this->db->query($sql, array($cou_name, $cou_number, $cou_term, $cou_year, $aut_ids_string, $aut_quantity));
Question: How do I convert the HAVING clause into valid Active Record code?
I tried using $this->db->having(); and $this->db->distinct(); but failed to combine the functions to achieve the desired result.
My (working) code so far:
$this->db->select('ac.cou_id');
$this->db->from('authorcourse ac');
$this->db->join('course c', 'c.cou_id = ac.cou_id');
$this->db->where('cou_name', $cou_name);
$this->db->where('cou_number', $cou_number);
$this->db->where('cou_term', $cou_term);
$this->db->where('cou_year', $cou_year);
$this->db->where_in('ac.aut_id',$aut_ids);
$this->db->group_by('ac.cou_id');
// missing code
Thanks a lot!
You code seems quite clumsy. But, you can use having clause in the following way:
$this->db->having("ac.aut_id = '".$aut_qty."'", null, false)

google spreadsheet query function column id other than letter of column

alright... not sure if these could be done.
i'm in google spreadsheets with cell A1 = time.. the range is A1:C4.
i have a simple table as follows:
time sit stand
1 bob mike
2 fred pat
3 chris mike
This my query:
=query($A$1:$C$4,"select A,B,C where C='mike'",0)
... pretty straight forward. however, I want the column reference to be dynamic. So i need to be able to query using the header. how do i do it? I've already tried the following:
=query($A$1:$C$4,"select 'sit ', 'stand' where 'stand' = 'mike' ",0)
=query($A$1:$C$4,"select sit, stand where stand = 'mike' ",0)
and per this page's suggestion:
Google spreadsheet Query Error - column doesn't exist
I've also tried the following:
=query($A$1:$C$4,"select Col2, Col3 where Col3 = 'mike' ",0)
=query($A$1:$C$4,"select Col2, Col3 where (Col3) = 'mike' ",0)
=query($A$1:$C$4,"select (Col2), (Col3) where (Col3) = 'mike' ",0)
=query($A$1:$C$4,"select 'Col2', 'Col3' where 'Col3' = 'mike' ",0)
None of them work... does anybody know how to do it or know if it is possible?
https://developers.google.com/chart/interactive/docs/querylanguage
the examples here seems like you can do it, but is that for app script only? and not in the spreadsheet function?
Unfortunately there is no native way of referencing columns by their headers in the QUERY spreadsheet function select clause.
You can use the Colx notation if the first argument of the QUERY is anything other than an explicitly referenced range. One way to achieve this is wrap the range in parentheses, and invoking ArrayFormula:
=ArrayFormula(QUERY(($A$1:$C$4),"select Col2, Col3 where Col3 = 'mike'",0))
And it is rather ugly, but you can use the MATCH function to bolt in header references:
=ArrayFormula(QUERY(($A$1:$C$4),"select Col"&MATCH("sit";$A$1:$C$1;0)&", Col"&MATCH("stand";$A$1:$C$1;0)&" where Col"&MATCH("stand";$A$1:$C$1;0)&" = 'mike'",1))
I have also came across this problem without a solution, so I've have written a script which will allow column references within a query.
To use:
1. Create a separate sheet and set "[SHEET NAME]" to the name of the data sheet
2. Create a Name Range (from tools menu) which is the row which the columns ids are stored eg A1:K1
3. change[COLUMNIDs ROW REFERENCE] in the code to the named range.
Now while querying simple prefix a $ character before the column id example:
=QUERY([SHEET_NAME]!A4:F, _Select(" * WHERE $[COLUMNID] < $[COLUMNID2]")
function _Select(squery){
var sheetName = "[SHEET NAME]";
var sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
var colIndex = sheet.getDataRange().getColumn();
var colIndex2 = sheet.getDataRange().getLastColumn();
var rangeString = sheetName+"!"+sheet.getRange(3, colIndex, 1, colIndex2).getA1Notation();
return "SELECT "+yq(rangeString, squery);
}
function yq(range, sQuery) {
var sheetName = SpreadsheetApp.getActiveSheet().getSheetName();
if( (typeof range == "object") && (range !== null) ){
sheetName = range.getSheet().getName();
range = range.getA1Notation();
}else{
var tRange = range.split("!");
if(tRange.length > 1){
sheetName = tRange[0]
range = tRange[1];
}
}
var sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
var range = sheet.getRange(range);
var qInput = sQuery.split(" ");
var outQuery = [];
for(var i = 0; i < qInput.length; i++){
if(qInput[i].charAt(0) == "$"){
var colIndex = getHeaderValues(sheet, qInput[i].slice(1), range, "[COLUMNIDs ROW REFERENCE]");
outQuery.push(colIndex.toString());
}else{
outQuery.push(qInput[i]);
}
}
return outQuery.join(" ");
}
function getHeaderValues(sheet, columnName, range, columnHeaderRow){
var columnHeaderRowIndex = range.getRowIndex() - 1;
if(!isNaN(parseFloat(columnHeaderRow)) && isFinite(columnHeaderRow)){
columnHeaderRowIndex = range.getRowIndex() + columnHeaderRow;
}else if(typeof columnHeaderRow == "string"){
columnHeaderRowIndex = SpreadsheetApp.getActive().getRangeByName(columnHeaderRow).getRowIndex();
}
var numColumns = range.getLastColumn() - range.getColumn() + 1;
var headersRange = sheet.getRange(columnHeaderRowIndex, range.getColumn(), 1, numColumns);
var headers = headersRange.getValues()[0];
var hIndex = null;
for(var i = 0; i < headers.length; i++){
if(headers[i] == columnName){
hIndex = headersRange.getColumn() + i;
hIndex = sheet.getRange(headersRange.getRow(), hIndex).getA1Notation();
return hIndex.charAt(0);
}
}
return null;
}
Hi I have another solution. I broke Lines that the hole thing can be read.
=query($A$1:$C$4,"select "
&CHAR(MATCH("time";1:1;0)+64)
&","
&CHAR(MATCH("sit";1:1;0)+64)
&","
&CHAR(MATCH("stand";1:1;0)+64)
&"where C='mike'",0)
Still not nice, and you are limmited to 24 Columns. Since after that you need to split. Dont like it at all :(
There are two things I've found you can do to improve Query column references:
Place column references searches in another cell (legend) and use
=query(A:C,"select "&D2&" where "&E2&" starts with '"&E3&"' ")
where for example D2 = A, E2 = C, E3 = foo
This has the benefit of allowing you to change the Query terms by editing cells rather than formulas and also doesn't break when you add/move columns around. You can take it further and name the ranges to make it look like
=query(A:C,"select "&cats&" where "&name&" starts with '"&search&"' ")
Switch it to Col[n] reference mode by messing with the range
=query({A:C},"select Col1 where Col3 matches 'foo' ")
This gives you the ability to move the dataset around without breaking it, but will break down if you insert more columns into the range.
I have found a workaround that is useful, you can name columns as named ranges and then you query those specific columns, some caveats is that you can't do that with large databases
=QUERY({employee,score},"select Col1,avg(Col2) group by Col1")

SQL date comparison in WHERE clause, TypoScript

I want to compare dates in a TypoScript select.
Here's what I have (note that I commented the were clauses) :
lib.my_val = CONTENT
lib.my_val {
select {
pidInList = 100000
max = 1
#where = effective_date < CURDATE()
#where = TIMESTAMP(effective_date) < NOW()
orderBy = effective_date DESC
}
table = tx_my_table
renderObj = COA
renderObj {
5 = TEXT
5{
field = my_field
wrap = <span>|</span>
}
[...]
}
}
Which returns lines.
I tried to add a where statement any way I could with static dates or variables... without success. My understanding of the where clause is that everything after the = is dumped as is in the SQL query. But it seems I missed something.
Basically I want the TypoScript to generate a SQL Query smilar to this :
SELECT * FROM tx_my_table WHERE effective_date < NOW() ORDER BY effective_date DESC LIMIT 1;
This should be simple. Has anyone done this in the past?
Thanks!
Your TypoScript seems to be OK.
What happens if you enter the SQL Query directly into MySQL?
Note that with your code, only one record with pid=100000 is
selected.
Have you tried this:
--
lib.my_val {
select {
pidInList = 100000
max = 1
where = UNIX_TIMESTAMP(effective_date) < UNIX_TIMESTAMP()
orderBy = UNIX_TIMESTAMP(effective_date) DESC
}
table = tx_my_table
}
TYPO3 Wiki on select

Parameterized LIKE clause in SQL statement using Dapper

I want to perform the following query using Dapper, which currently doesn't return expected results (I think it must be treating the #pName param as literal text within the single quotes?):
var q = "SELECT * FROM Users WHERE Name LIKE '#pName%'";
#pName is the param I assign a value to upon executing the query.
Things work if I just build the SQL like:
var q = "SELECT * FROM Users WHERE Name LIKE '" + name + "%'";
.. but I would prefer to use a param if possible.
I am executing the query using the following code:
o = _cn.Query<User>(q, new { pName = new DbString { Value = name, IsFixedLength = false, Length = 25, IsAnsi = true } }).ToList();
How do I got about this using Dapper?
SELECT * FROM Users WHERE Name LIKE #pName + '%'
I would like to add here another possible solution:
var results = cn.Query("SELECT * FROM Table WHERE Column LIKE #value", new { value = value + "%" });
The wildcard is inside the string var itself, and then we reference that var in the SQL. Applies to any wildcard pattern you want.