On a CakePHP 3 project I want to run a select in my controller. The user could choose different filtering conditions for the select. If a condition is not choosed, I do not need it in my select.
Now I have something like this
$where = [];
if ( ! empty($this->request->data['fcontact_id'])){
$where['Histories.contact_id'] = $this->request->data['fcontact_id'];
}
if ( ! empty($this->request->data['fuser_id'])){
$where['Histories.user_id'] = $this->request->data['fuser_id'];
}
if ( ! empty($this->request->data['fgroup_id'])){
$where['Histories.group_id'] = $this->request->data['fgroup_id'];
}
$histories = $this->Histories->find()->where($where);
Is there any better way to do it?
I would use one of the available search plugins:
https://github.com/friendsofcake/search
or
https://github.com/skie/plum_search
or
https://github.com/CakeDC/search
Related
I have two tables:
cache and main
In cache there are a lot of fields; in main a little less. A UNION is not going to work because of the unequal number of columns.
cache
client - file - target - many other columns
main
client - file - target - few other columns
From cache I would like all columns for which main.target LIKE '%string%', cache.client = main.client, cache.file = main.file
For these particular records, target, client and file are always the same in main and cache.
I just can't get my head around this, but then again MySQL never was my strongest point.
Thank you very much in advance!
In the end combining the two SELECT statements with a UNION made things very complicated, for the simple reason there were countless other queries, some without UNION, that in the end all had to be processed by the same end routine presenting the results. As this was only a one-time query and time wasn't really an issue, in the end I just used SELECT on the two different tables and then combined the results by checking if a certain field was present. If not, the remaining results had to be fetched from the cache table; if so, the remaining results had to be fetched from the main table.
I actually wonder whether this solution is faster, slower or just as fast.
if (!isset($row['current']))
{
$field = $row['field'];
$sqlcache = "SELECT * FROM " . $dbtable . " WHERE (client = '$sqlclient' AND file = '$sqlfile' AND field = '$field')";
$resultcache = $conn->query($sqlcache);
if (!$resultcache)
{
die($conn->error);
}
$rowcache = $resultcache->fetch_assoc();
$currenttarget = $rowcache['current'];
$context = $rowcache['context'];
$dirtysource = $rowcache['dirtysource'];
$stringid = $rowcache['stringid'];
$limit = $rowcache['maxlength'];
$locked = $rowcache['locked'];
$filei = $rowcache['filei'];
}
else
{
$currenttarget = $row['current'];
$context = $row['context'];
$dirtysource = $row['dirtysource'];
$stringid = $row['stringid'];
$limit = $row['maxlength'];
$locked = $row['locked'];
$filei = $row['filei'];
}
I have few tables which are joined by some conditions.
What I am trying to achieve is Combine 2 SELECT statements in such way where
If there is data in Condition 1 display them OR go to Condition 2 and display data
Condition 1 - I am getting record from table say for exampleA, B, C and D based on some conditions
Condition 2 - I am getting record from table say for example A, B, C and E based on some conditions
What is am trying to achieve is
Display record if it exists in Condition 1
OR
Display record if it exits in Condition 2
Condition 1/ Query 1 - Display data
async getData() {
try {
const data = await this._conn.query(`
select first_name.value_name,quiz_table.answer, windows,player,first_name.value_id,country_place,current_name, pet_name, marker, relations
from schema_name.plugin,schema_name.quiz_table,schema_name.first_name, schema_name.value_version, schema_name.relationss
where plugin.answer= quiz_table.answer
and quiz_table.windows=first_name.value_id
and marker is not null
and schema_name.value_version.value_id= schema_name.first_name.value_id
and schema_name.value_version.caste= schema_name.first_name.caste
and schema_name.value_version.value_name= schema_name.first_name.value_name
and schema_name.value_version.version_number= schema_name.first_name.version_number
and schema_name.relationss.value_id= schema_name.first_name.value_id
and schema_name.relationss.caste= schema_name.first_name.caste
and schema_name.relationss.value_name= schema_name.first_name.value_name
and schema_name.relationss.version_number= schema_name.first_name.version_number
and schema_name.quiz_table.windows= schema_name.first_name.value_id
and in_process='N'
}
OR
Condition 2/ Query 2 - Display data
select schema_name.relationss."relations", schema_name.quiz_table."answer", schema_name.quiz_table."windows", schema_name.quiz_table."in_process", schema_name.quiz_table."object_name", schema_name.quiz_table."processed_date", schema_name.quiz_table."player", schema_name.quiz_table."country_place", schema_name.tools."mesh_scope_note", schema_name.plugin."current_name", schema_name.plugin."pet_name"
from schema_name.quiz_table, schema_name.tools, schema_name.plugin, schema_name.relationss, schema_name.value_version
where (in_process = 'N'
and schema_name.quiz_table."windows" = schema_name.tools."value_id"
and schema_name.quiz_table."player" = schema_name.tools."language"
and schema_name.quiz_table."answer" = schema_name.plugin."answer"
and schema_name.relationss."language" = schema_name.quiz_table."player"
and schema_name.relationss."language" = schema_name.tools."language"
and schema_name.relationss."caste" = schema_name.tools."caste"
and schema_name.relationss."value_name" = schema_name.tools."value_name"
and schema_name.relationss."version_number" = schema_name.tools."version_number"
and schema_name.relationss."value_id" = schema_name.tools."value_id"
and schema_name.value_version."value_id" = schema_name.tools."value_id"
and schema_name.value_version."version_number" = schema_name.tools."version_number"
and schema_name.value_version."caste" = schema_name.tools."caste"
)
NOTE - 1-> I cannot use function or procedure here.
2-> Both the `Conditions` contains `different data`
The problem is, how will the computer choose which option to go to? A computer does not choose, it can't. You have to provide some metric for which to choose. The boolean operator || (or) is for checking if either is true (declarative-sorta), not for imperative. You can 'ask' "is a or b true?" but you can't tell a computer, "do this or that" without any weight to either one which would explain to the computer which to pick and when.
What would be possible is asking,
"If there is data in Condition 1 display them; if not, go to Condition 2 and display data".
If that suits your needs, this is how it could be coded (this is just the framework).
if (data1 != null) {
show data1
}
else {
show data2
}
Or your data could be non-null, but have no contents, in which you could try to get some data from it (say, getChildren() (totally random, I'm just making that up):
if (data1.getChildren() != null) {
show data1
}
else {
show data2
}
I hope you know that this is just pseudocode for the theory of it. show_ is not actual code, it's just the placeholder for whatever you would write. Would this work - checking if it is null and/or checking if its contents are null (i.e., it's empty/without data) and if so then going to the next dataset?
I don't know sql, but I thought that idea of check-null/check-contents-null might help.
I want to create a view in cb that will show some data based on date-range input.
My question is how can I distinct field from the data?
Here is my map code:
function (doc, meta) {
if(!doc.clipGeneration.fromCache){
var eiid = doc.clipGeneration.batchId;
if (eiid == null){
eiid = "API";
}
if ( !(doc.clipGeneration.externalId.indexOf("API_INTERVAL_TEST")>=0) ) {
emit([doc.clipGeneration.clipStyle, eiid,doc.eventOccurenceTimeStamp[0], doc.eventOccurenceTimeStamp[1], doc.eventOccurenceTimeStamp[2],doc.eventOccurenceTimeStamp[3]], doc.insertRawTimestamp);
emit([doc.clipGeneration.clipStyle, "ALL",doc.eventOccurenceTimeStamp[0], doc.eventOccurenceTimeStamp[1], doc.eventOccurenceTimeStamp[2],doc.eventOccurenceTimeStamp[3]], doc.insertRawTimestamp);
emit([doc.eventOccurenceTimeStamp[0], doc.eventOccurenceTimeStamp[1], doc.eventOccurenceTimeStamp[2],doc.clipGeneration.clipStyle], doc.insertRawTimestamp);
}
}
}
The reduce is _count, and the filters for example are:
startkey: [2015,1,1,null]
endkey: [2015,1,31,"\uffff"]
The output is as expected by the date-range:
{"key":[2015,1,11,"5001188"],"value":1},
{"key":[2015,1,12,"100022"],"value":5},
{"key":[2015,1,12,"155"],"value":11},
{"key":[2015,1,13,"100022"],"value":9},
{"key":[2015,1,13,"155"],"value":6},
{"key":[2015,1,13,"5001159"],"value":1},
{"key":[2015,1,13,"5001190"],"value":3},
{"key":[2015,1,14,"100022"],"value":12},
{"key":[2015,1,14,"5001194"],"value":1},
{"key":[2015,1,15,"100022"],"value":11},
{"key":[2015,1,16,"100022"],"value":10},
{"key":[2015,1,18,"100022"],"value":8},
{"key":[2015,1,18,"5001096"],"value":6},
{"key":[2015,1,18,"5001194"],"value":3}
But as you can see "100022" repeat many times, how can I make somthing like distinct in sql, so it will be shown only once?
Thanks
There is no way to actually make ONLY the ID field distrinct. You can reduce by key, but only the whole key - so [date, id] in your case. You can do this in N1QL, because it has an actual DISTINCT keyword just like SQL, but that's still in developer preview at the moment.
I have this code and I want to paginate $shares.
How can I archive this?
$level = Share::join('follows', 'shares.user_id', '=', 'follows.user_id')
->where('follows.follower_id', Auth::user()->id)
->where('follows.level', 1)
->get(array('shares.*'));
//get 10% of shares
$count = Share::count()/10;
$count = round($count);
$top10 = Share::orderBy('positive', 'DESC')
->take($count)
->get();
$shares = $top10->merge($level);
//get only unique from shares
$unique = array();
$uniqueShares = $shares->filter(function($item) use (&$unique) {
if (!in_array($item->id, $unique)) {
$unique[] = $item->id;
return true;
} else {
return false;
}
});
//order by id
$shares = $uniqueShares->sortBy(function($share)
{
return -($share->id);
});
return View::make('layout/main')
->with('shares', $shares);
lots of reudandant unnecessary codes here.
1st:
$level = Share::join('follows', 'shares.user_id', '=', 'follows.user_id')
->where('follows.follower_id', Auth::user()->id)
->where('follows.level', 1)
->get(array('shares.*'));
Why you are taking ALL the records only to discard it later?
2nd:
$shares = $top10->merge($level); Why you are merging the two arrays?
3rd:
$uniqueShares = $shares->filter(function($item) use (&$unique) {
if (!in_array($item->id, $unique)) {
$unique[] = $item->id;
return true;
} else {
return false;
}
});
You HAD to wrote this snippet because above in 2nd, you merged the two arrays which will yield duplicated entries. So why merging?
4th:
//order by id
$shares = $uniqueShares->sortBy(function($share)
{
return -($share->id);
});
And here comes the actual data which you actually want.
So let's recape
You need
10% of total shares
order by some positive column
order by amount of shares perhaps as i am guessing.
To use the inbuilt paginate(), you'l need paginate() that's a must.
Rest is simple.
count the total result. round(Share::count()/10)
put it in paginate() as the 1st arguement.
Add the order by clause whichever is necessary.
looking at the code, it doesn't look like you will/should have duplicated data which may haved added the distinct and group by clause.
use remember in Share::count()/10; to Cache it. You don't need to run the query over and over again.
and you're done.
The way you are merging your queries you may need to manually create it the pagination in your blade, then send a variable to "take" the next set you want.
Read the Laravel Docs for more info on implementing it into your views and manually creating it.
http://laravel.com/docs/pagination
Try this, should be good to go
Share::join('follows', 'shares.user_id', '=', 'follows.user_id')
->where('follows.follower_id', Auth::user()->id)
->where('follows.level', 1)
->paginate(20);
Maybe you would like to specify columns to select in select() method.
I'm new to sqlalchemy and could use some help.
I'm trying to write a small application for which i have to dynamically change a select-statement. So I do s = select([files]), and then i add filters by s = s.where(files.c.createtime.between(val1, val2)).
This works great, but only with an AND-conjunction.
So, when I want to have all entries with createtime (between 1.1.2009 and 1.2.2009) OR createtime == 5.2.2009, I got the problem that i don't know how to achieve this with different filter-calls. Because of the programs logic it's not possible to use s= s.where(_or(files.c.createtime.between(val1, val2), files.c.createtime == DateTime('2009-02-01')))
Thanks in advance,
Christof
You can build or clauses dynamically from lists:
clauses = []
if cond1:
clauses.append(files.c.createtime.between(val1, val2))
if cond2:
clauses.append(files.c.createtime == DateTime('2009-02-01'))
if clauses:
s = s.where(or_(*clauses))
If you're willing to "cheat" by making use of the undocumented _whereclause attribute on Select objects, you can incrementally specify a series of OR terms by building a new query each time based on the previous query's where clause:
s = select([files]).where(literal(False)) # Start with an empty query.
s = select(s.froms).where(or_(s._whereclause,
files.c.createtime.between(val1, val2)))
s = select(s.froms).where(or_(s._whereclause,
files.c.createtime == datetime(2009, 2, 1)))
Building up a union is another option. This is a bit clunkier, but doesn't rely on undocumented attributes:
s = select([files]).where(literal(False)) # Start with an empty query.
s = s.select().union(
select([files]).where(files.c.createtime.between(val1, val2)))
s = s.select().union(
select([files]).where(files.c.createtime == datetime(2009, 2, 1)))