How to Join Two Tables with Ssp.Class.Php

How to join two tables with ssp.class.php

As PaulF pointed out, you need to use JOIN or sub-query to retrieve father's name from the same table.

I assume you're using ssp.class.php to process your data on the server-side based on the example you've mentioned.

Class ssp.class.php doesn't support joins and sub-queries, but there is a workaround. The trick is to use sub-query as shown below in $table definition. Replace table with your actual table name in the sub-query.

$table = <<<EOT
(
SELECT
a.id,
a.name,
a.father_id,
b.name AS father_name
FROM table a
LEFT JOIN table b ON a.father_id = b.id
) temp
EOT;

$primaryKey = 'id';

$columns = array(
array( 'db' => 'id', 'dt' => 0 ),
array( 'db' => 'name', 'dt' => 1 ),
array( 'db' => 'father_id', 'dt' => 2 ),
array( 'db' => 'father_name', 'dt' => 3 )
);

$sql_details = array(
'user' => '',
'pass' => '',
'db' => '',
'host' => ''
);

require( 'ssp.class.php' );
echo json_encode(
SSP::simple( $_GET, $sql_details, $table, $primaryKey, $columns )
);

You also need to edit ssp.class.php and replace all instances of FROM `$table` with FROM $table to remove backticks.

Make sure all column names are unique otherwise use AS to assign an alias.

NOTES

There is also github.com/emran/ssp repository that contains enhanced ssp.class.php supporting JOINs.

LINKS

See jQuery DataTables: Using WHERE, JOIN and GROUP BY with ssp.class.php for more information.

Datatables + PHP: Server-Side Processing on Multiple Tables

TL;DR: I ended up using a modification of the original Datatables ssp.class.php called ssp.php implemented by Emran Ul Hadi: https://github.com/emran/ssp

His modification accepts JOIN, WHERE, GROUP BY and column aliases. Although the file hasn't been updated in over a year, it still works with DataTables 1.12.x. I made some modifications to his version that increases its robustness and improves the documentation with clearer examples.

Will post my mods/updates here when I have a bit more time. Eventually I hope to put in a pull-request to get my updates into his repository.

Datatables server-side PHP using SSP class - how to group after join

The correct solution is:

<?php
$table = <<<EOT
(
SELECT
a.id,
a.pr_template_id,
a.title as producttitle,
b.pr_template_id,
b.category_id,
string_agg(DISTINCT c.title, ', ') as cattitle
FROM products_table a
LEFT JOIN product_categories_template_relations b ON a.pr_template_id = b.pr_template_id
LEFT JOIN product_categories c ON b.category_id = c.category_id
group by a.id, b.pr_template_id
) temp
EOT;
?>

Adding GROUP BY support to the ssp class in complex function

two suggestion

1 ) in this code you should use string concatenation for $where

$resFilterLength = self::sql_exec( $db, $bindings,
"SELECT COUNT(`{$primaryKey}`)
FROM `$table` " . $where
);

2 ) seems you have order by limit and offset for pagination after group by (and group by id DESC is wrong)

   $where = "recipient='".$recipient."' AND grouped=''  
GROUP BY id ORDER BY id DESC LIMIT 10 OFFSET 5";

How to use database query with JOIN in server-side processing mode

There is a trick to use JOIN without modifying the code too much.

Change this line:

$sTable = "customers";

to:

$sTable = 
"(
SELECT a.id AS crmid, b.name
FROM forms a
INNER JOIN users b ON a.agent_id = b.id
) table";

I simplified the query above only for the sake of code clarity. Just make sure that all column names are unique, otherwise use aliases where needed.

Then use column names/aliases in $aColumns variable. For the query above it wold be

$aColumns = array('crmid', 'name');

Serverside datatable combining column data and data from other tables

In order to achieve what I needed, I made some changes in the Datatable inizialization script and in the ss-books-get controller.

Datatable Inizialization:

$(document).ready(function() {
$('#books').DataTable( {
dom: "<'row'<'col-md-4'B><'col-md-4'f><'col-md-4'p>>" +
"<'row'<'col-md-6'><'col-md-6'>>" +
"<'row'<'col-md-12't>><'row'<'col-md-4'l><'col-md-4'i><'col-md-4'p>>",
buttons: [
{
extend: 'collection',
text: '<i class="la la-download"></i> Export',
autoClose: true,
className: 'btn btn-success btn-icon-sm btn-square dropdown-toggle',
buttons: [
{ text: '<i class="fas fa-copy"></i>\xa0\xa0 Copy', extend: 'copyHtml5'},
{ text: '<i class="fas fa-file-excel"></i>\xa0\xa0 Excel', extend: 'excelHtml5'},
{ text: '<i class="fas fa-file-csv"></i>\xa0\xa0 CSV', extend: 'csvHtml5'},
{ text: '<i class="fas fa-file-pdf"></i>\xa0\xa0 PDF', extend: 'pdfHtml5'},
{ text: '<i class="fas fa-print"></i>\xa0\xa0 Print', extend: 'print' }
],
fade: true,
}
],
"columnDefs": [
// Use render to mix the title column and the subtitle column and to add the HTML tags. Also generate de buttons grabbing the ID from the id column of the table.
{
"render": function ( data, type, row ) {
if (row[8] == "") {
var title = data;
} else {
var title = data + ' | ' + row[8];
}
return '<a class="kt-link kt-font-bold" href="./book/'+row[7]+'" >' + title + '</a>';
},
"targets": 0
},
{
"render": function ( data, type, row ) {
return '<a href="./book/'+row[7]+'" class="btn btn-sm btn-clean btn-icon btn-icon-md" title="View Book"> <i class="fas fa-eye"></i> </a> <a href="./book/'+row[7]+'#add-copy" class="btn btn-sm btn-clean btn-icon btn-icon-md" title="Add Copy"> <i class="fas fa-plus"></i> </a> <a href="./book/'+row[7]+'#edit-book" class="btn btn-sm btn-clean btn-icon btn-icon-md" title="Edit Book"> <i class="fas fa-edit"></i> </a> <a href="./index.php?action=book-del&id='+row[7]+'" id="btn" class="btn btn-sm btn-clean btn-icon btn-icon-md btn-book-del" title="Delete Book"> <i class="fas fa-trash-alt"></i> </a>';
},
"targets": 6
},
// Then hide the subtitle/id columns (which I won't need to show in frontend)
{ "visible": false, "targets": [ 7 ] },
{ "visible": false, "targets": [ 8 ] }
],
pageLength: 25,
responsive: true,
"processing": true,
"serverSide": true,
"ajax": "index.php?action=ss-books-get"
} );
} );

Controller ss-books-get:

<?php

$table = 'library_book';

$primaryKey = 'id';

$columns = array(

array(
'db' => 'title',
'dt' => 0
),
array( 'db' => 'isbn', 'dt' => 1 ),
array(
'db' => 'subject_id',
'dt' => 2,
'formatter' => function( $d, $row ) {
return library::getSubjectByID($d);
}
),
array(
'db' => 'id',
'dt' => 3,
'formatter' => function( $d, $row ) {
return library::getLevelsByBookID($d);
}
),
array(
'db' => 'id',
'dt' => 4,
'formatter' => function( $d, $row ) {
return library::getCategoriesByBookID($d);
}
),
array(
'db' => 'id',
'dt' => 5,
'formatter' => function( $d, $row ) {
return library::getCountCopiesByBookID($d);
}
),
array(
'db' => 'type',
'dt' => 6
),
array(
'db' => 'id',
'dt' => 7
),
array(
'db' => 'subtitle',
'dt' => 8
),
);

require( 'ssp.class.php' );

echo json_encode(
SSP::complex( $_GET, $sql_details, $table, $primaryKey, $columns, $whereResult=null, $whereAll="hidden = 0 AND type = 1" )
);

I created 4 functions to get the subject, levels, categories and copies by book ID.

Here are the functions:

public static function getSubjectByID($id) {
if ($id == NULL) { $id = 0; } else {}
$a = new SQLMan();
$a->tablename = "library_subject";
$result = $a->select("","",$where="id =".$id);
if (empty($result)) {
return '<span class="kt-badge kt-badge--success greysuccess kt-badge--inline kt-badge--pill"> N/A </span>';
} else {
$result = $result[0];
return '<span class="kt-badge kt-badge--success kt-badge--inline kt-badge--pill">'.$result->fields["name"].'</span>';
}
}
public static function getCategoriesByBookID($id) {
$final = "";
$a = new SQLMan();
$a->tablename = "library_category";
$categoria= $a->select("","",$where=" hidden = 0");
$a = "";
$a = new SQLMan();
$a->tablename = "library_categoryvsbook";
$anycat = $a->select("many","","book_id=".$id);
if (count($anycat)>0) {
foreach($anycat as $cl) {
foreach($categoria as $cat) {
if ($cat->fields["id"] == $cl->fields["category_id"]) {
$final .= "<span class='kt-badge kt-badge--success kt-badge--inline kt-badge--pill'>".$cat->fields["name"]."</span> ";
$a = "";
} else {

}
}
}
} else {
$final .= "<span class='kt-badge kt-badge--success greysuccess kt-badge--inline kt-badge--pill'>N/A</span> ";
$a = "";
}
return $final;
}
public static function getLevelsByBookID($id) {
$final = "";
$a = new SQLMan();
$a->tablename = "library_level";
$categoria= $a->select("","",$where=" hidden = 0");
$a = "";
$a = new SQLMan();
$a->tablename = "library_levelvsbook";
$anycat= $a->select("many","","book_id=".$id);

if (count($anycat)>0) {
foreach($anycat as $cl) {
foreach($categoria as $cat) {
if ($cat->fields["id"] == $cl->fields["level_id"]) {
$final .= "<span class='kt-badge kt-badge--success kt-badge--inline kt-badge--pill'>".$cat->fields["name"]."</span> ";
$a = "";
} else {

}
}
}
} else {
$final .= "<span class='kt-badge kt-badge--success greysuccess kt-badge--inline kt-badge--pill'>N/A</span> ";
$a = "";
}
return $final;
}
public static function getCountCopiesByBookID($id) {
$result = "";
$a = new SQLMan();
$a->tablename = "library_copy";
$ejemplares= $a->select("","",$where=" hidden = 0 AND book_id =".$id);

$count = "0";
$countb = "0";
foreach($ejemplares as $ejem) {
if ($ejem->fields["status"] == "0") {
$count++;
} else {
}
}
$countb = count($ejemplares);
if ($count>0) {
$popcount = "kt-badge--success";
} else {
$popcount = "kt-badge--success greysuccessbadge";
};
$result .= "<span class='kt-badge ".$popcount." kt-badge--dot kt-badge--xl'></span>   ";
$result .= $count . " / " . $countb;
$count = "0"; $countb = "0";
return $result;
}

And now it looks exactly the same but the proccesing is faster.

Calling a function in DataTable Server Side Processing

ssp.class.php doesn't support a JOIN. But we have a workaround for this:

Solution 1 (Use sub-query):

Use sub-query in your $table definition and replace dist_code with disname in $columns as shown below:

$dbDetails = [
'host' => '****',
'user' => '****',
'pass' => '****',
'db' => '****'
];

$table = '(SELECT r.*, d.disname FROM requestss r INNER JOIN districts d ON r.dist_code = d.discode) tbl';

$primaryKey = 'id';

$columns = [
[ 'db' => 'time_stamp', 'dt' => 0 ],
[ 'db' => 'disname', 'dt' => 1 ],
[ 'db' => 'req_type', 'dt' => 2 ]
];

// Include SQL query processing class
require( 'ssp.class.php' );

// Output data as json format
echo json_encode(
SSP::simple( $_GET, $dbDetails, $table, $primaryKey, $columns )
);

Then, you need to replace all instances of `$table` with $table to remove backticks in ssp.class.php file.

Solution 2 (Create a view):

If you don't want to edit ssp.class.php file, you can create a view in your database:

CREATE
VIEW requests_view
AS SELECT r.*, d.disname FROM requestss r INNER JOIN districts d ON r.dist_code = d.discode;

Then, use requests_view as your $table in getData.php file:

$dbDetails = [
'host' => '****',
'user' => '****',
'pass' => '****',
'db' => '****'
];

$table = 'requests_view';

$primaryKey = 'id';

$columns = [
[ 'db' => 'time_stamp', 'dt' => 0 ],
[ 'db' => 'disname', 'dt' => 1 ],
[ 'db' => 'req_type', 'dt' => 2 ]
];

// Include SQL query processing class
require( 'ssp.class.php' );

// Output data as json format
echo json_encode(
SSP::simple( $_GET, $dbDetails, $table, $primaryKey, $columns )
);

You may also consider to use third party PHP libraries like Customized SSP Class For Datatables Library or Datatables library for PHP which support JOINs.



Related Topics



Leave a reply



Submit