MySQL Join and Distinct - php

I have two tables one called area and one called area covered.
Table area contains the fields postcode and region.
e.g:
area table contains postcode - AB10 region - Aberdeen
area covered table contains id - 1 postcode - AB10 date - 1364989057
Now I have a form which searches for either the postcode or the region. I'm using JQuery's autocomplete and can get either postcode or the region but not both.
at the moment I have:
$result = $db->query("SELECT DISTINCT `postcode` FROM `areaCovered` WHERE `postcode` LIKE '%$search%' ORDER BY `postcode` ASC") or die('Something went wrong');
Then I use the data retrieved from the database result and put into JSON:
$json = '[';
$first = true;
while ($row = $result->fetch_assoc())
{
if (!$first) { $json .= ','; } else { $first = false; }
$json .= '{"value":"'.$row['postcode'].'"}';
}
$json .= ']';
echo $json;
How can I firstly join the two tables to search for either postcode or region that exists only in the area covered table and then output the result whether it is region or the postcode.
I hope that makes sense to you,
thanks

Instead of distinct you should use group by, and join them.
Something in the lines of:
select
a.`postcode` as postcode,
a.`region` as region,
from
`area` as a
inner join
`areaCovered` as ac
on
a.`postcode`=ac.`postcode`
where
a.`postcode` like '%$search%'
or
a.`region` like '%$search%'
group by
a.`postcode`
order by
a.`postcode` asc
Preferably I would just json_encode() the whole result set and parse it client side, but it looks like you may need to have a special JSON structure for a jQuery plugin?
$list = array();
while ($row = $result->fetch_assoc()) {
array_push(
$list,
array('value' => $row['postcode'] . ', ' . $row['region'])
);
}
echo json_encode($list);
This will create a JSON structure that looks like;
[
{
"value": "123 45, Region 1"
},
{
"value": "678 90, Region 2"
},
...
]

Related

Creating a search in php - typing in a city and getting the attractions for that city listed below

I have created a database in phpMyAdmin. I want to create a search so it will display tourist attractions. So for example if I type in London the Big Ben will appear, as well as a number of other tourist attractions in London. I want to be able to type in a city and then tourist attractions for that city will appear below.
All the search tutorials I have looked at only retrieve data from one table, and I am retrieving it from two.
I have a table called city, and in that table there is city_id and city_name
I have a second table called attractions and in that table there is city_id, tourist_id, attraction_name, latitude, longitude and cost.
I would like to be able to create a search so when I type in the city_name the attraction_name, latitude, longitude and cost appears. However I don't know how to link these two tables together in the mysql_query. If anyone could help me that would be really great. Thanks
<?php
require_once('config1.php');
$output = '';
if(isset($_POST['search'])){
$searchq = $_POST['search'];
$query = mysql_query("SELECT * FROM zz_attractions INNER JOIN city on zz_attractions.city_id = zz_city.city_id where zz_city.city_name = ? LIKE '%searchq%'") or die("could not search");
$count = mysql_num_rows ($query);
if ($count == 0) {
$output = 'there was no search results';
} else {
while $row = mysql_fetch_array($query)) {
$attraction_name = $row['attractionname'];
$lat = $row['latitude'];
$long = $row['longitude'];
$cost = $row['cost'];
$output .= '<div>'.$attraction_name.' '.lat'. '.long.' '.cost.'</div>';
}
?>
You need to make a link between the two tables, using an unique value which is present in both: extra, we have city_id !
So, what you have to do know, is get the values you want using this id.
You have the name of a city, linked to an unique id, and this id brings you to a list of tourist attractions.
You have to make two SQL resquests:
- Get the city_id depending on city_name
- Get the data using this city_id
One solution is to use subquery :
SELECT attraction_name, latitude, longitude, cost FROM attractions WHERE city_id IN (SELECT city_id FROM city WHERE city_name ILIKE 'London');
What you want to use is a "join" query. That looks a little something like this
SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.id;
In your case that query might look like
SELECT * FROM attractions INNER JOIN city on attractions.city_id = city.city_id where city.city_name = ?
There're more ways how to implement your search. Really easy example for start is to use some autoComplete. You can use Bootstrap TypeAhead or as in and example jQuery EasyAutocomplete.
var options = {
url: function(phrase) {
return "http://yourSearchUrl.com/search/?query=" + phrase;
},
list: {
onChooseEvent: function() {
var item = $(".autocomplete").getSelectedItemData();
//fill your additional search form with ID for submit
//$("#input-qId").val(item.id);
//or redirect to page with attraction
window.location.href = "http://yourPage.com/attraction/?id=" + item.id;
}
},
template: {
type: "custom",
method: function(value, item) {
//custom template for autocomplete container
return "<span data-id='" + item.id + "'>" + item.value + "</span>";
}
},
getValue: "value" //defines array index with value
};
//your input selector
$(".autocomplete").easyAutocomplete(options);
For your search page you can return JSON array from select then. Two possible scenarios for search. When user type "Lo" you can show list of cities.
SELECT city_id, city_name FROM city WHERE city_name LIKE %get_url_phrase%;
Second scenario you search after submitting full city name. Also can return result by just partial city name.
SELECT * FROM attractions WHERE city_id IN (SELECT city_id FROM city WHERE city_name LIKE %get_url_phrase%);
If you search first just for city, then you can pass city_id to attraction search page and perform query
SELECT * FROM attractions WHERE city_id = "cityIdParam"
Possible to match sql query on exact phrase match, city_name = "London", fulltext search, in second query use table JOIN. Like clause just for example, not good performance at all.
The result JSON would be in form like:
[{"id": 1, "value": "AttractionName"}]
If you provide me with more accurate info about implementation i can answer you more :)

Get Value into an Array on Form Submission

Currently i am getting the value like this...
$property_buildingorlocation = ($_GET['buildingorlocation']);
Some times the user will input......
buildingname, areaname, cityname (array size to be 3)
arename, cityname (array size to be 2)
cityname (array size to be 1)
hence there will be 2 commas, 1 comma or no comma.
I want to get the data into array, either dynamically set the size of the array depending on number of inputs or commas (sizes mentioned above)
next if array size is 3, then i want to search in three mysql columns (of choice) with an and operator
if array size is 2 then i want to search in two mysql columns (of choice) with an and operator
if array size is 1 then search in 1 mysql column
i know i am pushing it with such an open question, but i need help... i have been at it since morning can't figure it out....
Put data into array
$searchparams=explode(',',$property_buildingorlocation);
$searchparams=('trim',$searchparams);
Count number of elements
$searchparamscount=count($searchparams);
Do your logic using switch
switch ($searchparamscount) {
case 1:
...
break;
case 2:
...
break;
case 3:
...
break;
}
Finally ended up using the logic below... it is working.
if (!empty($property_buildingorlocation)) {
$searchparams = array_map('trim', explode(',', $property_buildingorlocation));
$searchparamscount=count($searchparams);
// If Property Buildingname, Areaname and City are given
if ($searchparamscount == 3) {
$wheres[] = 'property_buildingname LIKE :property_buildingname AND property_areaname LIKE :property_areaname AND property_city LIKE :property_city';
$params[':property_buildingname'] = $searchparams[0];
$params[':property_areaname'] = $searchparams[1];
$select7 = $con->prepare("SELECT city_id, city_name from tbl_city WHERE city_name LIKE (:property_city)");
$select7->setFetchMode(PDO::FETCH_ASSOC);
$select7->bindParam(':property_city', $searchparams[2], PDO::PARAM_STR);
$select7->execute();
while($data7=$select7->fetch()){
$searchparams[2] = $data7['city_id'];
}
$params[':property_city'] = $searchparams[2];
// If Property Areaname and City are given
} else if ($searchparamscount == 2) {
$wheres[] = 'property_areaname LIKE :property_areaname AND property_city LIKE :property_city';
$params[':property_areaname'] = $searchparams[0];
$select7 = $con->prepare("SELECT city_id, city_name from tbl_city WHERE city_name LIKE (:property_city)");
$select7->setFetchMode(PDO::FETCH_ASSOC);
$select7->bindParam(':property_city', $searchparams[1], PDO::PARAM_STR);
$select7->execute();
while($data7=$select7->fetch()){
$searchparams[1] = $data7['city_id'];
}
$params[':property_city'] = $searchparams[1];
}
// If Property City is given
else if ($searchparamscount == 1) {
$wheres[] = 'property_city LIKE :property_city';
$select7 = $con->prepare("SELECT city_id, city_name from tbl_city WHERE city_name LIKE (:property_city)");
$select7->setFetchMode(PDO::FETCH_ASSOC);
$select7->bindParam(':property_city', $searchparams[0], PDO::PARAM_STR);
$select7->execute();
while($data7=$select7->fetch()){
$searchparams[0] = $data7['city_id'];
}
$params[':property_city'] = $searchparams[0];
}
}

How to combine multiple tables data and encode json as one array?

I have encoded json array from one month table data as below but how can I combine multiple data table with other month in one json array and GROUP BY dept after combining all data?
<?php
include("dbconfig.php");
$sql = "SELECT dept, SUM(ttlot) AS sum_ot, SUM(ttlnorm) AS sum_norm
FROM month_jan
GROUP BY dept
ORDER BY sum_ot DESC";
$result = mysqli_query($dbconfig, $sql) or die("Error in Selecting " . mysqli_error($dbconfig));
$category = array();
$category['name'] = 'Dept';
$series1 = array();
$series1['name'] = 'Normal';
$series2 = array();
$series2['name'] = 'OT';
$emparray = array();
while ($row = mysqli_fetch_assoc($result)) {
$category['data'][] = $row['dept'];
$series1['data'][] = $row['sum_norm'];
$series2['data'][] = $row['sum_ot'];
}
$result = array();
array_push($result,$category);
array_push($result,$series1);
array_push($result,$series2);
$json = json_encode($result,JSON_NUMERIC_CHECK);
echo $json;
mysqli_close($dbconfig);
?>
Output in January month:
[{"name":"Dept","data":["CNC","MACH","ANOD","BUFF","CAST","POLISH","SL","EPT","TUMB","TOOL","SHOT","QC","LOG","MAIN","LC","WWT","OG","NPD","E-COAT","SFT"]},{"name":"Normal","data":[47429.1,39975.7,34553.8,49075.9,28316.3,21237.1,13492.5,5848.2,7691.1,6963.9,5636.1,7555.8,5821.9,2161.2,1812,1191.7,1479.1,1299.6,11542.6,602]},{"name":"OT","data":[20041,17874,14431,13535.5,8800.5,5613.5,3569.5,3101,2327,2278,2237,2142,1810,942,690,456,297,110.5,66,50.5]}]
What result I want after combining four months:
[{"name":"Month","data":["Jan","Feb","Mac","Apr"]},{"name":"Normal","data":[504291,409757,295538,430759]},{"name":"OT","data":[89041,96874,81431,80535]}]
Does anyone can help me to solve the problem?
I did it manually by printing them, I think this is an alternative solution if you are having the some problem encoding to JSON of two tables.
Sometime rows with the same name produces an error on json_encode() function.
<?php
session_start();
require("../config.php");
$output = array();
$id = $_GET['id'];
if(isset($_SESSION['user'])){
$f_data ='';
$sql = "SELECT * FROM quiz WHERE subject_id=$id ORDER BY id DESC";
$query=$conn->query($sql);
while($row=$query->fetch_array()){
$sql2 = "SELECT * FROM q_details WHERE id=$row[2] ORDER BY id DESC LIMIT 1";
$query2=$conn->query($sql2);
while($row2=$query2->fetch_array()){
$f_data .= '{
"id":"'.$row[0].'",
"subject_id":"'.$row[1].'",
"questionaire_id":"'.$row[2].'",
"name":"'.$row[3].'",
"description":"'.$row[4].'",
"start":"'.$row[5].'",
"end":"'.$row[6].'",
"date":"'.$row[7].'",
"questionaire_name":"'.$row2[2].'",
"questionaire_description":"'.$row2[3].'"
},';
}
}
$f_data = substr($f_data, 0, -1);
echo '['.$f_data.']';
}
else{
echo"<script>window.open('http://localhost/lnhs_app/#/','_self')</script>";
}
?>
If you have rows with the same name you should rename the other like what I did on the example above (questionaire_name, questionaire_description).
It will produce this output:
[{ "id":"1", "subject_id":"2", "questionaire_id":"1", "name":"Quiz 1", "description":"Answer this quiz within 1 hour", "start":"7:30AM", "end":"8:30AM", "date":"08-01-18", "questionaire_name":"Right triangle", "questionaire_description":"Questionaire # 1" }]
With MySQL's JSON features and a combination of GROUP_CONCAT you can do some pretty awesome things with combining tables:
Your desired result:
[{"name":"Month","data":["Jan","Feb","Mac","Apr"]},{"name":"Normal","data":[504291,409757,295538,430759]},{"name":"OT","data":[89041,96874,81431,80535]}]
Utilizing GROUP_CONCAT you don't need joining tables but simply a group by field by which your fields are aggregated:
SELECT
CONCAT('{\"NAME\" : \"NORMAL\",',
'\"data\": [', GROUP_CONCAT( '"', SUM(ttlnorm), '"'), ']},',
'{\"NAME\" : \"OT\",',
'\"data\": [', GROUP_CONCAT( '"', SUM(ttlot), '"'), ']}',
)
from month_jan
GROUP BY dept;
If you are using a table structure that stores by month ("month_jan"), you will need to perform a union amongst your months or change your table structure so that all months needed are included within the same table. You can perform your concatenation on multiple levels based on your GROUP BY's. For example, if you have two group by fields, you will be able to nest your JSON:
ex: GROUP BY DEPT, MONTH
SELECT
CONCAT('{',
'\"DEPT\" :\"', dept,'\",',
'{\"NAME\" : \"Month\",',
'\"data\": [', GROUP_CONCAT( '"', month, '"'), ']},',
'{\"NAME\" : \"NORMAL\",',
'\"data\": [', GROUP_CONCAT( '"', SUM(ttlnorm), '"'), ']},',
'{\"NAME\" : \"OT\",',
'\"data\": [', GROUP_CONCAT( '"', SUM(ttlot), '"'), ']}',
)
from ttl_ot_norm
GROUP BY dept, month;
As a result, your data within your GROUP_CONCAT's will work out according to the form you expressed.
An alternate solution is to create a table that updates based on a cron job or table trigger and places this data into a JSON field type so it's continuously ready for retrieval with a cheap CPU cost. This way, you won't have the additional overhead of the concatenation and table joining on each query.
You can skip a lot of your PHP aggregation by combing GROUP_CONCAT and grouping your tables. I've saved hundreds of hours of programming over the years with this and a combination of MySQL's JSON features (link below)
Version 8 introduced these features where you don't need to create your own JSON like strings with JSON_ARRAYAGG and other great JSON features. Although, the above will work with version 5 and up.
https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_group-concat
https://dev.mysql.com/doc/refman/5.7/en/json-creation-functions.html#function_json-array
VERSION 8:
https://dev.mysql.com/doc/refman/8.0/en/group-by-functions.html#function_group-concat

Search query and ordering by matches with my sql

Hi am currently stuck here, been doing research on how to write a mysql statement for a flexible search for products and order them by relevance on a project am working on have seen a few but wasn't helpful please i need help on how to make it work, my current method doesn't work, here it is.
User types in search field and submits "iPad 3rd Generation".
My script breaks the string into words like so.
$termsExploded = array_unique(explode(' ', $term));
No i use php to create an sql query based on the number of words found.
$i = 0;
foreach ($termsExploded as $word) {
if (strlen($word)>1) {
if ($i == 0) {
$where_query = $where_query." name LIKE '%".$word."%'";
}
else{
$where_query = $where_query." OR name LIKE '%".$word."%'";
}
$i++;
}
}
The where query variable now looks like this.
name Like '%ipad%' Or name Like '%3rd%' Or name Like '%Generation%'
Now search for the products ids like so.
$IDs = "SELECT DISTINCT id FROM store_items WHERE".$where_query;
I now create a second where query based on the IDs returned like so
$where_query_s = null;
$i = 0;
foreach ($IDs as $result) {
$returnID = $result->id;
if ($i == 0) {
$where_query_s = $where_query_s." id = ".$returnID."";
}
else{
$where_query_s = $where_query_s." OR id = ".$returnID."";
}
$i++;
};
Now i select the products again based on the distinct IDs returned like so
$items = "SELECT * FROM store_items WHERE".$where_query_s;
Now this works to get the products but how can i sort it based on best match?
Assuming you want to order by the number of matches then build up another string as follows:-
ORDER BY IF(name Like '%ipad%', 1, 0) + IF(name Like '%3rd%', 1, 0) + IF(name Like '%Generation%', 1, 0) DESC
But this will be slow, and takes no account of indexing to improve performance nor of plural / singular (ie, it someone searches for 'flies' it won't rank 'fly' properly).
To put that more into code:-
$where_query = array();
$order_query = array();
foreach ($termsExploded as $word)
{
if (strlen($word)>1)
{
$where_query[] = " name LIKE '%".$word."%'"
$order_query[] = " IF(name Like '%".$word."%', 1, 0)"
}
}
$IDs = "SELECT DISTINCT id FROM store_items WHERE ".implode(' OR ', $where_query)." ORDER BY ".implode(' + ', $order_query)." DESC";
Arrange for your query to look like this:
select field1, field2, etc, count(*) records
from store_items
where blah blah blah
group by field1, field2, etc
order by records desc
If the table is MyISAM based or if it is InnoDB and the version is Mysql 5.6 or greater, then you can use full text search (see http://dev.mysql.com/doc/refman/5.6/en/fulltext-search.html)
effectively you want a query similar to
SELECT * FROM store_items WHERE MATCH (name) AGAINST ('iPad 3rd Generation')
ORDER BY MATCH (name) AGAINST ('iPad 3rd Generation')

MySQL query to search keywords ordered by relative match

I am creating an online system that matches bank statements (description, value, type, etc) to purchasers (names, addresses) and would like some feedback on the way I am currently doing this:
$array = array("keywords", "taken", "from",
"bank", "statements", "using", "explode",
"function", "using", "a", "space");
$i = 0;
$r = array(); //r = relevant
while($i<count($array)) {
$keyword = $array[$i];
$get = mysql_query("SELECT `id` FROM `users`, `addresses`
LEFT JOIN `users`.`id` = `addresses`.`user`
WHERE (`users`.`frame` LIKE '%$keyword%'
OR `users`.`lname` LIKE '%$keyword%')
OR ((`addresses`.`address` LIKE '%$keyword%'
OR `addresses`.`town` LIKE '%$keyword%')
OR (`addresses`.`county` LIKE '%$keyword%'
OR `postcode`.`town` LIKE '%$keyword%'));");
if(mysql_num_rows($get)) {
while($fetch = mysql_fetch_array($get)) {
list($var) = $fetch;
push_array($r, $var);
}
}
$i++;
}
//count the IDs that match within the relative array to see
//which is most relative to the search
Is there a better way of doing this as well as keeping the execute time to an absolute minimum? The database will be in the 10s of thousands when it's finished.
It would be better to build a keyword table that ties each keyword to a user, e.g.:
keywords (keyword, user) + UNIQUE(keyword, user)
keyword1 12
keyword1 14
keyword2 3
After you populate the keywords table from the data you wish to search on, the query becomes much more optimal:
SELECT users.*
FROM keywords
INNER JOIN users ON users.id = keywords.user
WHERE keyword IN ('keyword1', 'keyword2')
Of course, you need to maintain this table when you make changes to the user or address table (insert, update, delete).

Categories