advanced autocomplete list - php

I created this query to display my auto complete box with jQuery. It is working perfectly.
<?php
require_once('database.php');
if(isset($_POST['queryString'])) {
$queryString = $dbc->real_escape_string($_POST['queryString']);
if(strlen($queryString) >0) {
$q = "SELECT keyword
FROM (
SELECT tname AS keyword FROM t
UNION
SELECT sname AS keyword FROM sub
UNION
SELECT cname AS keyword FROM c
UNION
SELECT iname AS keyword FROM i
) s
WHERE keyword LIKE '%$queryString%'
LIMIT 10";
$r = mysqli_query ( $dbc, $q);
if($q) {
while ($row = mysqli_fetch_array($r, MYSQL_ASSOC)) {
echo '<li onClick="fill(\''.$row['keyword'].'\');">'.$row['keyword'].'</li>';
}
} else {
echo 'ERROR: There was a problem with the query.';
}
} else {
}
} else {
echo 'There should be no direct access to this script!';
}
?>
with this query display auto complete list with subjects, tutor names, cities according the keyword. Now I need to modify auto complete list with more values. For an example there is a tutor name in the list I want to display his/her current city, his/her profile image etc. It is something similar to Facebook search.
this is my city and address tables
# --------------
# Address Table
# --------------
CREATE TABLE address (
address_id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT,
address_one VARCHAR(40) NOT NULL,
address_two VARCHAR(40) DEFAULT NULL,
city_id INT(4) UNSIGNED NOT NULL,
PRIMARY KEY (address_id),
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
# --------------
# City Table
# --------------
CREATE TABLE city(
city_id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT,
city_name VARCHAR(30) NOT NULL,
district_id INT(2) UNSIGNED NOT NULL,
PRIMARY KEY (city_id),
UNIQUE (city_name)
) ENGINE=MyISAM;
How can I do this?

I think there are 2 options.
I believe you should adjust your query, because now you look in the t table and in the sub table checking if the searchword occurs. However, your query is so short that you dont have available the matching profile info, just the column on which you perform the search.
Ofcourse you dont want to query a lot of data from rows that dont even match your criteria. On the other hand, its not so convenient to do a lot of queryies after you performed the search. However, since you have limit to 10, it should be okay.
Change your query to select name, birthday, gender, imgdata from t etc..

Related

Group result in MySQL and show on list

I have a large table:
create table data
(
id bigint unsigned auto_increment primary key,
first varchar(120) null,
last_ varchar(120) null,
country varchar(30) not null
)
collate = utf8mb4_unicode_ci;
I need to display the number of people from individual countries on list.
I a have typical SQL query:
public function getAll(): array
{
$this->db->query('SELECT * FROM data ORDER by id DESC;');
return $this->db->resultSet();
}
but I don't know to how group my results :(
I print my result:
$this->model->getAll()
and then foreach....
In result I need:
1. 10 users from Poland;
2. 101 users from Germany;
3. 99 users from UK....
Please help me
You seem to be looking for simple aggregation:
select country, count(*) no_users from data group by country order by country;
This gives you two columns, with the country and the number of users. You can then generate the proper string output in your application.

proper query in php

I had some help with this code:
SELECT *, IF(newcost - cost > 500, newcost - cost, 0) as raiseby FROM
(
SELECT bp.*, b.company,(IF(bp.cost*1.2 < ls.maximumbid, bp.cost*1.2, bp.cost)) as newcost
FROM `windows_brands_products` bp
LEFT JOIN `windows_brands` b
ON bp.brand_id = b.id
JOIN Windows_last_submissions ls
JOIN windows_materials dm
WHERE ls.username = '$current_user->user_login'
AND bp.width = ROUND(ls.width)
AND bp.height = ROUND(ls.height)
AND bp.material IN (dm.name)
AND bp.type = ls.type
AND IF (ls.minimumbid != '0.00',bp.cost BETWEEN ls.minimumbid AND ls.maximumbid,bp.cost <= ls.maximumbid)
ORDER BY b.company ASC
) as temptable
The goal is to display a line stating that the user missed a (or some) companies by $500 and state how much the user needs to increase their max. bid (ls.maximum) in order to come within parameters of the query. It looks to me like it will look something like:
echo 'If you increase your maximum bid by '.$row->raiseby.',. $row->temptable.'can perform your installation';
I don't seem to get a positive response by using that statement...My assumptions could also be off about the way to reference each "row".
Am I wrong to assume that when you use "AS" parameter in sql the word to the right becomes the new row name?
Anyone have any idea as to how I could word this query to achieve my results?
Thanks
EDIT* I'm having a problem with sqlfiddle showing an error I can't figure out. it states 'incorrect integer value: column 'id' row 1':
CREATE TABLE windows_brands
(
id int(11),
company varchar(255)
);
INSERT INTO windows_brands
VALUES ('1','Anderson');
CREATE TABLE windows_brands_products
(
id int(11) AUTO_INCREMENT,
brand_id int(11),
width decimal(12,2),
height decimal(12,2),
material varchar(30),
type varchar(30),
cost decimal(12,2),
PRIMARY KEY (id)
);
INSERT INTO windows_brands_products
VALUES ('','2','30','36','wood','double hung','1500.00');
CREATE TABLE Windows_submissions
(
id int(11) AUTO_INCREMENT,
name varchar(30),
username varchar(12),
width decimal(12,2),
height decimal(12,2),
chosenmaterial varchar(30),
type varchar(30),
minimumbid decimal(12,2),
maximumbid decimal(12,2),
PRIMARY KEY (id)
);
INSERT INTO Windows_submissions
VALUES ('','Casey','caseys','30','36','wood','double hung','1000.00','1700.00');
CREATE TABLE windows_materials
(
id int(11) AUTO_INCREMENT,
name varchar(30),
PRIMARY KEY (id)
);
INSERT INTO windows_materials
VALUES ('','wood');
Can you see what the problem is - I've been looking it over for a while and can't see it.
This query works fine: http://sqlfiddle.com/#!9/22a74/1
In the query I'm trying to get to work...If, say, I make a maximumbid of $300 (for example) more than what the company charges, I should be able to echo something in a loop like, the nearest company is ____ and is $300 more than your maximumbid. I just don't know how to reference the aliases like 'raiseby' and 'temptable'. If I put that query into sqlfiddle 0 results show...which I want the same results like the company and the newcost to show- but also I want to let the user know how much they missed the target if, say, no results show.

PHP - SQL Join Query

I have this MySQL Structure:
CREATE TABLE Fields (
ID INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
ForUser VARCHAR(255) NOT NULL,
ForCategory VARCHAR(100) NOT NULL,
FieldName VARCHAR(100) NOT NULL
);
CREATE TABLE Content (
ID INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
ForUser VARCHAR(255) NOT NULL,
ForCategory VARCHAR(100) NOT NULL,
ForField VARCHAR(100) NOT NULL,
FieldContent VARCHAR(255) NOT NULL
);
Now I want to make SQL Query that list results in HTML Table. As Head Table I want to list FieldName from Fields, and as Table Body I want to list FieldContent from Content. Also in WHERE clause must be ForUser AND ForCategory... to list Content for each field. I'm tried with SQL Join, but I'm spend 3 hours without success. Can, please, someone write me an example how to display this.
If I understand this request correctly (you're a little light on detail), you will need a use a few components to achieve your goal:
Two sql queries (one for the table header and one for the table body)
Some php or another scripting language to display your results as html.
Your first query will just bring back the field names, filtered by user and category:
select ID, FieldName from Fields where ForUser = 'some_user' and ForCategory = 'some_category' order by ID;
IN your php or other code, you need to iterate through the results and display each result wrapped in the html tags, eg:
echo '<table><tr>';
$fields = # mysql_query ("select ID, FieldName from Fields where ForUser = 'some_user' and ForCategory = 'some_category' order by ID;", $connection);
while ($fields_result = mysql_fetch_assoc($fields)) {
echo '<th>' . $fields_result['FieldName'] . '</th>;
}
echo '</tr>';
Then run a second sql query to bring back the contents:
select
FieldContent
from
Content c join
Fields f on
c.ForField = f.FieldName and
c.ForUser = f.ForUser and
c.ForCategory = f.For Category
where
f.ForUser = 'some_user' and
f.ForCategory = 'some_category'
order by ID;
And in a similar fashion, iterate through the results in php to build the content rows in the table.
Note that I'm ordering on the PK in the Fields table to ensure that the content comes back in the same order as the fields. This approach might not suffice, you may need to add a "sequence" field if you need a specific field order.
Also note my prevous comment that you would do well to revise your database structure. You don't need to repeat all the fields in the Content table, you can just add a foreign key referencing the ID of the Field record
Table join query:
SELECT
a.ID,
a.ForUser,
b.ForUser,
a.ForCategory,
b.ForCategory,
a.FieldName,
b.ForField,
b.FieldContent
FROM
Fields a,
Content b
WHERE
a.ForUser = '' AND b.ForCategory = ''

Query with join 20 times slower than queries in a loop with php and MySQL

I'm trying to make some optimizations in queries of my site. I've allways thought that, it is better to use one query with a "JOIN" than put severals queries in a php loop, but when I do it, it is really slow.
The original method with queries in loop takes 0.055s and the new with "join" takes 1.084s.. Wich solution should I use ? And is there a way to make the new query faster ? Maybe another idea is to create a procedure in mysql with loop ?
Here is the situation : I've a forum, with topics in forum, and messages in topics. And to get the username, I get the id of the user in the msgs table and if this is positive it is a registered user else it's a guest in the guests table. Don't know if this is a good construction, but I can't put guest and registered member in the same table.
CREATE TABLE `topic` (
`id` int(6) NOT NULL AUTO_INCREMENT,
`post_date` int(14) NOT NULL DEFAULT '0',
`last_answere_date` int(14) NOT NULL,
`author_name` varchar(50) NOT NULL DEFAULT '',
`title` varchar(60) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `msgs` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`topic_id` int(10) unsigned NOT NULL DEFAULT '0',
`post_date` int(14) unsigned DEFAULT NULL,
`user_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `topic_id` (`topic_id`),
KEY `user_id` (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`nom` varchar(30) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `guests` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
And My two situations :
//Goal : get the list of 5 new topics or topic with new messages
//Methode query in loop
$timestart=microtime(true);
echo '<h3>Query in loop</h3>';
//Get the list of new topics
$reqTopic = $bdd->query('SELECT id,title,author_name,post_date FROM topic ORDER BY last_answere_date DESC LIMIT 0,5');
While($topic = $reqTopic->fetch())
{
//Get the last message
$reqMsgs = $bdd->prepare('SELECT count(*) as msgCount, user_id,post_date FROM msgs WHERE topic_id=? ORDER BY post_date DESC');
$reqMsgs->bindparam(1,$topic['id'],PDO::PARAM_INT);
$reqMsgs->execute();
$msg = $reqMsgs->fetch();
//IF the id is >0 then it's a registered member, else it's a guest
if($msg['user_id'] > 0)
$reqAuthor = $bdd->prepare('SELECT nom as name FROM users WHERE id=? LIMIT 0,1');
else
$reqAuthor = $bdd->prepare('SELECT name FROM guests WHERE id=? LIMIT 0,1');
$reqAuthor->bindparam(1,$msg['user_id'],PDO::PARAM_INT);
$reqAuthor->execute();
$author = $reqAuthor->fetch();
//Output
echo '<strong>'.$topic['title']. '</strong><br/>'
.'Author : '. $topic['author_name'] . ' | Date : '. date('d/m/Y H:i',$topic['post_date']) .'<br/>';
if($msg['msgCount'] > 0)
{
echo 'Last msg author : '. $author['name'] . ' | Date : '. date('d/m/Y H:i',$msg['post_date']) .'<br/>'
.'Nbr msgs : '.$msg['msgCount'].'<br/>';
}
echo '<br/>';
}
//End of script : get time
$timeend=microtime(true);
$time=$timeend-$timestart;
echo '<strong>'.number_format($time, 10) . ' sec</strong>';
//Methode Left join
$timestart=microtime(true);
echo '<h3>Left Join</h3>';
//The query
$reqTopic = $bdd->query('SELECT t.id,title,t.author_name,t.post_date, m.*, (SELECT COUNT(*) FROM msgs WHERE t.id=topic_id) as msgCount
FROM topic t
LEFT JOIN (
SELECT m.id,topic_id,post_date as mdate,user_id, IFNULL(u.nom,i.name) as name
FROM msgs m
LEFT JOIN users u ON u.id=m.user_id
LEFT JOIN guests i ON i.id=-m.user_id
GROUP BY topic_id
ORDER BY post_date DESC
) m
ON t.id=m.topic_id
GROUP BY t.id
ORDER BY last_answere_date DESC LIMIT 0,5');
While($topic = $reqTopic->fetch())
{
//Output
echo '<strong>'.$topic['title']. '</strong><br/>'
.'Author : '. $topic['author_name'] . ' | Date : '. date('d/m/Y H:i',$topic['post_date']) .'<br/>';
if($topic['msgCount'] > 0)
{
echo 'Last msg author : '. $topic['name'] . ' | Date : '. date('d/m/Y H:i',$topic['mdate']) .'<br/>'
.'Nbr msgs : '.$topic['msgCount'].'<br/>';
}
echo '<br/>';
}
//End of script : get time
$timeend=microtime(true);
$time=$timeend-$timestart;
echo '<strong>'.number_format($time, 10) . ' sec</strong>';
Generally speaking, the optimal approach for this kind of stuff is to proceed in two steps:
Fetch the rows that you need
Fetch data related to those rows
In your case, start by fetching your topics:
SELECT id,title,author_name,post_date
FROM topic
ORDER BY last_answere_date DESC LIMIT 0,5
Using the fetched topic ids, then fetch the related data:
SELECT topic_id, user_id, post_date
FROM msgs
WHERE topic_id IN (…)
ORDER BY topic_id, post_date DESC
SELECT id, nom as name FROM users WHERE id IN (…)
etc.
In your particular case, a correlated subquery can yield the count cheaply, if you really want SQL to return it:
SELECT t.id,title,t.author_name,t.post_date,
(SELECT COUNT(*) FROM msgs WHERE t.id=topic_id) as msgCount
FROM topic t
ORDER BY t.last_answere_date DESC LIMIT 0,5
(In the above, the planner should get the rows first, and then run the subquery once per row.)
The problem with using a left join to retrieve everything in one go like you did is that:
You may needlessly end up joining enormous sets that can result from using a group by statement in a subquery, because the latter can prevent the use of an index;
You may lose the benefit of indexes that might kick in when doing where … order by … limit … due to order by clauses within subqueries that you join on; and
You multiply the times you send the data by the number of related rows — e.g. topic-related data gets sent once per message in your left join query. (This is likely negligible in your particular case, but it may add up in others.)

Display category name from a table

i have two tables in my database. One name jokes and the other named category.
jokes
CREATE TABLE `jokes` (
`joke_id` int(11) NOT NULL AUTO_INCREMENT,
`joke` varchar(1024) NOT NULL,
`category_id` int(11) NOT NULL,
PRIMARY KEY (`joke_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;
category
CREATE TABLE `category` (
`category_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(51) NOT NULL,
PRIMARY KEY (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
and i was wondering what the query would be to find the category name of a joke so it can be displayed on the home page like title:"Celebrity Joke" joke:"Miley Cyrus is a joke" and so on..
Would anybody be able to help me out on this problem, im guessing it will be a query/string assigned to a variable named $category_name which will reference both tables, but again, im not too sure how to go about it.
Try this first joining two tables:
SELECT
* //You can filter more your columns here
FROM
jokes
LEFT JOIN category ON
jokes.category_id = category.category_id
Now after this statement you can add a WHERE CLAUSE and it could be something like this
WHERE category.category_name like '%Miley%'
Means you will retrieve records having a category that has name of Miley
If you were going to do this with all jokes/categories it would look like:
SELECT * FROM jokes UNION SELECT * FROM category
However if you wanted to do a single joke you could just use the answer posted by Drixson. IF you wanted all the jokes from one category you would do:
SELECT * FROM jokes WHERE category_id=CATEGORY_ID
Some PHP you could use to display jokes from each category:
//Cat ID, using 1 for example
$category = 1
//Query
$query = "SELECT * FROM jokes WHERE category_ID=:cat";
//Establish PDO, prepare, apply parameter, execute, fetch data
$search = new PDO("mysql:host=HOST;dbname=DB",USERNAME, PASSWORD);
$runQuery = $search->prepare($query);
$search->bindParam(':cat', $category, PDO::PARAM_INT);
$search->execute();
$results = $search->fetchAll();
//For every row display joke_id and the joke
foreach($results as $joke){
echo $jokes["joke_id"] . " - " . $jokes["joke"];
}
//Kill
$results = null;
Hope it helps. PDO is pretty easy to pick up so if you need anymore help just search for a PDO tutorial on Google.

Categories