1

Im trying to get my head around MySQL. I have learnt a great deal from info online but, im a little stuck on understanding how JOINS work and how to fit in into the DataTables code.

I have this table structure:

I have this table structure:

And this MySql statement:

SELECT leads.lead_id, leads.date_time, clients.username, courses.course_type, courses.location_name, CONCAT(first_name,' ',surname)
FROM courses
LEFT JOIN leads ON leads.lead_get_course_id = courses.course_id 
LEFT JOIN clients ON clients.client_id = courses.course_get_client_id
WHERE leads.checked_by_admin = 'No'

Which all works fine when I test it in dreamweaver but, when I try and apply this to DataTables code I get Unknown column 'leads.lead_id' in 'field list'

Here is my DataTables code:

<?php
/*
 * Script:    DataTables server-side script for PHP and MySQL
 * Copyright: 2010 - Allan Jardine
 * License:   GPL v2 or BSD (3-point)
 */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Easy set variables
 */

/* Array of database columns which should be read and sent back to DataTables. Use a space where
 * you want to insert a non-database field (for example a counter or static image)
 */
$aColumns = array(     
"leads.lead_id", 
"leads.date_time", 
"clients.username", 
"courses.course_type", 
"courses.location_name", 
"CONCAT(first_name,' ',surname)" 
);

/* Indexed column (used for fast and accurate table cardinality) */
$sIndexColumn = "leads.lead_id";

/* DB table to use */
$sTable = "courses";

$sJoin = 'LEFT JOIN leads ON leads.lead_get_course_id = courses.course_id';
$sJoin = 'LEFT JOIN clients ON clients.client_id = courses.course_get_client_id';

/* Database connection information */
$gaSql['user']       = "root";
$gaSql['password']   = "tommy";
$gaSql['db']         = "testingsiasite";
$gaSql['server']     = "localhost";


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * If you just want to use the basic configuration for DataTables with PHP server-side, there is
 * no need to edit below this line
 */

/* 
 * MySQL connection
 */
$gaSql['link'] =  mysql_pconnect( $gaSql['server'], $gaSql['user'], $gaSql['password']  ) or
    die( 'Could not open connection to server' );

mysql_select_db( $gaSql['db'], $gaSql['link'] ) or 
    die( 'Could not select database '. $gaSql['db'] );


/* 
 * Paging
 */
$sLimit = "";
if ( isset( $_GET['iDisplayStart'] ) && $_GET['iDisplayLength'] != '-1' )
{
    $sLimit = "LIMIT ".mysql_real_escape_string( $_GET['iDisplayStart'] ).", ".
        mysql_real_escape_string( $_GET['iDisplayLength'] );
}


/*
 * Ordering
 */
if ( isset( $_GET['iSortCol_0'] ) )
{
    $sOrder = "ORDER BY  ";
    for ( $i=0 ; $i<intval( $_GET['iSortingCols'] ) ; $i++ )
    {
        if ( $_GET[ 'bSortable_'.intval($_GET['iSortCol_'.$i]) ] == "true" )
        {
            $sOrder .= $aColumns[ intval( $_GET['iSortCol_'.$i] ) ]."
                ".mysql_real_escape_string( $_GET['sSortDir_'.$i] ) .", ";
        }
    }

    $sOrder = substr_replace( $sOrder, "", -2 );
    if ( $sOrder == "ORDER BY" )
    {
        $sOrder = "";
    }
}

/* 
 * Filtering
 * NOTE this does not match the built-in DataTables filtering which does it
 * word by word on any field. It's possible to do here, but concerned about efficiency
 * on very large tables, and MySQL's regex functionality is very limited
 */


 /*  */
 /*  */
$sWhere = "";
    if ( isset($_GET['sSearch']) && $_GET['sSearch'] != "" )
    {
            $sWhere = "WHERE (";
            for ( $i=0 ; $i<count($aColumns) ; $i++ )
            {
                    $sWhere .= $aColumns[$i]." LIKE '%".mysql_real_escape_string( $_GET['sSearch'] )."%' OR ";
            }
            $sWhere = substr_replace( $sWhere, "", -3 );
            $sWhere .= " AND checked_by_admin='No'";
            $sWhere .= ')';
    }else{
            $sWhere = "WHERE checked_by_admin='No'";
 }

/* Individual column filtering */
for ( $i=0 ; $i<count($aColumns) ; $i++ )
{
    if ( $_GET['bSearchable_'.$i] == "true" && $_GET['sSearch_'.$i] != '' )
    {
        if ( $sWhere == "" )
        {
            $sWhere = "WHERE ";
        }
        else
        {
            $sWhere .= " AND ";
        }
        $sWhere .= $aColumns[$i]." LIKE '%".mysql_real_escape_string($_GET['sSearch_'.$i])."%' ";
    }
}   

/*
 * SQL queries
 * Get data to display
 */
    if($sWhere != ""):
        $sWhere .= " AND checked_by_admin='No'";
    endif;
$sQuery = "
    SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $aColumns))."
    FROM $sTable
    $sJoin
    $sWhere
    $sOrder
    $sLimit
";
    $rResult = mysql_query( $sQuery, $gaSql['link'] ) or die(mysql_error());

/* Data set length after filtering */
$sQuery = "
    SELECT FOUND_ROWS()
";
$rResultFilterTotal = mysql_query( $sQuery, $gaSql['link'] ) or die(mysql_error());
$aResultFilterTotal = mysql_fetch_array($rResultFilterTotal);
$iFilteredTotal = $aResultFilterTotal[0];

/* Total data set length */
$sQuery = "
    SELECT COUNT(".$sIndexColumn.")
    FROM   $sTable
";
$rResultTotal = mysql_query( $sQuery, $gaSql['link'] ) or die(mysql_error());
$aResultTotal = mysql_fetch_array($rResultTotal);
$iTotal = $aResultTotal[0];


/*
 * Output
 */
$output = array(
    "sEcho" => intval($_GET['sEcho']),
    "iTotalRecords" => $iFilteredTotal,  // HERE FOR MASK TOTAL ENTRY not necerrary for others customers
    "iTotalDisplayRecords" => $iFilteredTotal,
    "aaData" => array()
);

while ( $aRow = mysql_fetch_array( $rResult ) )
{
    $row = array();
    for ( $i=0 ; $i<count($aColumns) ; $i++ )
    {
        if ( $aColumns[$i] == "version" )
        {
            /* Special output formatting for 'version' column */
            $row[] = ($aRow[ $aColumns[$i] ]=="0") ? '-' : $aRow[ $aColumns[$i] ];
        }
        else if ( $aColumns[$i] != ' ' )
        {
            /* General output */
            $row[] = $aRow[ $aColumns[$i] ];
        }
    }
    $row[] = "<span style='cursor:pointer'><img src='../images/more-info.png' alt='more info' onClick='javascript:my_onclick({$row[0]});'/></span>";
    $row[] = "<a href='../leads/actions/approve-lead.php?lead_id={$row[0]}'><img src='../images/approve.png' alt='' /></a>";
    $row[] = "<a href='../leads/actions/delete-lead.php?lead_id={$row[0]}' class='delete_link'><img src='../images/delete.png' alt='' /></a>";
    $output['aaData'][] = $row;
}

echo json_encode( $output );
?>

Any light on why Im getting this error would be great!

Raidri
  • 17,258
  • 9
  • 62
  • 65
monsterboy
  • 153
  • 3
  • 17
  • 1
    What happens with `SELECT leads.lead_id FROM leads` ? – Francois Nov 24 '11 at 11:02
  • did u try "lead_id" instead "leads.lead_id" ? – Arfeen Nov 24 '11 at 11:04
  • Foreign keys, incidentally, are often named "_id". So `courses.course_get_client_id` could just be named `courses.client_id` for simplicity. – halfer Nov 24 '11 at 11:07
  • [Sample code](http://sscce.org/) should be complete and concise–enough to recreate the issue but no more. Consider picking a [meaningful username](http://tinyurl.com/so-hints). One advantage to this is others can use [at-replies](http://meta.stackexchange.com/questions/43019/how-do-comment-replies-work) and you'll get a notification that someone has addressed you in a comment. – outis Nov 24 '11 at 11:29

1 Answers1

3

well, joins won't work with that php code. even i had to struggle with the same situation until i finally decided to create my own class for joins to work with datatable, i was thinking of modifying it for everyone's use and releasing it. but since you are facing the problem here is the class that i came up with and which works without any flaws for me, although currently not in perfect condition but i am giving out the code thinking it might help you.

class DataTable {

    protected $_sTable;
    protected $_aColumns = array();
    protected $_sJoin = '';
    protected $_sWhere_0 = '';
    protected $_sGroupBy = '';
    protected $_sIndexColumn = 'id';
    protected $_iFilteredTotal;
    protected $_iTotal;
    protected $_iResult;
    protected static $_dbh;

    public function __construct($sTable, array $aColumns, $sJoin = '', $sWhere_0 = '', $sGroupBy = '', $sIndexColumn = '') {
        //This is PDO object for database connection.
        if(!isset(self::$_dbh)) self::$_dbh = Config_Database::getInstance();
        $this->_sTable = $sTable;
        $this->_aColumns = $aColumns;
        if($sJoin != '') $this->_sJoin = $sJoin;
        if($sWhere_0 != '') $this->_sWhere_0 = $sWhere_0;
        if($sGroupBy != '') $this->_sGroupBy = $sGroupBy;
        if($sIndexColumn != '') $this->_sIndexColumn = $sIndexColumn;
        $this->sQuery();
    }

    protected function sLimit() {
        if ( isset( $_GET['iDisplayStart'] ) && $_GET['iDisplayLength'] != '-1' ) {
             $sLimit = ' LIMIT ' . intval($_GET['iDisplayStart']) . ', ' . intval($_GET['iDisplayLength']);
        } else {
             $sLimit = '';
        }
        return $sLimit;
    }

    protected function sOrder() {
        $sOrder = '';
        if ( isset( $_GET['iSortCol_0'] ) ) {
             $sOrder = ' ORDER BY  ';
             for ( $i=0 ; $i<intval( $_GET['iSortingCols'] ) ; $i++ ) {
                if ( $_GET[ 'bSortable_'.intval($_GET['iSortCol_'.$i]) ] == 'true' ) {
                     $sOrder .= $this->_aColumns[ intval( $_GET['iSortCol_'.$i] ) ].' '.$_GET['sSortDir_'.$i] .', ';
                }
             }
             $sOrder = substr_replace( $sOrder, '', -2 );
             if ( $sOrder == ' ORDER BY' ) {
                  $sOrder = '';
             }  
        }
        return $sOrder;
    }

    protected function sWhere() {
        $sWhere = '';
        if ( $_GET['sSearch'] != '' ) {
             $sWhere = ' WHERE (';
             for ( $i=0 ; $i<count($this->_aColumns) ; $i++ ) {
                if ( $_GET['bSearchable_'.$i] == "true" ) {
                     $sWhere .= $this->_aColumns[$i]." LIKE '%". $_GET['sSearch'] ."%' OR ";
                }
             }
             $sWhere = substr_replace( $sWhere, "", -3 );
             $sWhere .= ')';
        }
        /* Conditions */
        if($this->_sWhere_0 != '') {
            if($sWhere != '') {
                $sWhere .= ' AND '.$this->_sWhere_0;    
            } else {
                $sWhere .= ' WHERE '.$this->_sWhere_0;
            }
        }
        /* Individual column filtering */
        for ( $i=0 ; $i<count($this->_aColumns) ; $i++ ) {
            if ( $_GET['bSearchable_'.$i] == "true" && $_GET['sSearch_'.$i] != '' ) {
                if ( $sWhere == '' ) {
                    $sWhere = 'WAHERE ';
                } else {
                    $sWhere .= ' AND ';
                }
                $sWhere .= $this->_aColumns[$i]." LIKE '%".$_GET['sSearch_'.$i]."%' ";
            }
        }
        return $sWhere;
    }

    protected function sQuery() {
        $sQuery = "SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $this->_aColumns)).' FROM '.
        $this->_sTable.
        $this->_sJoin.
        $this->sWhere().
        $this->_sGroupBy.
        $this->sOrder().
        $this->sLimit();
        $sth = self::$_dbh->query($sQuery);
        $this->_iResult = $sth->fetchAll(PDO::FETCH_NUM);
        /* Data set length after filtering */
        $sQuery = 'SELECT FOUND_ROWS()';
        $sth = self::$_dbh->query($sQuery);
        $aResultFilterTotal = $sth->fetchAll(PDO::FETCH_NUM);
        $this->_iFilteredTotal = $aResultFilterTotal[0][0];
        /* Total data set length */
        $sQuery = 'SELECT COUNT('.$this->_sIndexColumn.') FROM '.$this->_sTable;
        $sth = self::$_dbh->query($sQuery);
        $aResultTotal = $sth->fetchAll(PDO::FETCH_NUM);
        $this->_iTotal = $aResultTotal[0][0];
        return $this;
    }

    public function aaData() {
        $output = array(
            "sEcho" => intval($_GET['sEcho']),
            "iTotalRecords" => $this->_iTotal,
            "iTotalDisplayRecords" => $this->_iFilteredTotal,
            "aaData" => array()
        );
        return $output;
    }

    public function iResult() {
        return $this->_iResult;
    }
}

Now when i need to access the datatable it will work by creating the instance of the above DataTable Object for example.

$sTable = 'table1';
$aColumns = array('table1.column1', 'table1.colmun2', 'table2.column1', 'table2.column2', 'table3.column1');
//Put your logic of join over here, if you don;t have join just leave it empty
$sJoin = '';
//Put your condition over here, if you don;t have any leave it empty.
$sWhere = '';
$dataTable = new DataTable($sTable, $aColumns, $sJoin, $sWhere);
$output = $dataTable->aaData();
$iResult = $dataTable->iResult();
//Change Columns attribute and values
foreach($iResult as $k => $v) {
    $iResult[$k][3] = //Change 2nd row with whatever content you like.
}
$output['aaData'] = $iResult;
echo json_encode($output);

My Code will work for any number of joins from any number of table, still it have some limitations which i need to work on when i get time.

hope it comes of some use to you :),

Update : here is what you should be doing for your code.

//Create new PDO connection.
$host = 'localhoost';
$database = 'database';
$username = 'username';
$password = 'password';
$sDatabase = new PDO('mysql:host='.$host.';dbname='.$database,$username,$password);
//for the database to work with the class change the code in constructor with the below one.
public function __construct($sDatabase, $sTable, array $aColumns, $sJoin = '', $sWhere_0 = '', $sGroupBy = '', $sIndexColumn = '') {
    if(!isset(self::$_dbh)) self::$_dbh = $sDatabase;
    $this->_sTable = $sTable;
    $this->_aColumns = $aColumns;
    if($sJoin != '') $this->_sJoin = $sJoin;
    if($sWhere_0 != '') $this->_sWhere_0 = $sWhere_0;
    if($sGroupBy != '') $this->_sGroupBy = $sGroupBy;
    if($sIndexColumn != '') $this->_sIndexColumn = $sIndexColumn;
    $this->sQuery();
}
//Datatable config and instance.
$sTable = 'courses';
$aColumns = array(     
"leads.lead_id", 
"leads.date_time", 
"clients.username", 
"courses.course_type", 
"courses.location_name", 
"CONCAT(first_name,' ',surname) as full_name" 
);
$sJoin = ' LEFT JOIN leads ON leads.lead_get_course_id = courses.course_id';
$sJoin .= ' LEFT JOIN clients ON clients.client_id = courses.course_get_client_id';
$sWhere = "checked_by_admin='No'";
$dataTable = new DataTable($sDatabase, $sTable, $aColumns, $sJoin, $sWhere);
$output = $dataTable->aaData();
$iResult = $dataTable->iResult();
$output['aaData'] = $iResult;
echo json_encode($output);

let me know if you still have any issues

Ibrahim Azhar Armar
  • 25,288
  • 35
  • 131
  • 207
  • looks great, thanks so much for sharing it. i`m trying to implement it now but, struggling with what to change here: foreach($iResult as $k => $v) { $iResult[$k][3] = //Change 2nd row with whatever content you like. } – monsterboy Nov 24 '11 at 11:26
  • also a little unsure how to add my db connection details to the class, thanks for your time. – monsterboy Nov 24 '11 at 11:31
  • @masterboy, there is no need to change anything there, sometimes, we want to display image, or display href attribute or some html code, that is what that foreach is for, you can leave it empty or remove that foreach, if you don't want to change anything. – Ibrahim Azhar Armar Nov 24 '11 at 11:36
  • get it now, thanks! im getting this error Class 'Config_Database' not found – monsterboy Nov 24 '11 at 11:39
  • I definitely will, could you please provide with with the code for Config_Database I tried using the following code but, could not get it to work. http://stackoverflow.com/questions/1202712/mysql-database-config-in-a-seperate-class – monsterboy Nov 24 '11 at 11:55
  • wow thats great, thanks alot however getting this error: Call to a member function fetchAll() on a non-object – monsterboy Nov 24 '11 at 12:07
  • on this line: $aResultTotal = $sth->fetchAll(PDO::FETCH_NUM); – monsterboy Nov 24 '11 at 12:09
  • that is because you can use only PDO connection with the current code. attempting to use any other wil fetch an error. are you using the PDO connection. – Ibrahim Azhar Armar Nov 24 '11 at 12:11
  • im using the standard connection setup by dreamweaver is there a way to adapt my current connection to PDO to use with your script and my current setup? really need to get this working. – monsterboy Nov 24 '11 at 12:18
  • just did a search and I guess not, back to the drawing board :( – monsterboy Nov 24 '11 at 12:24
  • you can go ahead and use the connection string which i have updated in my above code. that should work for you. – Ibrahim Azhar Armar Nov 24 '11 at 12:46
  • its way over my head to change all the connections over to PDO will have to look for an alternative script. Shame as i had all but this setup. – monsterboy Nov 24 '11 at 13:09
  • if you are using the regular way for interacting with database, i strongly suggest, start using PDO and once you start using it you will cherish it. to get you started here is the tutorial for starters. http://net.tutsplus.com/tutorials/php/why-you-should-be-using-phps-pdo-for-database-access/ – Ibrahim Azhar Armar Nov 24 '11 at 13:27
  • 1
    thanks alot for all your help but, I found a way using this edited script: http://www.datatables.net/forums/discussion/comment/22964#Comment_22964 – monsterboy Nov 25 '11 at 07:55