how to group by after the Where function into this query? - php

Hello folks I want to sort books by min and max price but I dont know where I will add the group by function after the WHERE ? here is the query
$sql = "SELECT DISTINCT bk.title AS Title, YEAR(bk.date_released) AS Year, bk.price AS Price, cat.name AS Category, aut.name AS Author FROM books bk
JOIN books_authors bk_aut
ON bk_aut.book_id = bk.id
JOIN authors aut
ON aut.id = bk_aut.author_id
JOIN books_categories bk_cat
ON bk_cat.book_id = bk.id
JOIN categories cat
ON cat.id = bk_cat.cat_id
JOIN books_locations bk_loc
ON bk_cat.book_id = bk.id
JOIN locations loc
ON loc.id = bk_loc.loc_id
";
if (isset($_GET['srch_for'])){
$locations = array();
$getters = array();
$queries = array();
foreach($_GET as $key => $value) {
$temp = is_array($value) ? $value : intval(trim($value));
if (!empty($temp)) {
list($key) = explode("-",$key);
if ($key == 'srch_locations'){
array_push($locations,$value);
}
if (!in_array($key,$getters)){
$getters[$key] = intval(trim($value));
}
}
}
if (!empty($locations)) {
$loc_qry = implode(",",$locations);
}
if(!empty($getters)) {
foreach($getters as $key => $value){
${$key} = $value;
switch($key) {
case 'srch_for':
array_push($queries, "(bk.title LIKE '%$srch_for%' || bk.description LIKE '%$srch_for%' || bk.isbn LIKE '%$srch_for%')");
case 'srch_author':
array_push($queries, "bk_aut.author_id = $srch_author");
break;
case 'srch_language':
array_push($queries, "bk_cat.cat_id = $srch_category");
break;
case 'srch_locations':
array_push($queries, "bk_loc.location_id IN ($loc_qry)");
break;
}
}
}
if(!empty($queries)) {
$sql .= " WHERE ";
$i=1;
foreach($queries as $query) {
if ($i < count($queries)) {
$sql .= $query." AND ";
}else{
$sql .= $query;
}
$i++;
}
}
$sql .= " ORDER BY bk.title ASC";
}
Run code s
I am beginner in php and I cant learn through listening because I am deaf which you help me guys thank you in advance

SELECT Title,Year, sum(Price) AS Price, Category,Author
FROM
(
SELECT DISTINCT bk.title AS Title, YEAR(bk.date_released) AS Year, bk.price AS Price, cat.name AS Category, aut.name AS Author
FROM books bk
JOIN books_authors bk_aut
ON bk_aut.book_id = bk.id
JOIN authors aut
ON aut.id = bk_aut.author_id
JOIN books_categories bk_cat
ON bk_cat.book_id = bk.id
JOIN categories cat
ON cat.id = bk_cat.cat_id
JOIN books_locations bk_loc
ON bk_cat.book_id = bk.id
JOIN locations loc
ON loc.id = bk_loc.loc_id
)T
Group By Title,Year, Category,A
You can use Sub query Like This..

Related

Binding multiple arrays in pdo

There are 3 different filters: books, authors and stores (select lists), and I may use their all together at once or only one or two of them, so I use UNION to get together all queries
require('database.php');
if(isset($_POST['books'])){
$books_ids = $_POST["books"];
}
if(isset($_POST['authors'])){
$authors_ids = $_POST["authors"];
}
if(isset($_POST['stores'])){
$stores_ids = $_POST["stores"];
}
$query = "";
if( !empty( $books_ids ))
{
$books_ids_in = implode(',', array_fill(0, count($books_ids), '?'));
$query .= "SELECT
b.id,
b.`name`,
b.`year`,
GROUP_CONCAT(DISTINCT a.`name`) AS author_names,
GROUP_CONCAT(DISTINCT s.`name`) AS store_names,
'book' as param
FROM
books AS b
LEFT JOIN books_authors AS b_a ON b.id = b_a.book_id
LEFT JOIN authors AS a ON a.id = b_a.author_id
LEFT JOIN books_stores AS b_s ON b.id = b_s.book_id
LEFT JOIN stores AS s ON s.id = b_s.store_id
WHERE
b.id IN (". $books_ids_in .")
GROUP BY b.id
ORDER BY b.id";
}
if( !empty( $authors_ids ) )
{
$authors_ids_in = implode(',', array_fill(0, count($authors_ids), '?'));
if (!empty($query)) {
$query .= " UNION ";
}
$query .= "SELECT
b.id,
b.`name`,
b.`year`,
GROUP_CONCAT(DISTINCT a.`name`) AS author_names,
GROUP_CONCAT(DISTINCT s.`name`) AS store_names,
'author' as param
FROM
books AS b
LEFT JOIN books_authors AS b_a ON b.id = b_a.book_id
LEFT JOIN authors AS a ON a.id = b_a.author_id
LEFT JOIN books_stores AS b_s ON b.id = b_s.book_id
LEFT JOIN stores AS s ON s.id = b_s.store_id
WHERE
b.id IN (
SELECT DISTINCT book_id FROM books_authors WHERE author_id IN (". $authors_ids_in .")
)
GROUP BY b.id
ORDER BY b.id";
}
if( !empty( $stores_ids ) )
{
$stores_ids_in = implode(',', array_fill(0, count($stores_ids), '?'));
if (!empty($query)) {
$query .= " UNION ";
}
$query .= "SELECT
b.id,
b.`name`,
b.`year`,
GROUP_CONCAT(DISTINCT a.`name`) AS author_names,
GROUP_CONCAT(DISTINCT s.`name`) AS store_names,
'store' as param
FROM
books AS b
LEFT JOIN books_authors AS b_a ON b.id = b_a.book_id
LEFT JOIN authors AS a ON a.id = b_a.author_id
LEFT JOIN books_stores AS b_s ON b.id = b_s.book_id
LEFT JOIN stores AS s ON s.id = b_s.store_id
WHERE
b.id IN (
SELECT DISTINCT book_id FROM books_stores WHERE store_id IN (". $stores_ids_in .")
)
GROUP BY b.id
ORDER BY b.id";
}
if( !empty( $query )) {
$stmt = $conn->prepare($query);
if( !empty( $books_ids ))
{
foreach ($books_ids as $k => $id) {
$stmt->bindValue(($k+1), $id);
}
}
if( !empty( $authors_ids ))
{
foreach ($authors_ids as $k => $id) {
$stmt->bindValue(($k+1), $id);
}
}
if( !empty( $stores_ids ))
{
foreach ($stores_ids as $k => $id) {
$stmt->bindValue(($k+1), $id);
}
}
$stmt->execute();
$results = $stmt->fetchAll();
echo json_encode($results);
}
$conn = null;
code works just fine when I use only one filter, but when I try to use 2 or more, I get error
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens' in C:\xampp\htdocs\bookstore\filter.php:123 Stack trace: #0 C:\xampp\htdocs\bookstore\filter.php(123): PDOStatement->execute() #1 {main} thrown in C:\xampp\htdocs\bookstore\filter.php on line 123
I guess, something's wrong with bindValue using but I don't know how to fix that?
UPD
var_dump($query) (3 books and 2 authors chosen)
string(1097) "SELECT b.id, b.name, b.year, GROUP_CONCAT(DISTINCT a.name) AS author_names, GROUP_CONCAT(DISTINCT s.name) AS store_names, 'book' as param FROM books AS b LEFT JOIN books_authors AS b_a ON b.id = b_a.book_id LEFT JOIN authors AS a ON a.id = b_a.author_id LEFT JOIN books_stores AS b_s ON b.id = b_s.book_id LEFT JOIN stores AS s ON s.id = b_s.store_id WHERE b.id IN (?,?,?) GROUP BY b.id ORDER BY b.id UNION SELECT b.id, b.name, b.year, GROUP_CONCAT(DISTINCT a.name) AS author_names, GROUP_CONCAT(DISTINCT s.name) AS store_names, 'author' as param FROM books AS b LEFT JOIN books_authors AS b_a ON b.id = b_a.book_id LEFT JOIN authors AS a ON a.id = b_a.author_id LEFT JOIN books_stores AS b_s ON b.id = b_s.book_id LEFT JOIN stores AS s ON s.id = b_s.store_id WHERE b.id IN ( SELECT DISTINCT book_id FROM books_authors WHERE author_id IN (?,?) ) GROUP BY b.id ORDER BY b.id" 01201
There are problems with your code for building a dynamic query.
When building a dynamic query you need to separate those parts of the query that are static from those that are dynamic.
You can see that the following code is static.
$query = "SELECT
b.id,
b.`name`,
b.`year`,
GROUP_CONCAT(DISTINCT a.`name`) AS author_names,
GROUP_CONCAT(DISTINCT s.`name`) AS store_names,
'book' as param
FROM
books AS b
LEFT JOIN books_authors AS b_a ON b.id = b_a.book_id
LEFT JOIN authors AS a ON a.id = b_a.author_id
LEFT JOIN books_stores AS b_s ON b.id = b_s.book_id
LEFT JOIN stores AS s ON s.id = b_s.store_id ";
And also
" GROUP BY b.id
ORDER BY b.id";
The rest of the code is dynamic.
When filtering records the WHERE clause is used and the AND & OR operators are used to filter records based on more than one condition.
The AND operator displays a record if both the first condition AND the second condition are true.
The OR operator displays a record if either the first condition OR the second condition is true.
so for the first condition WHERE is used but after that AND or OR must be used(using OR in your example)
// Static code
sql = "SELECT * FROM `table`"
// Set initial condition to WHERE
clause = "WHERE";
if( !empty( filter )){
Add clause to sql
Add condition to sql
change clause to OR or AND as required
}
Repeat for each filter
Note the filter is not changed until a filter is not empty and remains changed once changed.
The remaining static code is added after all the filters have been handled
To allow different filters to be applied you can use a flag.
$flag = 0;
if(isset($_POST['books'])){
$books_ids = $_POST["books"];
$flag += 1;
}
if(isset($_POST['authors'])){
$authors_ids = $_POST["authors"];
$flag += 10;
}
if(isset($_POST['stores'])){
$stores_ids = $_POST["stores"];
$flag += 100;
}
Use "lazy" binding when possible - passing data into execute will dramatically shorten your code.
See PDO info
You require to merge array to perform this. Using switch statement with the flag you merge the arrays required.
switch ($flag) {
case 1:
$param_array = $books_ids;
break;
case 10:
$param_array = $authors_ids;
break;
case 100:
$param_array = $stores_ids;
break;
case 11://books & authors
$param_array = array_merge($books_ids, $authors_ids);
break;
case 101://books & stores
$param_array = array_merge($books_ids, $stores_ids);
break;
case 110://authors & stores
$param_array = array_merge($authors_ids, $stores_ids);
break;
case 111://books & authors & stores
$param_array = array_merge(array_merge($books_ids,$authors_ids),$stores_ids);
break;
}
if( !empty( $query )) {
$stmt = $conn->prepare($query);
$stmt->execute($param_array);
$results = $stmt->fetchAll();
echo json_encode($results);
}
The following code uses the above points. I have echoed some lines to indicate results which can be removed once testing is done.Also some code has been commented out for testing.
//Set flag
$flag = 0;
if(isset($_POST['books'])){
$books_ids = $_POST["books"];
$flag += 1;
}
if(isset($_POST['authors'])){
$authors_ids = $_POST["authors"];
$flag += 10;
}
if(isset($_POST['stores'])){
$stores_ids = $_POST["stores"];
$flag += 100;
}
echo $flag. " <BR>";//Remove after testing
//Basic SQL statement
$query = "SELECT
b.id,
b.`name`,
b.`year`,
GROUP_CONCAT(DISTINCT a.`name`) AS author_names,
GROUP_CONCAT(DISTINCT s.`name`) AS store_names,
'book' as param
FROM
books AS b
LEFT JOIN books_authors AS b_a ON b.id = b_a.book_id
LEFT JOIN authors AS a ON a.id = b_a.author_id
LEFT JOIN books_stores AS b_s ON b.id = b_s.book_id
LEFT JOIN stores AS s ON s.id = b_s.store_id ";
// Set initial condition to WHERE
$clause = "WHERE";
if( !empty( $books_ids ))
{
$books_ids_in = implode(',', array_fill(0, count($books_ids), '?'));
$query .= $clause;
$query .= " b.id IN (". $books_ids_in .")";
// Set condition to OR for additional condition
$clause = " OR ";
}
if( !empty( $authors_ids ) )
{
$authors_ids_in = implode(',', array_fill(0, count($authors_ids), '?'));
/* This part commented out as I don't see relevance
if (!empty($query)) {
$query .= " UNION ";
}
*/
$query .= $clause;
$query .= " b.id IN (
SELECT DISTINCT book_id FROM books_authors WHERE author_id IN (". $authors_ids_in .")
)";
// Set condition to OR for additional condition
$clause = " OR ";
}
if( !empty( $stores_ids ) )
{
$stores_ids_in = implode(',', array_fill(0, count($stores_ids), '?'));
/* if (!empty($query)) {
$query .= " UNION ";
}
*/
$query .= $clause;
$query .= " b.id IN (
SELECT DISTINCT book_id FROM books_stores WHERE store_id IN (". $stores_ids_in .")
)";
$clause = " OR ";
}
//Add GROUP & ORDER
$query .= " GROUP BY b.id
ORDER BY b.id";
echo $query; //Remove after testing
//building $param_array
switch ($flag) {
case 1:
$param_array = $books_ids;
break;
case 10:
$param_array = $authors_ids;
break;
case 100:
$param_array = $stores_ids;
break;
case 11://books & authors
$param_array = array_merge($books_ids, $authors_ids);
break;
case 101://books & stores
$param_array = array_merge($books_ids, $stores_ids);
break;
case 110://authors & stores
$param_array = array_merge($authors_ids, $stores_ids);
break;
case 111://books & authors & stores
$param_array = array_merge(array_merge($books_ids,$authors_ids),$stores_ids);
break;
}
echo "<br>";
print_r($param_array);// remove after testing
/*
if( !empty( $query )) {
$stmt = $conn->prepare($query);
$stmt->execute($param_array);
$results = $stmt->fetchAll();
echo json_encode($results);
}
$conn = null;
Don't use same $k; use a variable and increment it with each bind; See below
$bindingIndex = 0;
if( !empty( $books_ids ))
{
foreach ($books_ids as $k => $id) {
$stmt->bindValue((++$bindingIndex), $id);
}
}
if( !empty( $authors_ids ))
{
foreach ($authors_ids as $k => $id) {
$stmt->bindValue((++$bindingIndex), $id);
}
}
if( !empty( $stores_ids ))
{
foreach ($stores_ids as $k => $id) {
$stmt->bindValue((++$bindingIndex), $id);
}
}

Get Results of a search form- MySQL PHP

I have a joined table and it gives all books of my database. And all books are displaying properly. But I need to work it according to search queries entered in form.
this is my query for join.
$rs = mysqli_query($connection,"SELECT DISTINCT bk.title As Title, YEAR(bk.date_released) AS Year, bk.price AS Price, cat.name AS Category, pub.name AS Publisher, aut.name AS Author,co.name AS Cover, cp.count AS Copies
FROM books bk
JOIN (SELECT book_id, COUNT(*) as count FROM copies GROUP BY book_id) cp
ON bk.id = cp.book_id
JOIN category cat
ON cat.id = bk.category_id
JOIN publishers pub
ON pub.id = bk.publisher_id
JOIN books_covers bk_co
ON bk_co.book_id = bk.id
JOIN covers co
ON co.id = bk_co.cover_id
JOIN books_authors bk_aut
ON bk_aut.book_id = bk.id
JOIN authors aut
ON aut.id = bk_aut.author_id
JOIN books_languages bk_lan
ON bk_lan.book_id = bk.id
JOIN languages lan
ON lan.id = bk_lan.lang_id
JOIN books_locations bk_loc
ON bk_loc.book_id = bk.id
JOIN locations loc
ON loc.id = bk_loc.location_id
ORDER BY bk.title ASC
");
$copies = mysqli_query($connection,"SELECT DISTINCT COUNT(copies.book_id) FROM copies INNER JOIN books ON copies.book_id=books.id
");
$dup = mysqli_query($connection,"SELECT book_id, COUNT(*) as count FROM copies GROUP BY book_id");
$rows_copies = mysqli_fetch_array($copies);
$rows = mysqli_fetch_assoc($rs);
$tot_rows = mysqli_num_rows($rs);
And this is my variables of search form
if(!empty($_GET)){
$title = $_GET['title'];
$author = $_GET['author'];
$isbn = $_GET['isbn'];
$language = $_GET['language'];
$publisher = $_GET['publisher'];
$year = $_GET['year'];
$category = $_GET['category'];
}else{
$title = "";
$author = "";
$isbn = "";
$language = "";
$publisher = "";
$year = "";
$category = "";
$language = "";
}
And this is my code for displaying results,
<div class="jumbo">
<?php if($tot_rows > 0){ ?>
<?php do { ?>
<div class="col-md-3">
<span class="product-image">
<img src="<?php echo $rows['Cover'] ?>" class="img-thumbnail product-img" alt="">
</span>
<ul class="iteminfo">
<li><strong>Title: </strong><?php echo $rows['Title'] ?></li>
<li><strong>Category: </strong><?php echo $rows['Category'] ?></li>
<li><strong>Author: </strong><?php echo $rows['Author'] ?></li>
<li><strong>Price: </strong><?php echo $rows['Price']." Rs" ?></li>
<li><strong>Publisher: </strong><?php echo $rows['Publisher'] ?></li>
<li><strong>Copies: </strong><?php echo $rows['Copies'] ?></li>
</ul>
</div>
<?php } while($rows=mysqli_fetch_assoc($rs)); }else{ ?>
<?php echo 'No Results'; }?>
</div>
How I get results only I searched with corresponding search queries. For an example if I search a book called "Romeo Juliet" I need to display that book only
I tried to test the diplay with this code and never succeed
$titlequery = mysqli_query($connection," SELECT * FROM "$rs" WHERE Title = "$title" ");
$rows = mysqli_fetch_assoc($titlequery);
Help me to solve this.
You're trying to execute a subquery, but the $rs variable you are passing in is a resource, not a string. If you set the original query to a variable and pass that in, then it should work:
$sql = "SELECT DISTINCT bk.title As Title, YEAR(bk.date_released) AS Year, bk.price AS Price, cat.name AS Category, pub.name AS Publisher, aut.name AS Author,co.name AS Cover, cp.count AS Copies
FROM books bk
JOIN (SELECT book_id, COUNT(*) as count FROM copies GROUP BY book_id) cp
ON bk.id = cp.book_id
JOIN category cat
ON cat.id = bk.category_id
JOIN publishers pub
ON pub.id = bk.publisher_id
JOIN books_covers bk_co
ON bk_co.book_id = bk.id
JOIN covers co
ON co.id = bk_co.cover_id
JOIN books_authors bk_aut
ON bk_aut.book_id = bk.id
JOIN authors aut
ON aut.id = bk_aut.author_id
JOIN books_languages bk_lan
ON bk_lan.book_id = bk.id
JOIN languages lan
ON lan.id = bk_lan.lang_id
JOIN books_locations bk_loc
ON bk_loc.book_id = bk.id
JOIN locations loc
ON loc.id = bk_loc.location_id
ORDER BY bk.title ASC
";
$rs = mysqli_query($connection, $query);
$titlequery = mysqli_query($connection, " SELECT * FROM ({$query}) WHERE Title = '{$title}'");
Also, watch your quotation marks in SQL queries when you need to use PHP quotation marks as string delimiters. PHP will interpret your string of " SELECT * FROM "$rs" WHERE Title = "$title" " as SELECT * FROM, the $rs resource, WHERE Title =, the $title variable, and , but without any concatenation. You'd need to backslash your SQL quotations, like " SELECT * FROM \"$rs\" WHERE Title = \"$title\" ", so PHP doesn't think you want to end your string.

MySQL select last image in LEFT JOIN

I have this function that lists the first inserted image and other data from accommodation database.
function getLIST($sort_by,$saved=0,$filter)
{
$session = JFactory::getSession();
$lang =& JFactory::getLanguage();
$query = "SELECT a.id FROM #__jomholiday_fields AS a where a.name='COM_JOMHOLIDAY_ACCOMODATION_RATING'";
$db = $this->getDbo();
$db->setQuery( $query );
$rating_id = $db->loadResult();
$query = "SELECT a.id FROM #__jomholiday_fields AS a where a.name='COM_JOMHOLIDAY_BOARD_BASIS'";
$db->setQuery( $query );
$board_basis_id = $db->loadResult();
$query = $db->getQuery(true);
$listing_expiry_days=(int)$this->getConf("listing_expiry_days");
if($listing_expiry_days)
{
$now=strtotime("now");
$temp=$now-$listing_expiry_days*(60*60*12);
$toold=date('Y-m-d',$temp);
}
else $toold=0;
$search_mod=0;
$query->select(
$this->getState(
'list.select',
'a.id, a.categories_id, a.number, a.headline, a.short_description, a.lat, a.lon, a.published, a.dpublished' .
', a.featured, a.address_name, a.created, a.modified, p.name , a.price_night, a.price_week, a.sleeps'
)
);
$query->from('#__jomholiday_listings AS a');
$query->select('p.name AS image');
$query->select('MAX(p.id)');
$query->join('LEFT', '#__jomholiday_photos AS p ON p.listings_id = a.id AND (p.rooms_id=0 OR p.rooms_id IS NULL) ');
$query->select('ac.name AS category_name');
$query->select('ac.rental AS price_type');
$query->join('LEFT', '#__jomholiday_categories AS ac ON ac.id = a.categories_id');
$query->where("(ac.lang='".$lang->getTag()."' OR ac.lang='*')");
//$query->where("p.id = MAX(p.id)");
$query->select('AVG(r.rating) AS rating_average');
$query->join('LEFT', '#__jomholiday_reviews AS r ON r.published="1" AND r.listingid=a.id');
if ($rating_id){
$query->select('f1.value AS accomodation_rating');
$query->join('LEFT', '#__jomholiday_listings_to_fields AS f1 ON f1.listings_id = a.id AND f1.fields_id='.$rating_id.'');
}
if ($board_basis_id){
$query->select('f2.value AS all_inclusive');
$query->join('LEFT', '#__jomholiday_listings_to_fields AS f2 ON f2.listings_id = a.id AND f2.fields_id='.$board_basis_id.' and f2.value="COM_JOMHOLIDAY_ALL_INCLUSIVE"');
$query->select('f3.value AS bed_breakfast');
$query->join('LEFT', '#__jomholiday_listings_to_fields AS f3 ON f3.listings_id = a.id AND f3.fields_id='.$board_basis_id.' and f3.value="COM_JOMHOLIDAY_BED_BREAKFAST"');
$query->select('f4.value AS full_board');
$query->join('LEFT', '#__jomholiday_listings_to_fields AS f4 ON f4.listings_id = a.id AND f4.fields_id='.$board_basis_id.' and f4.value="COM_JOMHOLIDAY_FULL_BOARD"');
$query->select('f5.value AS half_board');
$query->join('LEFT', '#__jomholiday_listings_to_fields AS f5 ON f5.listings_id = a.id AND f5.fields_id='.$board_basis_id.' and f5.value="COM_JOMHOLIDAY_HALF_BOARD"');
$query->select('f6.value AS room_only');
$query->join('LEFT', '#__jomholiday_listings_to_fields AS f6 ON f6.listings_id = a.id AND f6.fields_id='.$board_basis_id.' and f6.value="COM_JOMHOLIDAY_ROOM_ONLY"');
$query->select('f7.value AS self_cattering');
$query->join('LEFT', '#__jomholiday_listings_to_fields AS f7 ON f7.listings_id = a.id AND f7.fields_id='.$board_basis_id.' and f7.value="COM_JOMHOLIDAY_SELF_CATTERING"');
}
if ($saved)
{
$cids=JRequest::getString('savedlist', '', 'cookie');
$cid=explode(",",$cids);
JArrayHelper::toInteger($cid);
$cids=implode(",",$cid);
$query->where('a.id IN ( '. $cids .' )');
$search_mod=1;
}
$query->where("a.published='1'");
$query->where("a.approved='1'");
if ($toold) $query->where("a.dpublished>'$toold'");
if ($session->get('jom_zlat')!=null)
{
$lat1=(float)$session->get('jom_lat')-$session->get('jom_zlat');
$lat2=(float)$session->get('jom_lat')+$session->get('jom_zlat');
$lon1=(float)$session->get('jom_lon')-$session->get('jom_zlon');
$lon2=(float)$session->get('jom_lon')+$session->get('jom_zlon');
if ($lat1>$lat2){$temp=$lat1;$lat1=$lat2;$lat2=$temp;}
if ($lon1>$lon2){$temp=$lon1;$lat1=$lon2;$lon2=$temp;}
if ($lat1) $query->where("a.lat>".$lat1);
if ($lat2) $query->where("a.lat<".$lat2);
if ($lon1) $query->where("a.lon>".$lon1);
if ($lon2) $query->where("a.lon<".$lon2);
$search_mod=1;
}
if ($session->get('jom_address_select')!=null)
{
$temp=explode(",",$session->get('jom_address_select'));
if ($temp[0]) $temp1=$this->getRegion((int)$temp[0]);
if ($temp[1]) $temp1.=", ".$this->getRegion((int)$temp[1]);
if ($temp[2]) $temp1.=", ".$this->getRegion((int)$temp[2]);
$query->where("(a.address_name like '%".str_replace("'","\'",$temp1)."%')", ENT_QUOTES);
$search_mod=1;
}
if (str_replace(",","",$session->get('jom_booking')))
{
$temp=explode(",",$session->get('jom_booking'));
if ($temp[0] && $temp[2]>0)
{
$in=strtotime($temp[0]);
$out=strtotime($temp[1]);
$query->where("a.sleeps >= '".(int)$temp[2]."'");
while ($in<$out)
{
$query->where("(a.booking LIKE '%,".date("ymd",$in)."-".(int)$temp[2].",%' OR a.booking NOT LIKE '%,".date("ymd",$in)."-%' OR a.booking IS NULL)");
$in=strtotime('+1 day', $in);
}
}
$search_mod=1;
}
if ((int)$session->get('jomholiday_search_cat'))
{
$temp=explode(",",$session->get('jomholiday_search_cat'));
JArrayHelper::toInteger($temp);
$cidss = implode( ',', $temp );
$query->where("a.categories_id IN ( ". $cidss ." )");
$search_mod=1;
}
if ($session->get('jom_title')!=null){$search_mod=1; $query->where("(a.headline like '%".str_replace("'","\'",$session->get('jom_title'))."%' OR a.address_name like '%".str_replace("'","\'",$session->get('jom_title'))."%')", ENT_QUOTES);}
if ((int)$session->get('jom_pricemin')!=null){$search_mod=1; $query->where("a.price_night>=".(int)$session->get('jom_pricemin'));}
if ((int)$session->get('jom_pricemax')!=null) {$search_mod=1;$query->where("a.price_night<=".(int)$session->get('jom_pricemax'));}
if ($session->get('jomholiday_search'))
{
$val=json_decode($session->get('jomholiday_search'),true);
if (is_array($val))
{
$array_keys = array_keys($val);
foreach($array_keys as $key) if ($val[$key]!=null)
{
if (is_array($val[$key]))
{
$array_keys1 = array_keys($val[$key]);
foreach($array_keys1 as $key1)
{
$val[$key][$key1]=htmlspecialchars($val[$key][$key1],ENT_QUOTES);
$query->where('exists(select 1 from #__jomholiday_listings_to_fields AS fs'.$key.'_'.$key1.' where fs'.$key.'_'.$key1.'.listings_id = a.id AND fs'.$key.'_'.$key1.'.value="'.$val[$key][$key1].'" and fs'.$key.'_'.$key1.'.fields_id='.$key.')');
}
}
else if (trim($val[$key])!=null)
{
$val[$key]=htmlspecialchars(trim($val[$key]),ENT_QUOTES);
$query->where('exists(select 1 from #__jomholiday_listings_to_fields AS fs'.$key.' where fs'.$key.'.listings_id = a.id AND fs'.$key.'.value="'.$val[$key].'" and fs'.$key.'.fields_id='.$key.')');
}
}
$search_mod=1;
}
}
if ((int)JRequest::getVar('cid') && !$search_mod) $query->where("a.categories_id='".(int)JRequest::getVar('cid')."'");
if ((int)$session->get('jom_pricemin_f')!=null) $query->where("a.price_night>=".(int)$session->get('jom_pricemin_f'));
if ((int)$session->get('jom_pricemax_f')!=null) $query->where("a.price_night<=".(int)$session->get('jom_pricemax_f'));
if ($session->get('jomholiday_filter'))
{
$val=json_decode($session->get('jomholiday_filter'),true);
if (is_array($val))
{
$array_keys = array_keys($val);
foreach($array_keys as $key) if ($val[$key]!=null)
{
if (is_array($val[$key]))
{
$array_keys1 = array_keys($val[$key]);
foreach($array_keys1 as $key1)
{
$val[$key][$key1]=htmlspecialchars($val[$key][$key1],ENT_QUOTES);
$query->where('exists(select 1 from #__jomholiday_listings_to_fields AS fsf'.$key.'_'.$key1.' where fsf'.$key.'_'.$key1.'.listings_id = a.id AND fsf'.$key.'_'.$key1.'.value="'.$val[$key][$key1].'" and fsf'.$key.'_'.$key1.'.fields_id='.$key.')');
}
}
else if (trim($val[$key])!=null)
{
$val[$key]=htmlspecialchars(trim($val[$key]),ENT_QUOTES);
$query->where('exists(select 1 from #__jomholiday_listings_to_fields AS fsf'.$key.' where fsf'.$key.'.listings_id = a.id AND fsf'.$key.'.value="'.$val[$key].'" and fsf'.$key.'.fields_id='.$key.')');
}
}
}
}
if ($session->get('jom_address')!=null) $query->where("a.address_name like '".str_replace("'","\'",$session->get('jom_address'))."%'", ENT_QUOTES);
$query->group("a.id");
if ($this->getState('sort_by')=="a.created DESC") $order_s=$this->getState('sort_by');
elseif ($this->getState('sort_by')=="a.modified DESC") $order_s=$this->getState('sort_by');
elseif ($this->getState('sort_by')=="a.price_night DESC") $order_s=$this->getState('sort_by');
elseif ($this->getState('sort_by')=="a.price_night") $order_s=$this->getState('sort_by');
elseif ($this->getState('sort_by')=="a.headline") $order_s=$this->getState('sort_by');
else $order_s="";
if ($this->getConf(premium_first))
{
if ($order_s && JRequest::getVar('task')!='rss') $query->order("a.featured desc, ".$order_s.",id desc");
else $query->order("a.featured desc, a.created DESC, id desc");
}
else
{
if ($order_s && JRequest::getVar('task')!='rss') $query->order($order_s.",id desc");
else $query->order("a.created DESC, id desc");
}
if ($saved || JRequest::getVar('task')=='rss') $data = $this->_getList($query);
else $data = $this->_getList($query, $this->getState('limitstart'), $this->getState('limit'));
//echo $query;
return $data;
}
I need to retrive last inserted image from table #__jomholiday_photos. As you can see I did try to put the MAX(p.id) but that didn't helped.
I did try to put the $query->order("p.id DESC"); , that didn't helped aether.
Update:
Here is a query that is generated with this code
SELECT a.id, a.categories_id, a.number, a.headline, a.short_description, a.lat, a.lon,
a.published, a.dpublished, a.featured, a.address_name, a.created, a.modified,
p.name , a.price_night, a.price_week, a.sleeps,p.name AS image,MAX(p.id),ac.name AS category_name,
ac.rental AS price_type,AVG(r.rating) AS rating_average,f1.value AS accomodation_rating,
f2.value AS all_inclusive,f3.value AS bed_breakfast,f4.value AS full_board,f5.value AS half_board,
f6.value AS room_only,f7.value AS self_cattering
FROM #__jomholiday_listings AS a
LEFT JOIN #__jomholiday_photos AS p ON p.listings_id = a.id AND (p.rooms_id=0 OR p.rooms_id IS NULL)
LEFT JOIN #__jomholiday_categories AS ac ON ac.id = a.categories_id
LEFT JOIN #__jomholiday_reviews AS r ON r.published="1" AND r.listingid=a.id
LEFT JOIN #__jomholiday_listings_to_fields AS f1 ON f1.listings_id = a.id
AND f1.fields_id=22
LEFT JOIN #__jomholiday_listings_to_fields AS f2 ON f2.listings_id = a.id
AND f2.fields_id=10
and f2.value="COM_JOMHOLIDAY_ALL_INCLUSIVE" LEFT JOIN #__jomholiday_listings_to_fields AS f3
ON f3.listings_id = a.id AND f3.fields_id=10 and f3.value="COM_JOMHOLIDAY_BED_BREAKFAST"
LEFT JOIN #__jomholiday_listings_to_fields AS f4 ON f4.listings_id = a.id
AND f4.fields_id=10
and f4.value="COM_JOMHOLIDAY_FULL_BOARD" LEFT JOIN #__jomholiday_listings_to_fields AS f5
ON f5.listings_id = a.id AND f5.fields_id=10 and f5.value="COM_JOMHOLIDAY_HALF_BOARD"
LEFT JOIN #__jomholiday_listings_to_fields AS f6 ON f6.listings_id = a.id
AND f6.fields_id=10
and f6.value="COM_JOMHOLIDAY_ROOM_ONLY" LEFT JOIN #__jomholiday_listings_to_fields AS f7
ON f7.listings_id = a.id AND f7.fields_id=10 and f7.value="COM_JOMHOLIDAY_SELF_CATTERING"
WHERE (ac.lang='hr-HR' OR ac.lang='*')
AND a.published='1' AND a.approved='1'
GROUP BY a.id
ORDER BY a.featured desc, a.headline,id desc LIMIT 0, 15
'p.name' retrieves the firs record from '#__jomholiday_photos'. I need the last one of each listings.
I founded how to get the last image by replacing this code:
$query->join('LEFT', '#__jomholiday_photos AS p ON p.listings_id = a.id AND (p.rooms_id=0 OR p.rooms_id IS NULL) ');
with this one:
$query->join('LEFT', '( SELECT MAX(id) as maxpid , name, listings_id, rooms_id FROM #__jomholiday_photos GROUP BY id ORDER BY id DESC) AS p ON p.listings_id = a.id AND (p.rooms_id=0 OR p.rooms_id IS NULL) ');

PHP AND clause not showing results but OR is

I have a book search that is searching for books i am looking to have it search for books that share authors categories or publishers. I have it set up and it works for the OR clause e.g books that have a category CHILDRENS or HISTORY related to them this works correctly but when i search for books that belong to 2 categories (AND) e.g CHILDRENS AND MAGIC (Harry Potter) it does not show these book even though they are linked in the database.
Above is the search i have done using OR, When i do a search for books that belong to Childrens AND HISTORY
Above you can see i get no results for books that share Childrens and Magic when Harrypotter books do belong to both of these.
Above is the link in the database that gives every book their category, Magic is Category 1 and Childrens is Category 2 and you can see they both share these.
Below is the PHP code for the Query's
<?php
include 'header.php';
include 'searchscriptTEST.php';
$sql = "SELECT DISTINCT bk.title AS Title, bk.bookid AS BookID, bk.year AS Year, bk.publisher AS Publisher, aut.authorname AS Author
FROM book bk
JOIN book_category bk_cat
ON bk_cat.book_id = bk.bookid
JOIN categories cat
ON cat.id = bk_cat.category_id
JOIN books_authors bk_aut
ON bk_aut.book_id = bk.bookid
JOIN authors aut
ON aut.id = bk_aut.author_id";
if(isset($_GET['searchInput'])){
$input = $_GET['searchInput'];
$input = preg_replace('/[^A-Za-z0-9]/', '', $input);
}
if (isset($input)){
$getters = array();
$queries = array();
foreach ($_GET as $key => $value) {
$temp = is_array($value) ? $value : trim($value);
if (!empty($temp)){
if (!in_array($key, $getters)){
$getters[$key] = $value;
}
}
}
if (!empty($getters)) {
foreach($getters as $key => $value){
//${$key} = $value;
switch ($key) {
case 'searchInput':
array_push($queries,"(bk.title LIKE '%{$getters['searchInput']}%'
|| bk.description LIKE '%{$getters['searchInput']}%' || bk.isbn LIKE '%{$getters['searchInput']}%'
|| bk.keywords LIKE '%{$getters['searchInput']}%' || aut.authorname LIKE '%{$getters['searchInput']}%')");
break;
case 'srch_publisher':
array_push($queries, "(bk.publisher = '{$getters["srch_publisher"]}')");
break;
case 'Year':
if(isset($getters['Year1']) ==""){
array_push($queries, "(bk.year = '{$getters['Year']}')");
} else {
array_push($queries, "(bk.year BETWEEN '$value' AND '{$getters['Year1']}')");
}
break;
case 'srch_author':
if(isset($getters['authorOperator']) ==""){
array_push($queries, "(bk_aut.author_id = '{$getters["srch_author"]}')");
} else {
$operator = $getters['authorOperator'];
array_push($queries, "(bk_aut.author_id = '$value' $operator bk_aut.author_id = '{$getters['srch_author1']}')");
}
break;
case 'srch_category':
if(isset($getters['catOperator']) ==""){
array_push($queries, "(bk_cat.category_id = '{$getters["srch_category"]}')");
} else {
$operator1 = $getters['catOperator'];
array_push($queries, "(bk_cat.category_id = '$value' $operator1 bk_cat.category_id = '{$getters['srch_category1']}')");
}
break;
}
}
}
if(!empty($queries)){
$sql .= " WHERE ";
$i = 1;
foreach ($queries as $query) {
if($i < count($queries)){
$sql .= $query." AND ";
} else {
$sql .= $query;
}
$i++;
}
}
$sql .= " GROUP BY bk.title ORDER BY bk.title ASC";
var_dump($sql);
}else{
$sql .= " GROUP BY bk.title ORDER BY bk.title ASC";
}
$rs = mysql_query($sql) or die(mysql_error());
$rows = mysql_fetch_assoc($rs);
$tot_rows = mysql_num_rows($rs);
?>
This is the SQL Dump that gets sent to the database,
SELECT
DISTINCT bk.title AS Title,
bk.bookid AS BookID,
bk.year AS Year,
bk.publisher AS Publisher,
aut.authorname AS Author
FROM book bk
JOIN book_category bk_cat ON bk_cat.book_id = bk.bookid
JOIN categories cat ON cat.id = bk_cat.category_id
JOIN books_authors bk_aut ON bk_aut.book_id = bk.bookid
JOIN authors aut ON aut.id = bk_aut.author_id
WHERE
(bk_cat.category_id = '2' AND bk_cat.category_id = '1')
GROUP BY bk.title
ORDER BY bk.title ASC
There are multiple ways to do this but the simplist would be to use a WHERE clause something like this to SELECT books which are in more then one category:
WHERE
`bk`.`book_id` IN (SELECT `book_id` FROM `book_category` WHERE `category_id` = '2')
AND `bk`.`book_id` IN (SELECT `book_id` FROM `book_category` WHERE `category_id` = '1')
After formatting your query so that it's actually readable you see the line:
bk_cat.category_id = '2' AND bk_cat.category_id = '1'
That wont work, category_id can not be both 2 and 1 at the same time.
Your query should look something like:
SELECT books.*
FROM books
JOIN book_categories bc1 ON books.id = bc1.book_id AND bc1.category_id = 1
JOIN book_categories bc2 ON books.id = bc2.book_id AND bc1.category_id = 2
You need to JOIN twice on categories, or as many times as you have categories to match.

CodeIgniter partially override a method

I am trying to refactor this code a bit. Originally I had two different models, both extending MY_Model. However, most of the code was repetitive so now I am having First_model extend MY_Model and Second_model extends First_model. I cleaned up most of code from Second_model that it inherits from First_model, but I have several methods within Second_model that are only slightly different from the same method in First_model. Consider the following code:
First_model
class First_model extends MY_Model
{
private function getPostsByPostIDs($postIDs)
{
$postIDs = $this->strictCastIntArray($postIDs);
$postIDSqlArray = implode(",", $postIDs);
$year = date('Y');
$month = date('n');
$sql = "SELECT
post.id,
post.useraccount_id,
user.first_name user_first_name,
user.last_name user_last_name,
user.gender user_gender,
user.profile_pic user_profile_pic,
post.class_id,
post.school_id school_id,
school.display_name school_name,
school.state,
school.city,
post.karma_awarded_id,
post.is_parent_post,
post.reply_to_post_id,
post.comment_text,
post.image_url,
post.ts_created,
UNIX_TIMESTAMP(post.ts_created) post_timestamp,
post.ts_modified,
user.facebook_uid user_facebook_id,
user.id user_id,
sum(ka.karma) monthly_karma
FROM
WallPosts post
JOIN UserAccounts account ON (account.id = post.useraccount_id)
JOIN Users user ON (user.id = account.user_id)
LEFT JOIN Schools school ON (post.school_id = school.id)
LEFT JOIN KarmaAwarded ka ON (ka.user_id IN (SELECT
IFNULL(u_all.id, user.id)
FROM UserAccounts ua
INNER join Users u ON u.id = ua.user_id
LEFT join Users u_all ON u_all.facebook_uid = u.facebook_uid
WHERE ua.id = post.useraccount_id)
AND YEAR(ka.ts_created) = {$year}
AND MONTH(ka.ts_created) = {$month})
WHERE
post.id IN ({$postIDSqlArray})
GROUP BY post.id";
$query = $this->db->query($sql);
$queryResults = $query->result_array();
$functionResults = array();
foreach ($queryResults as $row) {
$functionResults[$row["id"]] = $row;
}
return $functionResults;
}
}
Second_model
class Second_model extends First_model
{
private function getPostsByPostIDs($postIDs)
{
$postIDs = $this->strictCastIntArray($postIDs);
$postIDSqlArray = implode(",", $postIDs);
$year = date("Y");
$month = date("n");
$sql = "SELECT
post.id,
post.useraccount_id,
user.first_name user_first_name,
user.last_name user_last_name,
user.gender user_gender,
user.profile_pic user_profile_pic,
post.class_id,
post.school_id school_id,
school.display_name school_name,
school.state,
school.city,
post.karma_awarded_id,
post.is_parent_post,
post.reply_to_post_id,
post.comment_text,
post.image_url,
UNIX_TIMESTAMP(post.ts_created) ts_created,
post.ts_modified,
user.facebook_uid user_facebook_id,
user.id user_id,
SUM(ka.karma) monthly_karma,
post.answer_status_flags
FROM
WallPosts post
JOIN UserAccounts account ON (account.id = post.useraccount_id)
JOIN Users user ON (user.id = account.user_id)
LEFT JOIN Schools school ON (post.school_id = school.id)
LEFT JOIN KarmaAwarded ka ON (ka.user_id IN (
SELECT
IFNULL(u_all.id, user.id)
FROM
UserAccounts ua
INNER JOIN Users u ON (u.id = ua.user_id)
LEFT OUTER JOIN Users u_all ON (u_all.facebook_uid = u.facebook_uid)
WHERE ua.id = post.useraccount_id)
AND YEAR(ka.ts_created) = {$year} AND MONTH(ka.ts_created) = {$month})
WHERE
post.id IN ({$postIDSqlArray})
GROUP BY post.id";
$query = $this->db->query($sql);
$queryResults = $query->result_array();
$functionResults = array();
foreach ($queryResults as $row) {
$functionResults[$row['id']] = $row;
}
return $functionResults;
}
}
Notice the only thing different is the query in the $sql variable. I am wondering can I somehow make the method in the first model protected and only change the query in the second? Or is there a more efficient way to trim down this code? I have several methods this same thing applies to and it seems a bit much to keep redefining the methods in the new Class.
I would think about pass the $sql as a variable in your models:
In your First Model you would have:
private $sqlPostId = '';
public function __construct() {
$this->sqlPostId = "SELECT
post.id,
post.useraccount_id,
user.first_name user_first_name,
user.last_name user_last_name,
user.gender user_gender,
user.profile_pic user_profile_pic,
post.class_id,
post.school_id school_id,
school.display_name school_name,
school.state,
school.city,
post.karma_awarded_id,
post.is_parent_post,
post.reply_to_post_id,
post.comment_text,
post.image_url,
post.ts_created,
UNIX_TIMESTAMP(post.ts_created) post_timestamp,
post.ts_modified,
user.facebook_uid user_facebook_id,
user.id user_id,
sum(ka.karma) monthly_karma
FROM
WallPosts post
JOIN UserAccounts account ON (account.id = post.useraccount_id)
JOIN Users user ON (user.id = account.user_id)
LEFT JOIN Schools school ON (post.school_id = school.id)
LEFT JOIN KarmaAwarded ka ON (ka.user_id IN (SELECT
IFNULL(u_all.id, user.id)
FROM UserAccounts ua
INNER join Users u ON u.id = ua.user_id
LEFT join Users u_all ON u_all.facebook_uid = u.facebook_uid
WHERE ua.id = post.useraccount_id)
AND YEAR(ka.ts_created) = {$year}
AND MONTH(ka.ts_created) = {$month})
WHERE
post.id IN ({$postIDSqlArray})
GROUP BY post.id";
}
private function getPostsByPostIDs($postIDs)
{
$postIDs = $this->strictCastIntArray($postIDs);
$postIDSqlArray = implode(",", $postIDs);
$year = date('Y');
$month = date('n');
// Here you use the defined variable in the constructor
$query = $this->db->query($this->sqlPostId);
$queryResults = $query->result_array();
$functionResults = array();
foreach ($queryResults as $row) {
$functionResults[$row["id"]] = $row;
}
return $functionResults;
}
And then you just have to change the SQL in the construct function in your second Model and go.

Categories