MySQL and using only some results - mysql

I am trying to create a directory and having an issue calling the "listing image" in the results. The issue is that only some listings will have images, otherwise if they do not, I want them to use the default-image I have set up. When I try and add in the 'image' table to my query, it returns ONLY the results that have an image available (leaving out the other listings that do not have an image).
Here is my code:
public function search($neighborhood = null, $biz_filter = null) {
$neighborhood = $this->uri->segment(3);
$biz_filter = $this->uri->segment(4);
// SELECT
$this->db->select('*');
// MAIN TABLE TO GRAB DATA
$this->db->from('biz');
// TABLES TO JOIN
$this->db->join('city', 'city.city_id = biz.biz_cityID');
$this->db->join('zip', 'zip.zip_id = biz.biz_zipID', 'zip.zip_cityID = city.city_id');
$this->db->join('state', 'state.state_id = city.city_stateID');
$this->db->join('neighborhood', 'neighborhood.neighborhood_id = biz.biz_neighborhoodID');
$this->db->join('biz_filter', 'biz_filter.bizfilter_bizID = biz.biz_id');
$this->db->join('biz_category', 'biz_category.bizcategory_id = biz_filter.bizfilter_bizcategoryID');
if ($neighborhood != "-" AND $biz_filter != "-") {
$this->db->where('biz_category.bizcategory_slug', $biz_filter);
$this->db->where('neighborhood.neighborhood_slug', $neighborhood);
} elseif ($neighborhood != "-" AND $biz_filter == "-") {
$this->db->where('neighborhood.neighborhood_slug', $neighborhood);
} elseif ($neighborhood == "-" AND $biz_filter != "-") {
$this->db->where('biz_category.bizcategory_slug', $biz_filter);
} else {
}
// ORDER OF THE RESULTS
$this->db->group_by('biz_name asc');
// RUN QUERY
$query = $this->db->get();
// IF MORE THAN 0 ROWS ELSE DISPLAY 404 ERROR PAGE
return $query;
}
How can I add in the separate table, 'image' that holds the logo images ('image.image_file'). The 'image' table and 'biz' table are connected through the business ID i pass through each table (image.biz_id = biz.biz_id).
Anyone know how to resolve the query to work properly?

Just use
$this->db->join('image', 'image.biz_id = biz.biz_id', 'left');
To LEFT JOIN your image table. When there is no records in the table for the biz_id the image.image_file will have null values. Read here for more information.
You can use a COALESCE function to replace the "null" images with a predefined default value. Just replace your line with $this->db->select('*'); to this one:
// SELECT
$this->db->select("*, COALESCE(image.image_file, 'images/not_found.png') as my_image_file");
When you render the output make sure you use my_image_file column for the image.
On a side note: avoid using '*' in the select. Select only those columns you actually need. Selecting all columns unnecessarily increases the load on the database server resources.

Related

MySQL - Using LIKE ? With Multiple Columns Search

I've had a look around Stackoverflow and can't seem to find what I am looking for.
I have a dynamically updating AJAX search form which shows location data from database.
The issue I am having is with this query here:
$sql = "SELECT location FROM location_data WHERE location LIKE ? LIMIT 10";
Let me explain what is happening first. There are 3 different columns in a database table, one called location, one called CRS and one called tiploc.
I would like to display results like the following:
Select location FROM location_data WHERE location(textbox) is LIKE ?(what the person typed in) OR CRS is LIKE ? or TIPLOC is LIKE ?
Now i've only tried it with CRS so far, and ive done the following query:
$sql = "SELECT location FROM location_data WHERE location OR CRS LIKE ? LIMIT 10";
The above only displays the CRS result (exact match) and doesn't provide any suggestions for location, only shows CRS. Does anyone know how I can amend my query, so that it searches both location and CRS and TIPLOC, LIKE on location, but exact match only on CRS and TIPLOC?
if(isset($_REQUEST['term'])){
// Prepare a select statement
$sql = "SELECT location FROM location_data WHERE location LIKE ? LIMIT 10";
if($stmt = mysqli_prepare($link, $sql)){
// Bind variables to the prepared statement as parameters
mysqli_stmt_bind_param($stmt, "s", $param_term);
// Set parameters
$param_term = $_REQUEST['term'] . '%';
// Attempt to execute the prepared statement
if(mysqli_stmt_execute($stmt)){
$result = mysqli_stmt_get_result($stmt);
// Check number of rows in the result set
if(mysqli_num_rows($result) > 0){
// Fetch result rows as an associative array
while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)){
echo "<p>" . $row["location"] . "</p>";
}
} else{
echo "<p>No matches found</p>";
}
} else{
echo "ERROR: Could not able to execute $sql. " . mysqli_error($link);
}
}
// Close statement
mysqli_stmt_close($stmt);
}
// close connection
mysqli_close($link);
Now heres the on page search, the field I am pulling input from is called "location".
--Code for JS AJAX Search--
<script type="text/javascript">
$(document).ready(function(){
$('.search-box input[type="text"]').on("keyup input", function(){
/* Get input value on change */
$(".result").show();
var inputVal = $(this).val();
var resultDropdown = $(this).siblings(".result");
if(inputVal.length >2){
$.get("backend-search.php", {term: inputVal}).done(function(data){
// Display the returned data in browser
resultDropdown.html(data);
});
} else{
resultDropdown.empty();
}
});
// Set search input value on click of result item
$(document).on("click", ".result p", function(){
$(this).parents(".search-box").find('input[type="text"]').val($(this).text());
$(this).parent(".result").empty();
});
});
$(document).click(function(){
$(".result").hide();
});
</script>
You need to repeat the LIKE expression for each column.
$sql = "SELECT location
FROM location_data
WHERE location LIKE ? OR CRS LIKE ? OR TIPLOC LIKE ?
LIMIT 10";
And since there are now 3 placeholders in the query, you need to fill them all in with the binding:
mysqli_stmt_bind_param($stmt, "sss", $param_term, $param_term, $param_term);
For every individual expression in OR, you have to specify their comparison conditions. Note the location LIKE ? instead of LOCATION OR:
$sql = "SELECT location
FROM location_data
WHERE location LIKE ?
OR CRS LIKE ?
OR TIPLOC LIKE ?
LIMIT 10";
Note: LIMIT clause without ORDER BY is non-deterministic in nature, since MySQL stores an unordered dataset. It basically means that, any 10 rows can be returned by MySQL (if not using ORDER BY).

SQL SELECT query excluding an array of id's for infinite scroll [duplicate]

I have followed help located in this topic: Using infinite scroll w/ a MySQL Database
And have gotten close to getting this working properly. I have a page that is displayed in blocks using jquery masonry, in which the blocks are populated by data from a mysql database. When I scroll to the end of the page I successfully get the loading.gif image but immediately after the image it says "No more posts to show." which is what it should say if that were true. I am only calling in 5 posts initially out of about 10-15, so the rest of the posts should load when I reach the bottom of the page but I get the message that is supposed to come up when there really aren't any more posts.
Here is my javascript:
var loading = false;
$(window).scroll(function(){
if($(window).scrollTop() == $(document).height() - $(window).height()) {
var h = $('.blockContainer').height();
var st = $(window).scrollTop();
var trigger = h - 250;
if((st >= 0.2*h) && (!loading) && (h > 500)){
loading = true;
$('div#ajaxLoader').html('<img src="images/loading.gif" name="HireStarts Loading" title="HireStarts Loading" />');
$('div#ajaxLoader').show();
$.ajax({
url: "blocks.php?lastid=" + $(".masonryBlock:last").attr("id"),
success: function(html){
if(html){
$(".blockContainer").append(html);
$('div#ajaxLoader').hide();
}else{
$('div#ajaxLoader').html('<center><b>No more posts to show.</b></center>');
}
}
});
}
}
});
Here is the php on the page the blocks are actually on. This page initially posts 5 items from the database. The javascript grabs the last posted id and sends that via ajax to the blocks.php script, which then uses the last posted id to grab the rest of the items from the database.
$allPosts = $link->query("/*qc=on*/SELECT * FROM all_posts ORDER BY post_id DESC LIMIT 5");
while($allRows = mysqli_fetch_assoc($allPosts)) {
$postID = $link->real_escape_string(intval($allRows['post_id']));
$isBlog = $link->real_escape_string(intval($allRows['blog']));
$isJob = $link->real_escape_string(intval($allRows['job']));
$isVid = $link->real_escape_string(intval($allRows['video']));
$itemID = $link->real_escape_string(intval($allRows['item_id']));
if($isBlog === '1') {
$query = "SELECT * FROM blogs WHERE blog_id = '".$itemID."' ORDER BY blog_id DESC";
$result = $link->query($query);
while($blogRow = mysqli_fetch_assoc($result)) {
$blogID = $link->real_escape_string($blogRow['blog_id']);
$blogTitle = $link->real_escape_string(html_entity_decode($blogRow['blog_title']));
$blogDate = $blogRow['pub_date'];
$blogPhoto = $link->real_escape_string($blogRow['image']);
$blogAuthor = $link->real_escape_string($blowRow['author']);
$blogContent = $link->real_escape_string($blogRow['content']);
//clean up the text
$blogTitle = stripslashes($blogTitle);
$blogContent = html_entity_decode(stripslashes(truncate($blogContent, 150)));
echo "<div class='masonryBlock' id='".$postID."'>";
echo "<a href='post.php?id=".$blogID."'>";
echo "<div class='imgholder'><img src='uploads/blogs/photos/".$blogPhoto."'></div>";
echo "<strong>".$blogTitle."</strong>";
echo "<p>".$blogContent."</p>";
echo "</a>";
echo "</div>";
}
}
Here is the php from the blocks.php script that the AJAX calls:
//if there is a query in the URL
if(isset($_GET['lastid'])) {
//get the starting ID from the URL
$startID = $link->real_escape_string(intval($_GET['lastid']));
//make the query, querying 25 fields per run
$result = $link->query("SELECT * FROM all_posts ORDER BY post_id DESC LIMIT '".$startID."', 25");
$html = '';
//put the table rows into variables
while($allRows = mysqli_fetch_assoc($result)) {
$postID = $link->real_escape_string(intval($allRows['post_id']));
$isBlog = $link->real_escape_string(intval($allRows['blog']));
$isJob = $link->real_escape_string(intval($allRows['job']));
$isVid = $link->real_escape_string(intval($allRows['video']));
$itemID = $link->real_escape_string(intval($allRows['item_id']));
//if the entry is a blog
if($isBlog === '1') {
$query = "SELECT * FROM blogs WHERE blog_id = '".$itemID."' ORDER BY blog_id DESC";
$result = $link->query($query);
while($blogRow = mysqli_fetch_assoc($result)) {
$blogID = $link->real_escape_string($blogRow['blog_id']);
$blogTitle = $link->real_escape_string(html_entity_decode($blogRow['blog_title']));
$blogDate = $blogRow['pub_date'];
$blogPhoto = $link->real_escape_string($blogRow['image']);
$blogAuthor = $link->real_escape_string($blowRow['author']);
$blogContent = $link->real_escape_string($blogRow['content']);
$blogTitle = stripslashes($blogTitle);
$blogContent = html_entity_decode(stripslashes(truncate($blogContent, 150)));
$html .="<div class='masonryBlock' id='".$postID."'>
<a href='post.php?id=".$blogID."'>
<div class='imgholder'><img src='uploads/blogs/photos/".$blogPhoto."'></div>
<strong>".$blogTitle."</strong>
<p>".$blogContent."</p>
</a></div>";
}
}
echo $html;
}
I have tried using the jquery infinite-scroll plugin, but it seemed much more difficult to do it that way. I don't know what the issue is here. I have added alerts and did testing and the javascript script is fully processing, so it must be with blocks.php right?
EDIT: I have made a temporary fix to this issue by changing the sql query to SELECT * FROM all_posts WHERE post_id < '".$startID."' ORDER BY post_id DESC LIMIT 15
The blocks are now loading via ajax, however they are only loading one block at a time. The ajax is sending a request for every single block and they are fading in one after another, is it possible to make them all fade in at once with jquery masonry?
I seen your code in another answer, and I would recommend using the LIMIT functionality in MySql instead of offsetting the values. Example:
SELECT * FROM all_posts ORDER BY post_id DESC LIMIT '".(((int)$page)*5)."',5
This will just take a page number in the AJAX request and get the offset automatically. It's one consistent query, and works independent of the last results on the page. Send something like page=1 or page=2 in your jQuery code. This can be done a couple different ways.
First, count the number of elements constructed on the page and divide by the number on the page. This will yield a page number.
Second, you can use jQuery and bind the current page number to the body:
$(body).data('page', 1)
Increment it by one each page load.
Doing this is really the better way to go, because it uses one query for all of the operations, and doesn't require a whole lot of information about the data already on the page.
Only thing to note is that this logic requires the first page request to be 0, not 1. This is because 1*5 will evaluate to 5, skipping the first 5 rows. If its 0, it will evaluate to 0*5 and skip the first 0 rows (since 0*5 is 0).
Let me know any questions you have!
Have you tried doing any debugging?
If you are not already using, I would recommend getting the firebug plugin.
Does the ajax call return empty? If it does, try echoing the sql and verify that is the correct statement and that all the variables contain the expected information. A lot of things could fail considering there's a lot of communication happening between client, server and db.
In response to your comment, you are adding the html in this piece of code:
if(html){
$(".blockContainer").append(html);
$('div#ajaxLoader').hide();
}
I would do a console.log(html) and console.log($(".blockContainer").length) before the if statement.

How to save data from a table from another database in Laravel?

I need to save data from an order table from one database to another through Laravel. I created a function in my controller like this:
public function getMarketplace()
{
$orderoc = OrderOC::orderBy('oc_order.date_added', 'desc')
->join('oc_order_product', 'oc_order_product.order_id', 'oc_order.order_id')
->join('oc_order_history', 'oc_order_history.order_id', 'oc_order.order_id')
->where('oc_order_history.order_status_id', '=', '17')
->get();
foreach($orderoc as $oc){
$ordererp = new Order;
$ordererp->erp_createdid = $oc->created_id;
$ordererp->erp_marketplaceid = 1;
$ordererp->erp_site = rand(1,100000000);
$ordererp->erp_payment_method = $oc->payment_method;
$ordererp->erp_orderdate = $oc->date_added;
$ordererp->erp_orderaprove = $oc->date_added;
$ordererp->erp_billingid = 1;
$ordererp->erp_shippingid = 1;
$ordererp->erp_marketplace = 'Comércio Urbano';
$ordererp->erp_orderquantity = $oc->quantity;
$ordererp->erp_erro = '';
$ordererp->erp_product_ok = 1;
$ordererp->erp_compraId = null;
$ordererp->save();
if(strlen($oc->created_id) == 0){
$oc->created_id = rand(1,10000000);
$oc->save();
}
$orderprod = new OrderProduct;
$orderprod->erp_productid = $oc->product_id;
$orderprod->erp_createdid = $oc->created_id;
$orderprod->erp_model = $oc->model;
$orderprod->erp_quantity = $oc->quantity;
}
}
One table is from my ERP and the other is responsible for receiving OpenCart purchases, but every time I run, the same product appears more than once in my order table.
(It is possible to see through the purchase date, since created_id is created in the controller function)
Does anyone know how to tell me why data is duplicated when inserted inside a foreach? This is not the first time, if you tell me a more robust way of doing the job, I'm grateful. Any suggestion? Thank you in advance!
One possiblity is you put unique validation on a table that receive the data

How to get last inserted id with insert method in laravel

In my laravel project I am inserting multiple records at time with modelname::insert method. Now I want to get last inserted id of it.I read somewhere when you insert multiple records with single insert method and try to get the last_record_id it will gives you the first id of the last inserted query bunch. But my first question is how to get last record id with following code .If I am able to get first id of the bunch .I ll make other ids for other record by my own using incremental variable.
Code to insert multiple record
if(!empty($req->contract_name) && count($req->contract_name)>0)
{
for($i=0; $i<count($req->contract_name); $i++)
{
$contract_arr[$i]['client_id'] = $this->id;
$contract_arr[$i]['contract_name'] = $req->contract_name[$i];
$contract_arr[$i]['contract_code'] = $req->contract_code[$i];
$contract_arr[$i]['contract_type'] = $req->contract_type[$i];
$contract_arr[$i]['contract_ext_period'] = $req->contract_ext_period[$i];
$contract_arr[$i]['contract_email'] = $req->contract_email[$i];
$contract_arr[$i]['created_at'] = \Carbon\Carbon::now();
$contract_arr[$i]['updated_at'] = \Carbon\Carbon::now();
$contract_arr[$i]['created_by'] = Auth::user()->id;
$contract_arr[$i]['updated_by'] = Auth::user()->id;
if($req->startdate[$i] != ''){
$contract_arr[$i]['startdate'] = date('Y-m-d',strtotime($req->startdate[$i]));
}
if($req->enddate[$i] != ''){
$contract_arr[$i]['enddate'] = date('Y-m-d',strtotime($req->enddate[$i]));
}
}
if(!empty($contract_arr)){
Contract::insert($contract_arr);
}
}
You should be able to call it like this
$lastId = Contract::insert($contract_arr)->lastInsertId();
If i see right, you're using a Model. Direct inserting only shows an success boolean. Try this instead:
Contract::create($contract_arr)->getKey()

Laravel: Querying based on Input. If input is empty, get all

I have a calendar (FullCalendar) where the user can filter down results based on a few params (Tutor Secondary Tutor, Lesson, Location). When the user makes a change to the query it hits the following code.
The issue I am having is the 'OR'. What I really want is an IF input is null then get all.
If User { Get all lessons where lead_tutor_id = 1 and secondary_tutors_id = 1 }
If User and Location { Get lessons where the user is as above, but have location_id = 3 }
etc, etc.
So, is there a way I can fall back to get ALL the results IF only one or two filters are set?
$current_events = Calendar::Where(function($query) use ($start_time, $end_time, $tutor, $location, $lesson)
{
$query->whereBetween('date_from', [$start_time, $end_time])->orderBy('date_from')
->whereRaw('lead_tutor_id = ?
OR secondary_tutors_id = ?
OR location_id = ?
OR lesson_id = ?',
[
$tutor, // Input get() for user
$tutor, // Input get() for user
$location, // Input get() for location
$lesson, // Input get() for lesson
]
);
})->with('lessons', 'leadtutor', 'secondarytutor')->get();
I've been playing with Query Scopes, but this seems to fail if passing a NULL value through to it.
Any help is very much appreciated. Thanks in advance.
You can build the query on forehand, store it in a variable and use it once its build.
$query = isset($var) ? $var : '';
$query .= isset($othervar) ? $othervar : '';
whereBetween(*)->orderBy(*)->whereRaw($query)
Only thing you need to keep in mind is to insert the 'OR's in the right place . So have like a check for wether it is the first thing to be inserted or not, if not then put 'OR' in front of it.
Hope that is enough info to help you.
After the advice from Saint Genius, I have got this working:
$built_query = [];
isset($lead_tutor) ? $built_query['lead_tutor'] = 'lead_tutor_id = ' . $lead_tutor . ' ' : null;
isset($secondary_tutor) ? $built_query['secondary_tutor'] = 'secondary_tutors_id = ' . $secondary_tutor . ' ' : null;
isset($location_id) ? $built_query['location'] = 'location_id = ' . $location_id : null;
isset($lesson_id) ? $built_query['lesson'] = 'lesson_id = ' . $lesson_id : null;
// Flatten the array so we can create a query and add the word ADD in between each element.
$built_query = implode(" AND ", $built_query);
// Run the query
$current_events = Calendar::whereBetween('date_from', [$start_time, $end_time])->orderBy('date_from')->whereRaw($built_query)->with('lessons', 'leadtutor', 'secondarytutor')->get();