PHP MYSQL search same keyword with multiple tables - php

I'm try to create a query which will search four different tables with one keyword to bring all the items which are list under that location.
I have four tables
- Country
- State
- County
- City
for e.g. UK -> England -> West Midlands -> Birmingham
When user types in west Midlands i wont to see all the items including items under birmingham, Walsall, wolverhampton
This what I came up with
$location = $_POST['location'];
$city_sql = " SELECT * FROM city";
$city_result = $db->query( $city_sql );
$new_array=array();
$i=0;
while ($fetch_sql = $db->fetch_object($city_result) ){
if ( strcmp(soundex(strtolower($fetch_sql->name)), soundex(strtolower($location))) == 0 ) {
$new_array[$i]['name'] = $fetch_sql->name;
$new_array[$i]['code'] = $fetch_sql->name;
$i++;
}
}
$k=0;
for ( $j=0; $j < sizeof($new_array); $j++ ){
$i = similar_text(strtolower($new_array[$j]['name']), strtolower($db->escape_value($location)), &$similarity_pst);
if( $i > $k && $i > 7 ){
$k = $i;
$city_db_name = $new_array[$j]['name'];
$city_code = $new_array[$j]['code'];
}
}
Please let me know if you have any idea.
PHP MYSQL search same keyword with multiple tables

You should use SQL features to get your data, not PHP's.
If I correctly understood, you want to get data from several tables and several columns.
Change your query like that:
SELECT
-- list of considered columns
col1,
col2,
col3
-- ...
FROM
City
JOIN
State ON State.state_id = City.state_id
JOIN
Country ON Country.country_id = State.country_id
WHERE
col1 LIKE '%keyword%'
OR col2 LIKE '%keyword%'
OR col3 LIKE '%keyword%'
-- ...
Like that, you will get columns you need containing your keyword. For example, if the table City contains {'Paris', 'paramatta', 'Porto'}, using the keyword Par, and the query SELECT name FROM city WHERE name LIKE '%Par%' will return you { 'Paris', 'paramatta' }
By the way, the link between countries, cities, etc. should be represented backward in your database: Country <- State <- City

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 :)

Two SELECT inside NOT IN echo array() mysql php, one SELECT IS OK

my code is OK only if I remove one (SELECT) inside the NOT IN, if I add two (SELECT) inside the NOT IN, it echo array(); First, I want to get the fruit that val=those value and mark = 'major'. Then I want to remove any of those fruit that either the mark='age' or mark='ripe', so I used OR fruit NOT IN. I already check the SELECT inside the NOT IN, it is OK when they are alone.
<?php
$dia = $wpdb->get_results( $wpdb->prepare("
SELECT fruit FROM table WHERE val IN (%s,%s,%s) AND mark = 'major' OR fruit NOT IN (
(SELECT fruit FROM table WHERE cat='uncommon' AND val = %s AND mark='age'),
(SELECT fruit FROM table WHERE cat='uncommon' AND val = %s AND mark='ripe')) GROUP BY fruit
",$sym1,$sym2,$sym3,$age,$ripe));
?>
You don't need two queries for this, you just need to alter your conditions. Change:
(SELECT fruit FROM table WHERE cat='uncommon' AND val = %s AND mark='age')
To:
(SELECT fruit FROM table WHERE cat='uncommon' AND (val = %s AND mark='age') OR (val = %s AND mark='ripe'))
Otherwise you'd need an aggregate query.

Creating dataset for network graph using data from database

I get data from my database and loop through it and compare employees of one company with employees of other companies to create an array of nodes and egdes. Nodes being companies and edges being employees working for both companies.
Comparing so many variables seems to be slowing the process a lot and is really inefficient so I am looking for a better way of achieving said array/json object.
Here is how the database looks like http://imgur.com/8iVJfwW
The final json object for d3 should look like:
{"nodes":[{"fullName":"Anglo American plc"},{"fullName":"Associated British Foods plc"},{"fullName":"ARM Holdings plc"},{"fullName":"Dixons Carphone plc"},{"fullName":"Diageo plc"},{"fullName":"Direct Line Insurance Group PLC"},{"fullName":"easyJet plc"},{"fullName":"GKN plc"},{"fullName":"Hammerson plc"},{"fullName":"International Consolidated Airlines Group, S.A."},{"fullName":"Imperial Brands PLC"},{"fullName":"intu properties plc"},{"fullName":"Intertek Group plc"},{"fullName":"ITV plc"},{"fullName":"Johnson Matthey Plc"},{"fullName":"Kingfisher plc"},{"fullName":"Lloyds Banking Group plc"},{"fullName":"Mediclinic International plc"},{"fullName":"Merlin Entertainments plc"},{"fullName":"National Grid plc"},{"fullName":"Next Plc"},{"fullName":"Provident Financial plc"},{"fullName":"Pearson plc"},{"fullName":"Reckitt Benckiser Group plc"},{"fullName":"Royal Dutch Shell plc"},{"fullName":"RELX PLC"},{"fullName":"Rio Tinto plc"},{"fullName":"RSA Insurance Group plc"},{"fullName":"SABMiller plc"},{"fullName":"J Sainsbury plc"},{"fullName":"Sky plc"},{"fullName":"Standard Life plc"},{"fullName":"SSE plc"},{"fullName":"Severn Trent Plc"},{"fullName":"Travis Perkins plc"},{"fullName":"Tesco PLC"},{"fullName":"Taylor Wimpey plc"},{"fullName":"United Utilities Group PLC"},{"fullName":"Worldpay Group plc"},{"fullName":"Whitbread PLC"}],"edges":[{"source":0,"target":12,"officers":["PARKER, Thomas, Sir"]},{"source":0,"target":19,"officers":["STEVENS, Anne"]},{"source":0,"target":47,"officers":["GROTE, Byron"]},{"source":1,"target":14,"officers":["BASON, John"]},{"source":2,"target":13,"officers":["PUSEY, Stephen"]},{"source":2,"target":51,"officers":["KENNEDY, Christopher"]},{"source":3,"target":7,"officers":["BARKER, Glyn"]},{"source":3,"target":13,"officers":["WHEWAY, Jonathan"]},{"source":4,"target":9,"officers":["REYNOLDS, Paula"]}]};
What I am doing is executing this query:
SELECT
CD.Company_ID,
CD.Company_Name,
OD.Officer_Name,
CO.Officer_Role
FROM
Company_Details CD
INNER JOIN Company_Officer CO
ON CD.Company_ID = CO.Company_ID
INNER JOIN Officer_Details OD
ON CO.Officer_ID = OD.Officer_ID
WHERE CD.Company_Index='FTSE 100' AND
CO.Resigned_On='' AND
CO.Officer_ID IN
( SELECT CO2.officer_id
FROM Company_Officer CO2
INNER JOIN Company_Details CD2
ON CO2.Company_ID = CD2.Company_ID
WHERE CO2.Resigned_On='' AND CD2.Company_Index ='FTSE 100'
GROUP BY CO2.officer_id
HAVING Count( DISTINCT CO2.company_id ) > 1
)
ORDER BY `CD`.`Company_ID` ASC;
Which gives me names of officers and companies, only officers that work for more than 1 company (to create edges) and only officers that have not resigned.
First I create $nodes by looping through the query and getting only unique companies.
while($row = mysqli_fetch_array($data)){
array_push($Officers_DB,array("name"=>$row['Officer_Name'], "company"=>$row['Company_Name']));
if(!valueExists($nodes, 'fullName', $row['Company_Name'])){ //Get rid of duplicates
array_push($nodes, array("fullName"=>$row['Company_Name']));
}
}
Then I create $edges by comparing each company with every other company from my $nodes array then I check if I am not comparing the same companies after that I loop through all officers from query and compare them with all other officers from query again I check if this isn't the same officer and then I check if officer from first loop works for $i company and in the next loop if officer works for '$j' company so if there is a person with the same name working for 2 different companies I create edge in $edges.
$edges = array();
for ($i = 0; $i < count($nodes); $i++) {
for ($j = $i + 1; $j < count($nodes); $j++) {
if ($nodes[$i]['fullName'] != $nodes[$j]['fullName']) {
foreach($Officers_DB as $Officer){
if($Officer['company']==$nodes[$i]['fullName']){
foreach($Officers_DB as $Officer2){
if($Officer2['company']==$nodes[$j]['fullName']){
if($Officer['name']==$Officer2['name']){
array_push($edges, array("source"=>$i, "target"=>$j, "officers"=>array($Officer['name'])));
}
}
}
}
}
}
}
}
foreach ($edges as $i => &$edge) {
for ($j = $i + 1; $j < count($edges); $j++) {
if ($edge['source'] == $edges[$j]['source'] && $edge['target'] == $edges[$j]['target']) {
foreach ($edges[$j]['officers'] as $officer) {
array_push($edge['officers'], $officer);
}
array_splice($edges, $j, 1);
}
}
}
This method works but is really slow and inefficient and I was wondering of other ways of achieving the same result.
Here is how the database looks like Company_details: http://i.imgur.com/bzDBIPI.png companies are unique
Officer_details: http://i.imgur.com/xce9DW5.png officers are unique
and Company_Officer: http://i.imgur.com/SNYOx0i.png which is the relational table between the other two. With relation one to many and many to one.

Report generation based from mysql query

I have this 3 tables namely form, form_responses, metrics with the following structure
form
->id
->phone
->calldatetime
form_reponses
->id
->form_id
->metrics_id
->response
metrics
->id
->description
->question
And I want to make report with a format something like this
|Metrics Description|Metrics Question|Phone1|Phone2|Phone3|Phone4
|___________________|________________|______|______|______|______
| Sample | Sample | Yes | Yes | Yes | Yes
Is it possbile to this output just by the mysql query alone? Please note that the Phone1, Phone2, Phone3... is scaling horizontally. Originally I need that output in the excel file I have already tried this using Laravel PHP and http://www.maatwebsite.nl/laravel-excel/docs
$query = "SELECT id, phone FROM qcv.forms WHERE calldatetime >= '$from' AND calldatetime <= '$to' ORDER BY id ASC LIMIT 250 ;";
$phone = DB::connection('mysql')->select($query);
$metrics = Metric::all();
$metric_start = 10;
$start = "D";
$count = 10;
foreach ($phone as $key => $value2) // Populate Phone Numbers Horizontally
{
$sheet->cell($start.'9', $value2->phone);
// This will fill the responses for each number
foreach ($metrics as $key => $value)
{
$responses = FormResponses::where('form_id', '=', $value2->id)->where('metrics_id', '=', $value->id)->get();
$sheet->cell($start.$count, $responses[0]->response);
$count++;
}
$start++;
$count = 10;
}
foreach ($metrics as $key => $value) // Populate Metrics Vertically
{
$sheet->cell('C'.$metric_start, $value->question);
$sheet->cell('B'.$metric_start, $value->description);
$sheet->cell('A'.$metric_start, $value->metrics_name);
$metric_start++;
}
But seems this method is really slow especially in processing so I'm wondering if I could do the output in mysql command alone?
To get multiple sub-records per row in a one-to-many relationship using SQL, you would have to use a sub-query:
SELECT
m.description,
m.question,
(select phone from form f1 where f1.id = m.id and ...
/* some other unique criteria */) as Phone1,
(select phone from form f2 where f2.id = m.id and ...
/* some other unique criteria */) as Phone2,
(select phone from form f3 where f3.id = m.id and ...
/* some other unique criteria */) as Phone3,
(select phone from form f4 where f4.id = m.id and ...
/* some other unique criteria */) as Phone4
FROM metrics m
However...you may not have any columns to uniquely identify each form in this way...and your SQL engine may not allow a 3rd level of nesting of sub-queries (which is another way to individually select records from the same table).
So here's one other variation that would work. It should be slightly less code and fewer database connections, so it should perform better, even if you find it less intuitive. Here's the SQL portion:
SELECT
m.description,
m.question,
f.phone
FROM metrics m
INNER JOIN form f ON f.id = m.id
And then in PHP:
$lastid = '';
$phone_count = 0;
foreach ($record as $key => $value) {
$phone[$phone_count] = $value->phone;
$phone_count++;
if ($lastid != $value->id) {
// new record
$sheet->cell ( /* whatever */ );
$phone_count = 0;
}
$lastid = $value->id;
}

How can I insert into a table only when certain field values are not the same?

So, for sake of simplicity, let's say I've got a table like this (f1,f2,f3 are fields):
f1 f2 f3
a b c
d e f
And say I've got a PHP array like this I want to add in to the table:
a g h
Now, I want to be able to add this one in, but I don't want to be able to add something like this:
a e f
Field f1 can have duplicates. Fields f2 & f3 cannot. I've tried adding a unique index to f2, and used REPLACE INTO, but it's not what I want. I need there to be a way to only insert if the f2 & f3 field entries are not already found on the same row in the database table.
$query = "REPLACE INTO table1 (title, description, start, end, location, affiliation)
VALUES ('{$my_title_php_array[$count]}',
'{$my_description_php_array[$count]}',
'{$my_start_php_array[$count]}',
'{$my_end_php_array[$count]}',
'{$my_location_php_array[$count]}',
'{$my_affiliation_php_array[$count]}')”;
description is of data type 'TEXT', which can't be used as an INDEX (too big). Ideally, I'd like to have all be necessarily checked in comparison with the incoming PHP array entries.
Let's say I have these things in my new example's PHP array:
Title1 Desc1 1:00pm 2:00pm Loc1 Aff1
Title1 Desc1 3:00pm 4:00pm Loc1 Aff1
Title2 Desc2 1:00pm 2:00pm Loc2 Aff2
Title2 Desc1 1:00pm 2:00pm Loc3 Aff3
These should all be considered unique and entered in. I'd like to be able to enter them only when they don't exactly match a row in my database already. Desc1 is long. The descriptions are usually the most unique. Is there a way of shortening?
I had to look up this information myself recently and here is the answer I found:
Use multiple columns as unique identifier for mysql
I believe it's what you're needing.
Globally, you want a constraint on a pair of entry? In MySQL, I think you can't. Just, do a select (something like SELECT COUNT(*) FROM _table WHERE f1 = ? AND f2 = ? replace with your values) check the result.
I personally would use PHP and mysql to check the database table for existing rows for "f2" and "f3".
For sake of simplicity, I will use standard mysql and will assume the table name is "alphabet". Example:
$array = array('a', 'e', 'f');
$checkTable = mysql_query("SELECT * FROM `alphabet` WHERE `f2` = '".$array[1]."' OR `f3` = '".$array[2]."'");
if(!mysql_num_rows($checkTable)){
mysql_query("INSERT INTO `alphabet` VALUES('".$array[0]."', '".$array[1]."', '".$array[2]."')");
}
Something like the above. Lets go through it together.
We first set the array containing the letters "a", "e", and "f".
$array[0] = "a", $array[1] = "e", and $array[2] = "f".
We check in the database for any rows where the field "f2" or "f3" is equal to the second and third parameter of our array.
Using mysql_num_rows() if there is no duplicates it will go ahead and add the array into the database table "alphabet".
Correct me if I am wrong or if anybody has a simpler solution. Hope I helped.
<?php
$data[] = 'f1 value';
$data[] = 'f2 value';
$data[] = 'f3 value';
for ($i = 0; $i < count($data); $i++) {
for ($j = $i+1; $j < count($data); $j++) {
$value_a = $data[$i];
$value_b = $data[$j];
$query = "SELECT *FROM mytable WHERE ";
$query.= "(f1=".$value_a." AND f2=".$value_b.") OR";
$query.= "(f1=".$value_a." AND f3=".$value_b.") OR";
$query.= "(f2=".$value_a." AND f3=".$value_b.")";
$result = mysql_query($query);
if (mysql_num_rows($result)) {
//duplicated
}
}
}
?>

Categories