I have my own dataset and I want to perform a federated query in SPARQL. Here is the query:
PREFIX : <http://myURIsNamespace#>
PREFIX wd: <http://www.wikidata.org/entity/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX p: <http://www.wikidata.org/prop/>
PREFIX ps: <http://www.wikidata.org/prop/statement/>
PREFIX pq: <http://www.wikidata.org/prop/qualifier/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
select * where {
?bioentity :hasMutatedVersionOf ?gene .
?gene :partOf wd:Q430258 .
SERVICE <https://query.wikidata.org/sparql> {
?gene p:P644 ?statement;
wdt:P31 wd:Q7187 ;
wdt:P703 wd:Q15978631 ;
wdt:P1057 wd:Q430258 .
?statement ps:P644 ?start .
?statement pq:P659 wd:Q20966585 .
?gene p:P645 ?statement2.
?statement2 ps:P645 ?end .
?statement2 pq:P659 wd:Q20966585 .
FILTER (xsd:integer(?start)>21000000 && xsd:integer(?start)<30000000)
}
}
I run the query via graphDB SPARQL interface but it's really really slow. It takes more than a minute to return 8 records. If I split the query in two parts, they are ridiculously fast.
Query#1
select * where {
?bioentity :hasMutatedVersionOf ?gene .
?gene :partOf wd:Q430258 .
}
56 records in 0.1s
Query#2
select * where {
SERVICE <https://query.wikidata.org/sparql> {
?gene p:P644 ?statement;
wdt:P31 wd:Q7187 ;
wdt:P703 wd:Q15978631 ;
wdt:P1057 wd:Q430258 .
?statement ps:P644 ?start .
?statement pq:P659 wd:Q20966585 .
?gene p:P645 ?statement2.
?statement2 ps:P645 ?end .
?statement2 pq:P659 wd:Q20966585 .
FILTER (xsd:integer(?start)>21000000 && xsd:integer(?start)<30000000)
}
}
158 records in 0.5s
Why the is the federation so slow? Is there a way to optimize the performance?
Short answer
Just place your SERVICE part first, i. e. before ?bioentity :hasMutatedVersionOf ?gene .
Read a good article on the topic (e. g. chapter 5 of this book)
Relevant quote from the aforementioned article:
3.3.2 Query Optimization and Execution
The execution order of query operators significantly influences the overall query evaluation cost.
Besides the important query execution time there are also other
aspects in the federated scenario which are relevant for the query
optimization:
Minimizing communication cost. The number of contacted
data sources directly influences the performance of the query
execution due to the communication overhead. However, reducing the
number of involved data source trades off against completeness of
results.
Optimizing execution localization. The standard query
interfaces of linked data sources are generally only capable of
answering queries on their provided data. Therefore, joins with
other data results usually need to be done at the query issuer. If
possible at all, a better strategy will move parts of the result
merging operations to the data sources, especially if they can be
executed in parallel.
Streaming results. Retrieving a complete result
when evaluating a query on a large dataset may take a while even with
a well optimized execution strategy. Thus one can return results as
soon as they become available, which can be optimized by trying to
return relevant results first.
Long answer
Example data
PREFIX : <http://myURIsNamespace#>
PREFIX wd: <http://www.wikidata.org/entity/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX p: <http://www.wikidata.org/prop/>
PREFIX ps: <http://www.wikidata.org/prop/statement/>
PREFIX pq: <http://www.wikidata.org/prop/qualifier/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
INSERT { ?gene rdf:type owl:Thing }
WHERE {
SERVICE <https://query.wikidata.org/sparql> {
?gene p:P644 ?statement;
wdt:P31 wd:Q7187 ;
wdt:P703 wd:Q15978631 ;
wdt:P1057 wd:Q430258 .
?statement ps:P644 ?start .
?statement pq:P659 wd:Q20966585 .
?gene p:P645 ?statement2.
?statement2 ps:P645 ?end .
?statement2 pq:P659 wd:Q20966585 .
FILTER (xsd:integer(?start)>26000000 && xsd:integer(?start)<30000000)
}
}
The total number of triples is 79. Please note that 26000000 is used instead of 21000000.
Query 1
PREFIX : <http://myURIsNamespace#>
PREFIX wd: <http://www.wikidata.org/entity/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX p: <http://www.wikidata.org/prop/>
PREFIX ps: <http://www.wikidata.org/prop/statement/>
PREFIX pq: <http://www.wikidata.org/prop/qualifier/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
SELECT * WHERE {
?gene rdf:type owl:Thing .
SERVICE <https://query.wikidata.org/sparql> {
?gene p:P644 ?statement;
wdt:P31 wd:Q7187 ;
wdt:P703 wd:Q15978631 ;
wdt:P1057 wd:Q430258 .
?statement ps:P644 ?start .
?statement pq:P659 wd:Q20966585 .
?gene p:P645 ?statement2.
?statement2 ps:P645 ?end .
?statement2 pq:P659 wd:Q20966585 .
FILTER (xsd:integer(?start)>20000000 && xsd:integer(?start)<30000000)
}
}
Query 2
PREFIX : <http://myURIsNamespace#>
PREFIX wd: <http://www.wikidata.org/entity/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX p: <http://www.wikidata.org/prop/>
PREFIX ps: <http://www.wikidata.org/prop/statement/>
PREFIX pq: <http://www.wikidata.org/prop/qualifier/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
SELECT * WHERE {
SERVICE <https://query.wikidata.org/sparql> {
?gene p:P644 ?statement;
wdt:P31 wd:Q7187 ;
wdt:P703 wd:Q15978631 ;
wdt:P1057 wd:Q430258 .
?statement ps:P644 ?start .
?statement pq:P659 wd:Q20966585 .
?gene p:P645 ?statement2.
?statement2 ps:P645 ?end .
?statement2 pq:P659 wd:Q20966585 .
FILTER (xsd:integer(?start)>20000000 && xsd:integer(?start)<30000000)
}
?gene rdf:type owl:Thing
}
Performance
Query 1
Query 2
GraphDB
30 sec
1 sec
Blazegraph
1 sec
1 sec
GraphDB behaviour
Executing Query 1, GraphDB performs 79 distinct GET requests to Wikidata¹:
These requests are queries of this kind:
SELECT ?start ?statement ?end ?statement2 WHERE {
<http://www.wikidata.org/entity/Q18031286> p:P644 ?statement;
wdt:P31 wd:Q7187 ;
wdt:P703 wd:Q15978631 ;
wdt:P1057 wd:Q430258 .
?statement ps:P644 ?start .
?statement pq:P659 wd:Q20966585 .
<http://www.wikidata.org/entity/Q18031286> p:P645 ?statement2.
?statement2 ps:P645 ?end .
?statement2 pq:P659 wd:Q20966585 .
FILTER (xsd:integer(?start)>20000000 && xsd:integer(?start)<30000000)
It seems interesting, that on another machine, GraphDB performs GET requests of another kind:
GET /sparql?queryLn="Sparql"&query=<original_query_service_part>&$gene=<http://www.wikidata.org/entity/Q18031286>
In this request, Sesame protocol is used, these bindings in URL are not a part of SPARQL 1.1 Protocol.
Perhaps the exact kind of a request depends on the value of the internal reuse.vars.in.subselects parameter, which default value is presumably different on Windows and on Linux.
Blazegraph behaviour
Executing Query 1, Blazegraph performs single POST request to Wikidata²:
SELECT ?gene ?statement ?start ?statement2 ?end
WHERE {
?gene p:P644 ?statement;
wdt:P31 wd:Q7187 ;
wdt:P703 wd:Q15978631 ;
wdt:P1057 wd:Q430258 .
?statement ps:P644 ?start .
?statement pq:P659 wd:Q20966585 .
?gene p:P645 ?statement2.
?statement2 ps:P645 ?end .
?statement2 pq:P659 wd:Q20966585 .
FILTER (xsd:integer(?start)>20000000 && xsd:integer(?start)<30000000)
}
VALUES ( ?gene) {
( wd:Q14908148 ) ( wd:Q15320063 ) ( wd:Q17861651 ) ( wd:Q17917753 ) ( wd:Q17928333 )
( wd:Q18024923 ) ( wd:Q18026347 ) ( wd:Q18030710 ) ( wd:Q18031220 ) ( wd:Q18031457 )
( wd:Q18031551 ) ( wd:Q18031832 ) ( wd:Q18032918 ) ( wd:Q18033094 ) ( wd:Q18033798 )
( wd:Q18034311 ) ( wd:Q18035006 ) ( wd:Q18035085 ) ( wd:Q18035609 ) ( wd:Q18036516 )
( wd:Q18036676 ) ( wd:Q18037580 ) ( wd:Q18038385 ) ( wd:Q18038459 ) ( wd:Q18038737 )
( wd:Q18038763 ) ( wd:Q18039997 ) ( wd:Q18040291 ) ( wd:Q18041261 ) ( wd:Q18041415 )
( wd:Q18041558 ) ( wd:Q18045881 ) ( wd:Q18047232 ) ( wd:Q18047373 ) ( wd:Q18047918 )
( wd:Q18047966 ) ( wd:Q18048744 ) ( wd:Q18049145 ) ( wd:Q18049164 ) ( wd:Q18053139 )
( wd:Q18056540 ) ( wd:Q18057411 ) ( wd:Q18060804 ) ( wd:Q18060856 ) ( wd:Q18060876 )
( wd:Q18060905 ) ( wd:Q18060958 ) ( wd:Q20773708 ) ( wd:Q15312971 ) ( wd:Q17860819 )
( wd:Q17917713 ) ( wd:Q18026310 ) ( wd:Q18027015 ) ( wd:Q18031286 ) ( wd:Q18032599 )
( wd:Q18032797 ) ( wd:Q18035169 ) ( wd:Q18035627 ) ( wd:Q18039938 ) ( wd:Q18041207 )
( wd:Q18041512 ) ( wd:Q18041930 ) ( wd:Q18045491 ) ( wd:Q18045762 ) ( wd:Q18046301 )
( wd:Q18046472 ) ( wd:Q18046487 ) ( wd:Q18047149 ) ( wd:Q18047491 ) ( wd:Q18047719 )
( wd:Q18048527 ) ( wd:Q18049774 ) ( wd:Q18051886 ) ( wd:Q18053875 ) ( wd:Q18056212 )
( wd:Q18056538 ) ( wd:Q18065866 ) ( wd:Q20766978 ) ( wd:Q20781543 )
}
Conclusion
With federated queries, it is hard to create effective execution plan, since selectivity of remote patterns is unknown.
In your particular case, it should be not very important, whether to join results locally or remotely, because both local and remote resultsets are small. However, in GraphDB, joining results remotely is less effective, because GraphDB does not reduce communication costs.
¹ For screenshots creation, <http://query.wikidata.org/sparql> instead of <https://query.wikidata.org/sparql> was used.
² In Blazegraph, one might write hint:Query hint:optimizer "None" to ensure sequential evaluation.
Related
In my triple store i've a collection of schema:CreativeWork which has the property schema:version and schema:dateCreated.
Now i want to get all schema:CreativeWork but only the newest ones.
My sample:
PREFIX schema: <https://schema.org/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT DISTINCT *
WHERE {
?subject rdf:type schema:CreativeWork .
?subject schema:identifier ?identifier .
?subject schema:version ?version .
?subject schema:dateCreated ?dateCreated .
OPTIONAL {?subject schema:about/schema:name ?name .}
FILTER( ?identifier = "46d8b7abfec44865a567ea04e385661b" ) .
} LIMIT 10
How do i manage to query only the latest version?
executable sample: https://api.triplydb.com/s/rLq4V-JgS
Note: FILTER( ?identifier = "46d8b7abfec44865a567ea04e385661b" ) . is just to make it easier.
The query of UninformedUser is working well:
PREFIX schema: <https://schema.org/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT DISTINCT *
{
{
SELECT ?identifier (max(?dateCreated) as ?latestDate)
WHERE {
?subject rdf:type schema:CreativeWork .
?subject schema:identifier ?identifier .
?subject schema:dateCreated ?dateCreated .
} group by ?identifier
}
?subject schema:identifier ?identifier .
?subject schema:version ?version .
?subject schema:dateCreated ?latestDate .
OPTIONAL {?subject schema:about/schema:name ?name . }
} LIMIT 100
This query seems very lazy for a "WHERE IN"... Because not need to check "the universe", only the little IN () set.
SELECT ?item ?itemLabel ?of ?ofLabel
WHERE
{
?item wdt:P31 ?of.
FILTER ( ?item IN (
wd:Q28114532, wd:Q27745011,wd:Q3415363,wd:Q3415324,wd:Q2877432,wd:Q2877444,
wd:Q2396644,wd:Q3444776,wd:Q2877428,wd:Q578757,wd:Q2877445,wd:Q2333617
) )
SERVICE wikibase:label {
bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en".
}
}
There are another way to do faster the same thing?
NOTE
The problem grows with similar thing, but checking if the item has "any dependency" — an instance, sub-instance, class or sub-class of something (eg. Q7860962).
SELECT ?item ?itemLabel ?x ?xLabel
WHERE
{
?x (wdt:P31|wdt:P279)* wd:Q7860962 .
?item wdt:P31 ?x .
FILTER ( ?item IN (
wd:Q28114532, wd:Q27745011,wd:Q3415363,wd:Q3415324,wd:Q2877432,wd:Q2877444,
wd:Q2396644,wd:Q3444776,wd:Q2877428,wd:Q578757,wd:Q2877445,wd:Q2333617
) )
SERVICE wikibase:label {
bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en".
}
}
As #AKSW has pointed out, you could use VALUES. Your first query will be ~150 times faster:
SELECT ?item ?itemLabel ?of ?ofLabel
WHERE
{ VALUES (?item) {
(wd:Q28114532) (wd:Q27745011) (wd:Q3415363) (wd:Q3415324) (wd:Q2877432) (wd:Q2877444)
(wd:Q2396644) (wd:Q3444776) (wd:Q2877428) (wd:Q578757) (wd:Q2877445) (wd:Q2333617)
}
?item wdt:P31 ?of.
SERVICE wikibase:label {
bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en".
}
}
Try it!
In your second query, you should also add hint:Prior hint:gearing "forward":
SELECT ?item ?itemLabel ?x ?xLabel
WHERE
{
VALUES (?item) {
(wd:Q28114532) (wd:Q27745011) (wd:Q3415363) (wd:Q3415324) (wd:Q2877432) (wd:Q2877444)
(wd:Q2396644) (wd:Q3444776) (wd:Q2877428) (wd:Q578757) (wd:Q2877445) (wd:Q2333617)
}
?item wdt:P31 ?x .
?x (wdt:P31|wdt:P279)* wd:Q7860962 .
hint:Prior hint:gearing "forward" .
SERVICE wikibase:label {
bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en".
}
}
Try it!
I would like to get the list of actors in Wikidata and also the number of awards received by each of them. Which query do I have to write ?
I tried this but it doesn't seem to work because I have only a few results :
SELECT ?actor ?actorLabel ?awardsNumber WHERE {
{
SELECT ?actor (COUNT(DISTINCT ?awardsNumber) AS ?awardsNumber)
WHERE {
?actor wdt:P106 wd:Q33999 .
?awardsNumber wdt:P166 ?actor .
}
GROUP BY ?actor
}
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" . }
}
ORDER BY DESC (?awardsNumber)
Thank you in advance for your help !
Not sure why you used the property P166 ("award received") as incoming property. Of course the query must be
SELECT ?actor ?actorLabel ?awardsNumber WHERE {
{
SELECT ?actor (COUNT(DISTINCT ?award) AS ?awardsNumber)
WHERE {
?actor wdt:P106 wd:Q33999 .
?actor wdt:P166 ?award.
}
GROUP BY ?actor
}
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" . }
}
ORDER BY DESC (?awardsNumber)
I have a database with the following structure
user_id | cat_name | cat_slug | parent_id
-------------------------------------------
Tools | tools | 0 |
2 |Chainsaws |chainsaws | 1
etc
My end goal is to essentially have an array that has a breadcrumb trail of sorts that shows the category path, it could have anywhere from no parents to 5 levels of category parenting.
I was able to kind of get what I want.. with a few errors along the way. I keep getting a Trying to get property of non-object error. Althrough all my other attempts at returning values have failed.
My solution outputs my (semi - desired) effect underneath the errors, and with additional category breaks ( symbolized by ">" ). I was just hoping someone could help me clean it up, because I'm at a breaking point, after going about this for a few hours with no solution.
Model
function get_parent_trail($parent_id){
if ( $parent_id != 0 && $parent_id){
$parent_trail = array();
for( $i = 1; $i <= 4; $i ++ ) {
$this -> db -> select ( '*' );
$this -> db -> from ( 'categories' );
$this -> db -> where ( 'cat_id' , $parent_id );
$query = $this -> db -> get() -> row();
array_unshift( $parent_trail, $query->cat_name ) ;
$parent_id = $query->parents;
}
foreach( $parent_trail as $ti ) {
if ( $ti ) {
echo "<strong>" . $ti . "</strong> > ";
}
}
} else {
echo "<span style='color:red;'>No Parent Category</span>";
}
}
View
<table class='admin_table'>
<thead>
<th>ID</th>
<th>Name</th>
<th>Parent</th>
</thead>
<tbody>
<?php
foreach($cats as $cat){
echo "<tr>";
echo "<td>" . $cat['cat_id'] . "</td>";
echo "<td>" . $cat['cat_name'] . "</td>";
echo "<td>";
$this -> categories -> get_parent_trail( $cat['parents'] );
echo "</td>";
echo "</tr>";
}
?>
</tbody>
</table>
NOTE:
The '4' in the for loop doesn't need to be dynamic as I've set a hard limit of up to 5 categories, though there has been no need to go that far into sub-categories.
I also have an additional ">" at the end of my list, which I need to get rid of, I know the reason my way doesn't work, it's just the closest solution I could find for the time being.
End Result
Basically, I want my end result to look like;
With 2 'levels' of parent categories
id | name | slug | Parent(s)
-----------------------------------------------------------------------
1 | Electric Chainsaws | electric-chainsaws | Tools > Chainsaws
What you are wanting to do is build a recursive function.
Example of this would be:
function factorial($number)
{
if ($number < 2)
{
return 1;
}
else
{
return ($number * factorial($number-1));
}
}
After much hair pulling and several bottles of very strong rum, I was able to finally figure this out. I'm still relatively novice at using codeigniter so my solution may have some unnecessary steps to it, but I feel obliged to share what I learned. Here is my entire function.
function get_parent_trail($parent_id){
if ( $parent_id != 0 && $parent_id){
$parent_trail = array();
$inc = 0;
for( $i = 1; $i <= 4; $i ++ ) {
if ( $parent_id != 0 && $parent_id){
$this -> db -> select ( '*' );
$this -> db -> from ( 'categories' );
$this -> db -> where ( 'cat_id' , $parent_id );
$query = $this -> db -> get();
$row = $query -> row_array();
array_unshift( $parent_trail, $row['cat_name'] ) ;
$parent_id = $row['parents'];
} else {
$inc++;
}
}
$popOff = array_pop($parent_trail);
if ($inc > 2 ){
echo "<span style='color:red;'>No Parent Category</span>";
}
$string = '';
foreach( $parent_trail as $ti ) {
if ( $ti ) {
$string .= $ti.' > ';
}
}
(string) $test = substr($string, 0, -2);
echo $test;
} else {
echo "<span style='color:red;'>No Parent Category</span>";
}
}
I am using jqgrid in one of my application.
Right now i am facing a strange problem and do not know how to rectify it?
Actually in one of the reports (having multiple link) jqgrid is showing wrong footer information that is its showing Page 0 of 0 even if there are records in the table.
This is the code which runs:
if( isset($this->params['named']['ajax']) && $this->params['named']['ajax'] == '1' )
{
$this->autoRender = false;
// get how many rows we want to have into the grid - rowNum parameter in the grid
$limit = $this->params['url']['rows'];
// get index row - i.e. user click to sort. At first time sortname parameter -
// after that the index from colModel
$sidx = $this->params['url']['sidx'];
// sorting order - at first time sortorder
$sord = $this->params['url']['sord'];
$page = $this->params['url']['page'];
// if we not pass at first time index use the first column for the index or what you want
if( !$sidx ) $sidx = 1;
// calculate the number of rows for the query. We need this for paging the result
$findconditions = array();
if(!empty($this->params['named']['batch']))
array_push(&$findconditions, array('Batch.id' => $this->params['named']['batch'] ));
$row = $this->Placement->find('count',array(
'link' => array(
'Student' => array(
'Batch'
)
),
'conditions'=> $findconditions
));
$count = $row;
// calculate the total pages for the query
if( $count > 0 )
{
$total_pages = ceil($count / $limit);
}
else
{
$total_pages = 0;
}
// if for some reasons the requested page is greater than the total
// set the requested page to total page
if( $page > $total_pages ) $page = $total_pages;
// calculate the starting position of the rows
$start = $limit * $page - $limit;
// if for some reasons start position is negative set it to 0
// typical case is that the user type 0 for the requested page
if( $start < 0 ) $start = 0;
// the actual query for the grid data
$limit_range = $start . "," . $limit;
$sort_range = $this->modelClass . '.' . $sidx . " " . $sord;
$this->Placement->recursive = -1;
$where='';
if( $this->params['url']['_search'] == 'true' )
{
//pr($this->params);
$searchconditions = array();
if( isset($this->params['named']['batch']) && !empty($this->params['named']['batch']) )
{
$where.= " Batch.id =".$this->params['named']['batch'];
}
if( isset($this->params['url']['isstillworking']) && !empty($this->params['url']['isstillworking']) )
{
$where.= " AND Placement.isstillworking ='".$this->params['url']['isstillworking']."'";
}
if( isset($this->params['url']['studentname']) && !empty($this->params['url']['studentname']) )
{
$where.=" AND Student.fullname LIKE '" .$this->params['url']['studentname'] . "%'";
}
if( isset($this->params['url']['companyname']) && !empty($this->params['url']['companyname']) )
{
$where.=" AND Company.name LIKE '" .$this->params['url']['companyname'] . "%'";
}
if( isset($this->params['url']['salary']) && !empty($this->params['url']['salary']) )
{
$where.= " AND Placement.salary =".$this->params['url']['salary'];
}
if( isset($this->params['url']['contactnumber1']) && !empty($this->params['url']['contactnumber1']) )
{
$where.= " AND Student.contactnumber1 =".$this->params['url']['contactnumber1'];
}
if( isset($this->params['url']['batchname']) && !empty($this->params['url']['batchname']) )
{
$where.=" AND Batch.name LIKE '" .$this->params['url']['batchname'] . "%'";
}
$sql="SELECT Student.fullname,
Placement.isstillworking,
Company.id,
Company.name,
Placement.id,
Placement.salary,
Placement.created,
Student.id,
Student.contactnumber1,
Batch.id,
Batch.name
FROM placements Placement
INNER JOIN (
SELECT student_id, isstillworking, max( created ) AS other_col
FROM placements
GROUP BY student_id
) AS b ON Placement.student_id = b.student_id
AND Placement.created = b.other_col
INNER JOIN students Student ON ( Student.id = Placement.student_id )
INNER JOIN batches Batch ON ( Student.batch_id = Batch.id )
INNER JOIN companies Company ON ( Company.id = Placement.company_id )
WHERE ".$where.
" AND Student.type='student'
AND Student.trainingcompleted=1
ORDER BY ".$sort_range."
LIMIT ".$limit_range
;
$result=$this->Placement->query($sql);
}
else
{
$sql="SELECT Student.fullname,
Placement.isstillworking,
Company.id,
Company.name,
Placement.id,
Placement.salary,
Placement.created,
Student.id,
Student.contactnumber1,
Batch.id,
Batch.name
FROM placements Placement
INNER JOIN (
SELECT student_id, isstillworking, max( created ) AS other_col
FROM placements
GROUP BY student_id
) AS b ON Placement.student_id = b.student_id
AND Placement.created = b.other_col
INNER JOIN students Student ON ( Student.id = Placement.student_id )
INNER JOIN batches Batch ON ( Student.batch_id = Batch.id )
INNER JOIN companies Company ON ( Company.id = Placement.company_id )
WHERE Batch.id =
".$this->params['named']['batch'].
" AND Student.type='student'
AND Student.trainingcompleted=1
ORDER BY ".$sort_range."
LIMIT ".$limit_range
;
$result=$this->Placement->query($sql);
}
$i = 0;
$response->page = $page;
$response->total = $total_pages;
$response->records = $count;
//pr($result);
foreach($result as $result)
{
$response->rows[$i]['id'] = $result['Placement']['id'];
$student = "<a href='" . APP_URL . "placements/report18/studentid:" . $result['Student']['id']."'>" . $result['Student']['fullname'] . "</a>";
$company = "<a href='" . APP_URL . "companies/view/" . $result['Company']['id'] . "'>" . $result['Company']['name'] . "</a>";
$batch = "<a href='" . APP_URL . "batches/view/" . $result['Batch']['id'] . "'>" . $result['Batch']['name'] . "</a>";
$contactnumber1 =$result['Student']['contactnumber1'];
$response->rows[$i]['cell'] = array($student, $result['Placement']['isstillworking'], $result['Company']['name'], $result['Placement']['salary'], $contactnumber1, $batch);
$i++;
}
echo json_encode($response);
}
I am also attaching the screen shot for reference.
Please help me on this.
Regards,
Pankaj
Why on earth would you not use Cake's ORM layer and Pagination class? If you use Model->query() you have to escape input yourself!