I'm working on a advanced search functionality with php and mysql.
The tables are:
blogPost[id, title, description]
water[id, title, description,]
waterSpecie[id, waterId, specieId]
specie[id, name]
user[id, username]
What I want done is this:
The user will be able to search from a text field with a keyword, and the results should only be unique once.
For example:
The user searches for cod then I would like to show all the blogposts that has cod in there titles or description and all the waters that has cods in it and also if a user is nicked cod. But if let's say the blogPost has cod in its title and description I don't want it to show up twice in the results list.
But if only lets say the blogPost table has cod in its title I would only want to show that and nothing else.
I've managed to do it with this sql query: I would now like to add the blogPost table to that query and make it possible to search from it. So if only one table have cod I want to show only the result from that table.
SELECT DISTINCT W.lat, W.lng, W.municipalityId, W.title, W.description
FROM water AS W, specie AS S, waterSpecie AS WS
WHERE S.name LIKE '%$term%' AND W.id = WS.waterId AND S.id = WS.specieId
OR W.title LIKE '%$term%' AND W.id = WS.waterId AND S.id = WS.specieId;
I hope I've managed to explain my problem and hopefully I could get some help on this issue.
You might try this:
Select distinct tablename,id from
(select 'blogpost', as tablename, id, title as searchfield from blogpost
union
select 'blogpost' as tablename, id, description as searchfield from blogpost
union
select 'water' as tablename, id, description as searchfield from water
union
select 'specie' as tablename, id, name as searchfield from specie
union
select 'user' as tablename, id, username as searchfield from user) searcher
where searcher.searchfield='cod'
I don't exactly get what's going on with waterSpecie, so I've left it out.
You should get results something like:
tablename id
blogpost 5
user 12
And then you can query the database to get the record from blogpost with id=5, and the record from user with id=12.
You'll be able to do this programmatically in your PHP. And if you add a table that you want to add to the search functionality, you only have to do it by adding a UNION in the query below, rather than making a join and adding another piece to a WHERE clause.
I'm not sure that this would scale to Amazon.com size, so consult somebody better than me before you get that big.
You will be best served by simplifying your MySQL queries and combining results in your PHP code. The main reason for this in your case is that you want to combine dissimilar results - blog entries if they have the search term and/or waters and other things if they have the search terms.
In pseudo code, I'd do something like this (use a DAO in the real code, of course):
$foundposts = findblogposts($searchterm);
$foundusers = findusers($searchterm);
$foundwaters = findwaters($searchterm);
// etc
if($foundposts){
print($foundposts);
}
if($founduers){
print($foundusers);
}
if($foundwaters){
print($foundwaters);
}
// etc
That way, you can handle the different formatting requirements you probably have to show blog posts correctly, and users correctly, etc.
Related
I have 3 tables;
projects, campaigns, clients.
I need to return results from all 3 tables where the searchterm matches. However, I need to check against 'name' column in projects and campaigns tables, but 'description' column in the clients table. NB This is an existing client database, I have no authority to change the the column names.
Example: user searches for 'data', I need to SELECT:
name as title FROM projects WHERE name LIKE %data%,
name as title FROM campaigns WHERE name LIKE %data%
AND
description as title FROM clients WHERE description LIKE %data%
I'm struggling to combine the queries. Below is what I have so far, which returns a syntax error. I am also thinking I may be taking the wrong approach.
SELECT
p.name,
c.name,
cl.description AS title
FROM
projects,
campaigns,
clients
WHERE
p.name LIKE % DATA %
OR c.name LIKE % DATA %
OR cl.description LIKE % DATA %
You are looking for union all:
SELECT name as title FROM projects WHERE name LIKE %data%,
UNION ALL
SELECT name as title FROM campaigns WHERE name LIKE %data%
UNION ALL
SELECT description as title FROM clients WHERE description LIKE %data%;
If you want to remove duplicates, then use UNION instead of UNION ALL.
I have a textbox (for which I used jQuery auto-completion) in my PHP form where user can insert an actor/actress name and then by clicking "Search" button, a new window is opened showing list of movies by that actor/actress.
This is a query where I get movies by actor name:
$query = $conn->prepare("SELECT DISTINCT c.movieName, c.castName, c.movieImdbId, f.year, f.posterLink FROM cast_movie as c JOIN film_info as f ON c.ImdbId = f.ImdbId WHERE c.castName = :q");
$query->execute(array(':q' => $searchText ));
My question:
The above query works fine if user select a name from auto-completion list. However I would like to enable user to write any name (even if he couldn't find from auto-completion list). For example, If user write "tom" in the textbox, and click on "search" button, I want to show list of all movies by all actors that their name containing word "tom".
For this purpose, I used LIKE :q and ':q' => '%' . $searchText . '%' in the above query, but the query never ends!!(I think because cast_movie is a VIEW which is quite large (with 3 million rows) and joining this view with the other table takes a very long time (actually I waited for 10 minutes and it didn't finished yet).
Could someone kindly let me know if there is any way to fix this? (I read we can use index for joining very large tables, but I think it's not possible to define index for cast_movie since it is VIEW.)
UPDATE:
Regarding comments, in order to provide more information:
cast_movie is a view which is made by joining "movie_roleNames" and "movies".
movie_roleNames is also a view which is made by joining two tables "Cast" and "nameRoles".
film_info is also a view that is made by joining two tables "movies" and "movies_info".
The structure of the above tables:
table "movies": Id, movieName, ImdbId(unique Id of movies), Rate, numVotes, year (indexes: ImdbId, movieName, year)
table "cast": castName, castImdbID (unique Id of casts) (indexes: castName, castImdbID)
table "nameRoles": Id, castImdbId, movieImdbId, role_Id, (indexes: movieImdbId, castImdbId)
VIEW "movie_roleNames": Id, castName, castImdbId, movieImdbId and the join statement was: SELECT n.Id, c.castName, n.castImdbId, n.movieImdbId
FROM nameRoles as n
join Cast as c
ON n.castImdbId = c.castImdbID
VIEW "cast_movie": Id, castName, castImdbId, movieImdbId, movieName and the join statement was: SELECT m.Id, r.castName, r.castImdbId, r.movieImdbId, m.movieName
FROM movie_roleNames AS r
JOIN movies AS m
ON r.movieImdbId = m.ImdbId
All ideas are highly appreciated,
First of all, I'd just want to say that I'm sorry for the poor title. I'm really struggling with explaining the problem I'm facing in just a short sentence.
I have a table called actors which contains an aID (primary key) and an aName and some more stuff. I also have a table called videos which contains vID (primary key) and other data. The third and last table I have is called connections and that one contains a primary key, a cVideoID and a cActorID.
Let's say I have created a video and when I navigate to the video *www.example.com/video.php?v=primary_key* I'd like to print out all actors who are in that movie (actor1, actor2, actor3 and actor4). Therefor I created the connections-table to keep track of all movie-actor connections. For every movie I create I connect the actors with the movie.
I thought that I could do something like this:
<?php
$result2 = mysql_query("SELECT `actors`.`aID`, `actors`.`aName` FROM `actors` WHERE `connections`.`cVideoID` = {$_get['v']}");
while($actors = mysql_fetch_array($result2))
{
echo "<a href='actor.php?id={$actors['aID']}>{$actors['aName']}</a> ';
}
?>
But it seems like that's not working. Any ideas?
What you want to do, is select all of the entries from connections, where the video ID is the selected video. Then, you JOIN on the actors table, to get all of the information about the actors that were found.
Example: Get all of the actor's names for a specific video ID:
SELECT a.aName
FROM connections c
LEFT JOIN actors a
ON a.aID = c.aID
WHERE c.vID = 1;
SQL Fiddle
What you need here is a join.
A normal left join works like this:
LEFT JOIN [name of table] [name of table you will want to use]
ON ([where statements searching for the right columns to join])
So your query will look something like this:
SELECT a.aID, a.aName
FROM `connections` c
LEFT JOIN `author` a ON (c.cActorID=a.aID)
WHERE c.cVideoID=[id of the video]
Now first of all you say the database you want to catch the columns aID and aName from the table a next you use the FROM statement to "import" the connections table as "c". You then load the author table and make it accessible as "a" (see the select statement a.[...]) and you also say that it should join the two tables ON every c.cActorID=a.aID and in the end you make a where statement to declare you are only searching for videos with the c.cVideoId=[id]
i have a pictures table : pictures(articleid,pictureurl)
And an articles table : articles(id,title,category)
So, briefly, every article has a picture, and i link pictures with article using articleid column. now i want to select 5 pictures of articles in politic category.
i think that can be done using IN but i can't figure out how to do it.
Note: Please only one query, because i can do it by selecting articles firstly then getting the pictures.
Thanks
To get five pictures from articles in a category you could do this:
SELECT pictures.pictureurl
FROM articles, pictures
WHERE articles.id = pictures.articleid AND articles.category = 'politic'
ORDER BY [your sort criteria]
LIMIT 5;
You could consider rephrasing the question a bit.
If you are looking for an IN query instead of a JOIN this is an alternative to Alex's query:
SELECT pictureurl
FROM pictures
WHERE arcticleid IN (SELECT id FROM articles WHERE category='politic')
LIMIT 5
Rewritten for clarification (see comments):
If you like to keep your JOIN criteria separated from your SELECT criteria, you can write something like the below:
SELECT pictureurl
FROM pictures
JOIN articles ON id = articleid
WHERE category LIKE 'politics'
ORDER BY RAND()
LIMIT 5
I find the intent slightly clear when it's written like that, and maybe it's just me, but I have encountered complex queries written in the SELECT * FROM a, b, c form that worked under MySQL 4 which choke MySQL 5, whereas the above format works fine with both.
Also, if you use uniform ID column names for conformity, and to avoid confusing yourself in more complex scenarios, you can use the USING clause instead. So if articles ID column is also named articlesid, the JOIN could be written like so:
SELECT pictureurl
FROM pictures
JOIN articles USING (articleid)
...
You don't really need to use IN for this. IN serves when you nest queries or when you have a known set of values to check against.
To select 5 random images in the politics category:
SELECT pictureurl FROM articles, pictures WHERE pictures.articleid = articles.id AND articles.category = 'politics' ORDER BY RAND() LIMIT 5
I have multiple tables with Customer data (ex Customer Name, Customer Contact Name, Customer Service Item etc).
I need to enable search on these multiple columns across tables. Then I have to use the search result to pull Customer information (I need Customer ID, or Customer Name).
What is the best way to do this?
Possible Solutions:
Offer multiple filters (different search boxes), and then handle each result separately. (The client does not prefer this, and wants it in a single box.)
Create a temp table (CustomerID, Search Field Values).
Create index !?
User inner join, and put logic into handling the search result!!!!
Thanks.
try something like:
SELECT
c.*
FROM CustomerTable c
INNER JOIN (SELECT
CustomerID
FROM Table1
WHERE columnA =filter1
UNION
SELECT
CustomerID
FROM Table2
WHERE columnB =filter2
UNION
SELECT
CustomerID
FROM Table3
WHERE columnC =filter3
) dt ON c.CustomerID=dt.CustomerID
http://dev.mysql.com/doc/refman/5.1/en/fulltext-search.html
I do believe this similar to Oracle Text Search etc which is used in Oracle applications to allow more intelligent searches, "google-likish".
So it is a fulltext index which is to be created.
Doing it with inner joins (or worse, copying stuff around in temporary tables) might work but the code will be complex and you might kill performance.
the only thing you can do if he customer insists on making a search that works like this is to create a TEXT column, FULLTEXT index it, and concatenate all of the columns you want to search in to this column. if you do this, i suggest that you write your queries in this form to guarantee correct matches while maintining a sort orderthat makes sense:
select *
from sometable
where match(search_column) against('$search_terms' in boolean mode)
order
by match(search_column) against('$search_terms')