JSONStore complex queries - ibm-mobilefirst

How would you implement the following query against JSONStore
In SQL format it is
select * from table where (A or B) and (C or D)
I'm assuming we would use an advancedFind operation with an array of QueryParts, however in the samples I can see how you can use QueryParts to form and AND but not how to form an OR query.
Any guidance appreciated.

Taking your example SQL and giving it values it would look like this:
select * from people where (name = 'carlos' or name = 'mike') AND (rank = 'king' or rank = 'pawn')
Which is the same as:
select * from people where (name = 'mike' AND rank = 'king') or (name = 'carlos' AND rank = 'pawn') or (name = 'carlos' AND rank = 'king') or (name = 'mike' and rank = 'pawn')
That can be expressed by JSONStore pseudocode like this:
var queryPart1 = WL.JSONStore.QueryPart()
.equal('name', 'mike') //and
.equal('rank', 'king');
//or
var queryPart2 = WL.JSONStore.QueryPart()
.equal('name', 'carlos') //and
.equal('rank', 'pawn');
//or
var queryPart3 = WL.JSONStore.QueryPart()
.equal('name', 'carlos') //and
.equal('rank', 'king');
//or
var queryPart4 = WL.JSONStore.QueryPart()
.equal('name', 'mike') //and
.equal('rank', 'pawn');
WL.JSONStore.get('people').advancedFind([queryPart1, queryPart2, queryPart3, queryPart4])
.then(...);
Everything inside a query part must match (i.e. it's like an and) and as long as one query part matches (i.e. it's like an or) results will be returned. Remember to work with top-level search fields.
Sometimes these fairly complex searches are required, but more often than not I would recommend re-thinking the offline experience. I wrote about that here.
FYI - Feature requests here. Bug reports here.

Related

cfsavecontent display double apostrophe in SQL statement

I have several OR in my SQL statement so I want to save a chuck of it in a cfsavecontent. Here is that part:
<cfsavecontent variable="checkDepartment">
<cfif #wrkDept# EQ #dept[2][1]#>
Department = 'Health' AND
<cfelse>
Department = '#wrkDept#' AND
</cfif>
</cfsavecontent>
But the error I get on the page shows 2 sets of apostrophes around the word Health.
SQL
SELECT COUNT(*) AS numItems
FROM IT_PROJECTS
WHERE
Department = ''Health'' AND
status = 'Cancelled'
Can anyone help me to only get a single apostrophe? Thanks
So this answer seems a lot more complicated than it really is. And without knowing specifically what your query looks like (re:OR conditions), I'm not really sure how to structure it. It can be better. The goal should be to make one single trip to your SQL server with the query that makes the most sense for the data you're trying to get. I'm not sure what you are trying to do with cfsavecontent, but I don't think you need it.
The bulk of my example query (https://trycf.com/gist/4e1f46bfa84a6748aced0f9ee8221c6d/acf2016?theme=monokai) is setup. I chose to go with a cfscript format, because as Redtopia said, I also find it much easier to build a dynamic query in cfscript.
After initial setup, I basically just script out the variables I'll use in my final queryExecute().
// Base query.
qry = "SELECT count(*) AS theCount FROM IT_PROJECTS WHERE 1=1 " ;
// This is our dynamic filter that we build below.
qfilter = {} ;
// Query options.
opts = { "dbtype":"query" } ;
After we have our base, I build up the dynamic part of the query. This is the part that will likely change quite a bit depending on your current needs and setup.
For the first part, I basically replaced your cfif with a ternary evaluation. I'm not sure how your data plays into the evaluation of dept or where that array comes from. But from there I build a basic included statement of the query and set up the queryparam values for it. Then I add a second check that will pick a different set of values for the query (currently based on even/odd seconds). Again, I'm not sure of the intent of your query here, so I just made something dynamic.
//////////// BUILD DYNAMIC FILTER ////////////
qdept = ( wrkDept == dept[2][1] ) ? 'Health' : wrkDept ;
/// This one is an included filter:
qry &= " AND department = :dpt AND status = :sts " ;
qfilter.dpt = {"value":qdept,"cfsqltype":"CFSQLVARCHAR"} ;
qfilter.sts = {"value":"Cancelled","cfsqltype":"CFSQLVARCHAR"} ;
/// Adding Dynamic ORs
// Dynamically set status based on even/odd seconds.
qStatus = ( now().second()%2==0) ? "Cancelled" : "Active" ;
qry &= " OR ( department = :dpt2 AND status = :sts2 ) " ;
qfilter.dpt2 = {value:"IT",cfsqltype:"CFSQLVARCHAR"} ;
qfilter.sts2 = {value:qStatus,cfsqltype:"CFSQLVARCHAR"} ;
This gives us a SQL string that looks like:
SELECT count(*) AS theCount
FROM IT_PROJECTS
WHERE 1=1
AND department = :dpt AND status = :sts
OR
( department = :dpt2 AND status = :sts2 )
With a SQL statement, the placement of AND and OR conditions can greatly impact the results. Use parenthesis to group conditions how you need them.
After we've built the query string, we just have to plug it and our queryparams into the queryExecute().
result = queryExecute( qry , qfilter , opts ) ;
And if we want to output our data, we can go:
writeOutput("There are " & result.theCount & " records." ) ;
Which gives us:
There are 8 records.
Again, I don't know what your main conditions look like. If you can give me an example of a query with a bunch of ORs and ANDs, I'll try to modify this for you.

How do I write a contains statement in linq?

I want to select records where any of the selected fields is a 1.
decimal myNumber = 1;
query = from q in query where myNumber.Contains(q.trial, q.score, q.id) select q;
in sql I would write
select trial, score, id
from query q
where 1 in (q.trial, q.score, q.id)
How do I duplicate the sql using linq?
You could use an array and use Contains method, for sample:
var query = from q in query
where new[]{q.trial, q.score, q.id}.Contains(myNumber)
select q;
The oposite, when you have many values and you need to compare with an single column, you could do something like this:
var myValues = new[] {1, 2, 3, 4, 5};
var query = from q in query
where myValues.Contains(q.trial)
select q;
Elaborating a bit more on #Felipe's post:
var found = from q in query
let arr = new []{ q.trial, q.score, q.id}
where arr.Contains(1)
select q;
EDIT: looks like #Felipe updated his post to use dynamically created arrays. I'm going to leave my post in to demonstrate the usage of variables within the LINQ query (let). This is useful to know for occasional cases.

How to execute query with subqueries on a table and get a Rowset object as a result in Zend?

I'm currently struggling on how to execute my query on a Table object in Zend and get a Rowset in return. Reason I need particularly THIS is because I'm modifying a code for existing project and I don't have much flexibility.
Query:
SELECT *
FROM `tblname` ud
WHERE ud.user_id = some_id
AND
(
(ud.reputation_level > 1)
OR
(
(SELECT COUNT( * )
FROM `tblname` t
WHERE t.user_id = ud.user_id
AND t.category_id <=> ud.category_id
AND t.city_id <=> ud.city_id
) = 1
)
)
Is there a way to describe this query using Select object?
Previous SQL solution was very simple and consisted of one WHERE clause:
$where = $this->getAdapter()->quoteInto("user_id = ?",$user_id);
return $this->fetchAll($where);
I need to produce same type of the result (so that it could be processed by existing code) but for more complicated query.
Things I've tried
$db = Zend_Db_Table::getDefaultAdapter();
return $db->query($sql)->fetchAll();
---------------- OR ----------------------
return $this->fetchAll($select);
---------------- OR ----------------------
return $this->_db->query($sql)->fetchAll();
But they either produce arrays instead of objects or fail with Cardinality violation message.
I would appreciate any help on how to handle SQL text queries in Zend.
$dbAdapter = Zend_Db_Table::getDefaultAdapter();
//change the fetch mode becouse you don't like the array
$dbAdapter->setFetchMode(Zend_Db::FETCH_OBJ);
$sql = "you're long sql here";
$result = $dbAdapter->fetchAll($sql);
Zend_Debug::dump($result);
exit;
For a list of all fetch modes go to Zend_Db_Adapter
To write you're query using Zend_Db_Select instead of manual string , look at Zend_Db_Slect

constructing dynamic In Statements with sql

Suppose we need to check three boolean conditions to perform a select query. Let the three flags be 'A', 'B' and 'C'.
If all of the three flags are set to '1' then the query to be generated is
SELECT * FROM Food WHERE Name In ('Apple, 'Biscuit', 'Chocolate');
If only the flags 'A' and 'B' are set to '1' with C set to '0'. Then the following query is generated.
SELECT *
FROM Food
WHERE Name In ('Apple, 'Biscuit');
What is the best way to do it?
SELECT *
FROM Food
WHERE (Name = 'Apple' AND <condition A>)
OR (Name = 'Biscuit' AND <condition B>)
OR (Name = 'Chocolate' AND <condition C>)
Now, while being correct this is not desirable from performance point of view since conditions A, B, and C are not data driven (they don not change from row to row). So you can use permutations of all possible conditions by constructing SQL dynamically - use IN clause and construct its string dynamically.
Yet another solution is assembling final result in the client by running each SELECT separately (pseudo-code):
if A then {
result1 = execute("SELECT * FROM Food WHERE Name = 'Apple')
}
if B then {
result2 = execute("SELECT * FROM Food WHERE Name = 'Biscuit')
}
if C then {
result2 = execute("SELECT * FROM Food WHERE Name = 'Chocolate')
}
result = join(result1, result2, result3)
This solution may work when you have high percentage of cases with just one or two true conditions.
First may be you need to check if all are false and show error. Or may be not if it is acceptable in your case.
Then if these flags are mere bool variables do (pseudocode)
sql = "SELECT *
FROM Food
WHERE Name In (";
if (A) sql += "'Apple', "
if (B) sql += "'Biscuit', "
if (C) sql += "'Chocolate', "
sql = sql.deleteLastCharacter() + ");";
Why don't you include A/B/C in the query?
select * from food where (name = 'Apple' or NOT A) and (name = 'Biscuit' OR NOT B)...
I think this should be read: Dynamic SQL.
The sp_executesql system stored procedure reveals to be pretty useful also.
This is a really complex topic that has many subtle performance implications. You really need to read these excellent articles by Erland Sommarskog:
Dynamic Search Conditions in T-SQL
The Curse and Blessings of Dynamic SQL

SELECT MAX query returns only 1 variable + codeigniter

I use codeigniter and have an issue about SELECT MAX ... I couldnot find any solution at google search...
it looks like it returns only id :/ it's giving error for other columns of table :/
Appreciate helps, thanks!
Model:
function get_default()
{
$this->db->select_max('id');
$query = $this->db->getwhere('gallery', array('cat' => "1"));
if($query->num_rows() > 0) {
return $query->row_array(); //return the row as an associative array
}
}
Controller:
$default_img = $this->blabla_model->get_default();
$data['default_id'] = $default_img['id']; // it returns this
$data['default_name'] = $default_img['gname']; // it gives error for gname although it is at table
To achieve your goal, your desire SQL can look something like:
SELECT *
FROM gallery
WHERE cat = '1'
ORDER BY id
LIMIT 1
And to utilise CodeIgniter database class:
$this->db->select('*');
$this->db->where('cat', '1');
$this->db->order_by('id', 'DESC');
$this->db->limit(1);
$query = $this->db->get('gallery');
That is correct: select_max returns only the value, and no other column. From the specs:
$this->db->select_max('age');
$query = $this->db->get('members');
// Produces: SELECT MAX(age) as age FROM members
You may want to read the value first, and run another query.
For an id, you can also use $id = $this->db->insert_id();
See also: http://www.hostfree.com/user_guide/database/active_record.html#select
CodeIgniter will select * if nothing else is selected. By setting select_max() you are populating the select property and therefore saying you ONLY want that value.
To solve this, just combine select_max() and select():
$this->db->select('somefield, another_field');
$this->db->select_max('age');
or even:
$this->db->select('sometable.*', FALSE);
$this->db->select_max('age');
Should do the trick.
It should be noted that you may of course also utilize your own "custom" sql statements in CodeIgniter, you're not limited to the active record sql functions you've outlined thus far. Another active record function that CodeIgniter provides is $this->db->query(); Which allows you to submit your own SQL queries (including variables) like so:
function foo_bar()
{
$cat = 1;
$limit = 1;
$sql = "
SELECT *
FROM gallery
WHERE cat = $cat
ORDER BY id
LIMIT $limit
";
$data['query'] = $this->db->query($sql);
return $data['query'];
}
Recently I have been utilizing this quite a bit as I've been doing some queries that are difficult (if not annoying or impossible) to pull off with CI's explicit active record functions.
I realize you may know this already, just thought it would help to include for posterity.
2 helpful links are:
http://codeigniter.com/user_guide/database/results.html
http://codeigniter.com/user_guide/database/examples.html