SQL Match Against or Some other method to search two tables - mysql

I've look at the questions on here but can't find an answer that specifically matches what i'm trying to achieve...
Basically I have an SQL table that stores FAQ information. The table in question are below with the primary keys in bold.
Table: questions,
Fields: id_question, question, answer, status, etc......
Table: question_tags,
Fields: id_question, tag
Table: tags,
Fields: tags
The question_tags table is essentially a link between the question table and the tag table (i.e. many to many).
What I am looking to do is implement something like SQL MATCH AGAINST so when a user enters a question into the search box (PHP) the system looks up the questions table and searches the questions for the keywords in the search term. I can get this to work but what I want to be able to do is include the tags within the search. The reason for this is that I believe there are a number of different ways the same question can be using different words. The tags are supposed to compliment the question when searching. I understand that this is impossible using the MATCH AGAINST function within SQL so i'm kind of stuck.
Is there a way around this limitation?
Or instead of having each tag in a separate column of a separate table (linked with a third table) as above, should I simply create another field in the questions table for the entire tag string?
Or does anyone else have any other suggestions?
The solution will not be working with large datasets to begin with but it would be helpful if the solution was scalable.
Thanks

Tags may be a good candidate for de-normalization for this use case.
One possibility would be something like
SELECT * FROM
(
SELECT Question, Answer, Status, MATCH(title,category) AGAINST ('keyword') as rank
FROM questions
WHERE MATCH(Question,Answer) AGAINST ('Keyword')
UNION
SELECT Question, Answer, Status, MATCH(Tag) AGAINST ('keyword')
FROM questions Q
INNER JOIN question_tags QT
ON Q.id_question = QT.id_question
INNER JOIN tags T
ON QT.id_tag = T.id_tag
WHERE MATCH(Tag) AGAINST ('keyword')
) R
ORDER BY rank
Basically doing a FT search against question/answer and another on tags and unioning the resultset and then sorting by rank.

Related

Finding rows in MySQL Table that do NOT have certain text

Suppose I want to find an article in a database table that includes the text "There were many bison" With phpMyAdmin, I can navigate to Search, choose a field, then choose Like %...%, and it will select the article that includes those words.
I'd like to know if there's a way to find all rows that do NOT include that string.
Let me explain my bigger goal. I'm working on articles about many animal species that are divided into sections on Classification, Distribution, Ecology, etc. Each section can be thought of as an independent article, and I was tempted to make unique tables for each of these sections. However, that would be a logistical nightmare; I'd need literally hundreds of tables.
So I just write one long article with each section beginning with something like this:
So if I have articles about 600 species in my database table, and I want to know which articles DO NOT include an Ecology section, I can simply search for all the rows that do not have that particular div, or something similar (e.g [h2]Ecology[/h2] - though with real tags, not brackets).
Is there a way to do that with phpMyAdmin, MySQL Workbench (which I downloaded and installed just today) or some other tool?
Thanks.
you could use a NOT REGEX http://dev.mysql.com/doc/refman/5.1/en/regexp.html with SQL.
one solution would be to create a categories table on your database and then assign each article a category. That way you could create a query to select all the articles that have the specific category that you want.
example would be :
table articles:
-article_id (primary Key)
-article
-category_cat_id (foreign Key that references cat_id)
table category
- cat_id (primary Key)
-cat_name
a query to select all the articles with the categry of lets say ecology:
SELECT * FROM articles
LEFT JOIN category
ON articles.category_cat_id = category.cat_id
WHERE cat_name != 'ecology'(if you want to select all the articles except those with a ecology cateogry)
another alternative is
WHERE cat_name = 'ecology'( if you want to select all posts with the category of ecology)

How to represent Cross Apply and Split String in MySQL

For some background, what i'm trying to do create a database that contains multiple recipes. However, it's necessary for the individual ingredients to be linked to the recipe they originally came from.
For instance, I have table containing all the individual ingredients.
And a table where the recipes are stored, minus the ingredients.
Now, i've found this article which covers how to split strings using T-SQL XML Commands, and the code that is used to do so is:
SELECT
Books.BookId,
Books.Book,
BookAuthors.AuthorId,
BookAuthors.Author
FROM Books
CROSS APPLY dbo.split(Books.Authors,',') split
INNER JOIN BookAuthors ON BookAuthors.AuthorId = split.val
The result i'm looking for would be very similar to this:
However, CROSS APPLY etc only works on MS SQL Server and my question is:
Is it possible to achieve the same, or very similar effect using MySQL?
Thanks for any help.
This should quite match what you're trying to get:
SELECT
Books.BookId,
Books.Book,
BookAuthors.AuthorId,
BookAuthors.Author
FROM Books
LEFT JOIN BookAuthors ON (find_in_set(BookAuthors.AuthorId, Books.Authors) <> 0)
Found this article very helpful: MySQL query finding values in a comma separated string
Leave a comment if you need further explanation how it works.

Store Voting Information - Database Outline

Summary: What is the most efficient way to store information similar to the like system on FB. Aka, a tally of likes is kept, the person who like it is kept etc.
It needs to be associated with a user id so as to know who liked it. The issue is, do you have a column that has a comma delimited list of the id of things that were liked, or do you have a separate column for each like (way too many columns). The info that's stored would be a boolean value (1/0) but needs to be associated with the user as well as the "page" that was liked.
My thought was this:
Column name = likes eg.:
1,2,3,4,5
Aka, the user has "like" the pages that have an id of 1, 2, 3, 4 and 5. To calculate total "likes" a tally would need to be taken and then stored in a database associated with the pages themselves (table already exists).
That seems the best way to me but is there a better option that anyone can think of?
P.S. I'm not doing FB likes but it's the easiest explanation.
EDIT: Similar idea to the plus/neg here on stackoverflow.
In this case the best way would be to create a new table to keep track of the likes. So supposing you have table posts, which has a column post_id which contains all the posts (on which the users can vote). And you have another table users with a column user_id, which contains all the users.
You should create a table likes which has at least two columns, something like like_postid and like_userid. Now, everytime a user likes a post create a new row in this table with the id of the post (the value of post_id from posts) that is liked and the id of the user (the value of user_id from users) that likes the post. Of course you can enter some more columns in the likes table (for instance to keep track of when a like is created).
What you have here is called a many-to-many relationship. Google it to get some more information about it and to find some more advice on how to implement them correctly (you will find that a comma seperated lists of id's will not be one of the best practices).
Update based on comments:
If I'm correct; you want to get a list of all users (ordered by name) who have voted on an artist. You should do that something like:
SELECT Artists.Name, User.Name
FROM Artists
JOIN Votes
ON Votes.page_ID = Artists.ID
JOIN Users
ON Votes.Votes_Userid = Users.User_ID
WHERE Artists.Name = "dfgdfg"
ORDER BY Users.Users_Name
There a strange thing here; the column in your Votes table which contains the artist id seems to be called page_ID. Also you're a bit inconsistent in column names (not really bad, but something to keep in mind if you want to be able to understand your code after leaving it alone for 6 months). In your comment you say that you only make one join, but you actually do two joins. If you specify two table names (like you do: JOIN Users, Votes SQL actually joins these two tables.
Based on the query you posted in the comments I can tell you haven't got much experience using joins. I suggest you read up on how to use them, it will really improve your ability to write good code.

mysql group by comma separated values

I have a mysql table comments in that table a field is tags and all tags are comma separated like
Comments Table
Name Reply Tags
a b new,old,facebook,fb
b d water,faebook,wall
b r wall,php,fb
c q name,facebook,email
a y weather,cold,old
a w twitter,next,pet,fb
I need to get most used tag in this table with mysql query..
I think that the best approach is to use a separate table for Tags and for the relation between Tags and your table (i.e.: CommentTags), it'll allow you to quickly find those comments that use any speciffic tag, do statistics, etc. With your current approach, you end up using a string splitting for each row, each time.
Now, if you are stuck with your current approach, here is a question about string splitting that you may find useful. But I foresee a great deal of performance complains by users...

"Secondary" query

I'm new to MySQL and I'm having trouble trying to figure out how to solve the following problem:
1 - I have a table with data about some people, including a name, a number code and a category for each one.
Let's supose "JOHN DOE" is one of them, his number code is "1111" and his category is "A"; "FOO" is another one, with number code "2222" and category "B"; and "BAR" is another one, number code "3333" and category "A".
2 - Everyone in category "A" was suposed to fill out a form which filled a second table in my database. In this table, the reference to the responsible for each answer is his/her number code. Each person could also answer the form more than one time.
The problem is: Now I need a table that shows me who answered the form and who did't.
PS: Let's call the database "data_base", the first table "people" (with columns "name", "num_code" and "category") and the second table "answers" (with columns "num_code" and "answer").
Could someone help me?
This can be simply solved with a subquery:
SELECT
`num_code`,
`name`,
(
SELECT COUNT(*)
FROM `answers`
WHERE `num_code` = `people`.`num_code`
) AS `AnswerCount`
FROM
`people`
ORDER BY
`name`
There are a number of ways to solve this problem in SQL. One of the advantages of the above result format is that you will get the number of answers per person. Therefore if it is 0, then you know they didn't fill one out.
You can do this with a so called 'LEFT JOIN'. It gets all records in people and links them to the records in answers. Then using the where clause, all records that indeed have an answer are removed from the result and only those who don't are returned.
select
p.*
from
people p
left join answers a on a.num_code = p.num_code
where
a.num_code is null
Another solution is to use NOT EXISTS. It is actually a bit cleaner to use that, but also a little more complex (you will need a sub-select). And it has proven (to me) to be slower in MySQL.