Joining activity table with the source tables in MYSQL - mysql

I have a MYSQL 'activity' table where all activity by a user gets logged. Let's say that a user's activities can be either to ask a question or answer a question. So if a user asks a question, their question gets put into the 'question' table and also the activity gets put into the 'activity' table. Same thing if user provides an answer, except that the answer goes into the 'answers' table and the 'activity' table.
The question table's fields are:
q_id question
The answers table's fields are:
a_id q_id answer
The activity table's fields are:
activity_id q_id user_id action_type
(There are more columns then shown above, but these illustrate the point.)
What I want to be able to do is show a user's recent actions on the site, and actually show what the actions were.
My current MYSQL query simply joins the activity table with the question table as follows (using PDO):
"SELECT *
FROM activity
LEFT JOIN question ON activity.q_id = question.q_id
WHERE activity.user_id = :user_id
ORDER BY activity.a_id desc"
This works okay, and can always give me the question for display in the activities list. However, if the activity that is returned is an answer, I would like to be able to show the answer as well. I tried just using a triple join as follows:
"SELECT *
FROM activity
LEFT JOIN question ON activity.q_id = question.q_id
LEFT JOIN answers ON activity.q_id = answers.q_id
WHERE activity.user_id = :user_id
ORDER BY activity.a_id desc"
But this just gives me a list of rows that is twice as long as the first query, and does not display the answers when the action_type was an answer.
I figure this should be possible, but the more I think about it I believe that maybe I should scrap the activity table and just perform the query directly on the question and answers tables with a UNION? Any opinions on this decision, and any thoughts on the queries?

You could use an outer join, which would return everything in the activity table, even if there isn't a corresponding row in the answer table:
SELECT *
FROM activity
LEFT JOIN question ON activity.q_id = question.q_id
LEFT OUTER JOIN answers ON activity.q_id = answers.q_id
WHERE activity.user_id = :user_id
ORDER BY activity.a_id desc
I'm assuming that for every q_id value in the activity table, there's always going to be one corresponding row in the question table.
To fix the problem with the duplicate answers, I'd add an a_id field to the activity table. For the question activity, you'd set it to NULL, and for each answer you'd set the a_id field to the appropriate a_id value to identify which answer goes with the activity. You'd then adjust the SQL above as follows:
SELECT *
FROM activity
LEFT JOIN question ON
activity.q_id = question.q_id
LEFT OUTER JOIN answers ON
activity.q_id = answers.q_id AND
activity.a_id = answers.a_id
WHERE activity.user_id = :user_id
ORDER BY activity.a_id desc

Related

Counting results from 2 tables base on a third table

I am trying to count number of questions and answers for every company but I want to count them in a single query.
So the problem is this: table pitanje (question) is linked with tvrtka (company)
pitanje.tvrtka_id=tvrtka.tvrtka_id and table answer (odgovor) is linked with question table odgovor.pitanje_id = pitanje.pitanje_id
I have tried with something similar to this and got some faulty results (I counted question and answers separately for testing).
SELECT tvrtka.naziv,
(SELECT COUNT(*) FROM pitanje WHERE tvrtka.tvrtka_id = pitanje.tvrtka_id) AS brojPitanja,
(SELECT COUNT(*) FROM odgovor WHERE odgovor.pitanje_id = pitanje.pitanje_id) AS brojOdgovora
FROM tvrtka
ORDER BY tvrtka.tvrtka_id
But all I get is some MySQL errors (unknown column, not uniqe alias etc.) now and can't get even to a faulty results.
If someone can just explain me the concept of the code above. A lot of answers are written like this but I can't figure out how to do it on my example.
With englisch names it would be something like this:
SELECT
c.name,
COUNT(DISTINCT q.question_id) as numQuestions,
COUNT(a.answer_id) as numAnswers
FROM company c
LEFT JOIN questions q ON q.company_id = c.company_id
LEFT JOIN answers a ON a.question_id = q.question_id
GROUP BY c.name
I let it to you, to translate the table and column names back to your schema.
What is wrong with my code?
Here:
(SELECT COUNT(*) FROM pitanje WHERE tvrtka.tvrtka_id = pitanje.tvrtka_id) AS brojPitanja,
(SELECT COUNT(*) FROM odgovor WHERE odgovor.pitanje_id = pitanje.pitanje_id) AS brojOdgovora
in your second subquery with WHERE odgovor.pitanje_id = pitanje.pitanje_id you are trying to reference a table (pitanje) from another subquery. This is not possible. You can only reference a table in the FROM clause of the outer query, which is tvrtka.

How to query DB table with additional fields from another table

I'm working on a HN-style database, and I'm trying to query a list of 'posts', that contain a 'userHasVoted' property for each one (this checks to see if the user currently logged in has voted for that specific post). (Note: the userHasVoted field does not exist - but needs to be dynamically created if the user has voted for a specific post.)
The 'posts' live in a separate table as the 'votes', joined on post.id and votes.postId.
How can I query the DB to show every post with this property, not limited to just the posts the user has voted for?
It's not entirely clear to me what you are asking, but I think the most likely scenario is you used an INNER JOIN (perhaps expressed as just JOIN), which will only return results where a record from both tables actually exists. What you want is an outer join, which will let you keep records from the first table if no record matches in the second:
SELECT p.*, case when v.postid is not null then 1 else 0 end as UserHasVoted
FROM posts p
LEFT JOIN votes v ON v.postid = p.id and v.userid = #UserID

Filtering Results with JOIN

I have page called questions where the user gets asked questions and he/she has the option to answer them. The questions are pulled from a table called questions. When a question gets answered, a table in my database called answered_questions registers the id of the question answered and the id of the user who answered the question. The purpose of this is to hide the answered questions when the user accesses the page again.
On page load I'm trying to join the two tables and see if the question_id exists in both tables where the userID is that of the logged in user. If the id does exist in both tables then it shouldnt display the result per the use of <>. Problem is that its looping several times for each iteration when I try the following query:
SELECT questions.question_id, questions.user_id
FROM `questions`
JOIN `answered_questions`
ON questions.question_id <> answered_questions.question_id
WHERE answered_questions.user_id = ".$userID."
But it works fine when I use this
SELECT questions.question_id, questions.user_id
FROM `questions`
JOIN `answered_questions`
ON questions.question_id **=** answered_questions.question_id
WHERE answered_questions.user_id = ".$userID."
I sense that I'm doing something wrong with the logic of it all. Any help or clues would be highly appreciated.
To get unanswered questions You can use LEFT JOIN:
SELECT questions.question_id, questions.user_id
FROM questions
LEFT JOIN answered_questions
ON answered_questions.question_id = questions.question_id
AND answered_questions.user_id = ".$userID."
WHERE answered_questions.question_id IS NULL

MYSQL joins not working as expected

I am trying to create a join statement to solve my problem but cannot get my head around it.
I am a new to join statements so please bear with me if my sql statement is nonsense.
I have two tables, one is a table of questions where users have asked questions about items for sale.
Second is a table of items that the user has asked a question about.
Table one called questions consists of question_ref, questioner_user_ref, item_ref, seller_ref, question_text, timestamp
questions
===========
+--------------+--------------------+---------+-----------+--------------+----------+
| question_ref |questioner_user_ref |item_ref |seller_ref |question_text |timestamp |
+--------------+--------------------+---------+-----------+--------------+----------+
Table two called my_item_comments consists of questioner_ref, item_ref, last_question_ref
my_item_comments
===========
+---------------+---------+------------------+
|questioner_ref |item_ref |last_question_ref |
+---------------+---------+------------------+
I have set up table two to keep track of items that the user has asked questions about so they can be informed when someone else asks the seller a question or the seller answers.
So I want to create a recordset of questions that
a). Someone has answered a question about an item the user is selling
b). A seller has replied to a question the user asked,
c). A third user has asked a question about an item that the user has also asked a question about.
A bit like facebook's commenting system, where you are informed about comments people have made on statuses that you have commented on.
So my current sql statement is as follows
$user_ref= current logged in user
$sql=mysql_query("
SELECT * FROM questions
LEFT JOIN my_item_comments
ON questions.item_ref=my_item_comments.item_ref
WHERE questions.questioner_user_ref!='$user_ref'
AND (questions.seller_ref='$user_ref' OR questions.item_ref=my_item_comments.item_ref
ORDER BY timestamp DESC");
The results don't work and I think its because of the OR questions.item_ref=my_item_comments.item_ref but for the life of me I cannot work it out.
Any help would be greatly appreciated, even if it means restructuring my database with more tables or new fields in the tables.
thanks in advance, Barry
SELECT * FROM questions
LEFT JOIN my_item_comments ON questions.item_ref=my_item_comments.item_ref
WHERE
questions.questioner_user_ref != '$user_ref' AND
(questions.seller_ref='$user_ref' OR questions.item_ref=my_item_comments.item_ref)
ORDER BY timestamp DESC
I think you were missing a ) to enclose the OR clause (in the example above I added it)
You should try to improve readability for yourself and us so that it is easier to debug and easier for us to help you :-)
$q = "
SELECT *
FROM questions
RIGHT JOIN my_item_comments ON questions.item_ref = my_item_comments.item_ref
WHERE questions.questioner_user_ref != '".$user_ref."'
AND ( questions.seller_ref = '".$user_ref."'
OR questions.item_ref=my_item_comments.item_ref
)
ORDER BY timestamp DESC";
$rs = mysql_query($q);
And preferably just the query with dummy data
SELECT *
FROM questions
RIGHT JOIN my_item_comments ON questions.item_ref = my_item_comments.item_ref
WHERE questions.questioner_user_ref != 'dummy_ref'
AND ( questions.seller_ref = 'dummy_ref'
OR questions.item_ref=my_item_comments.item_ref
)
ORDER BY timestamp DESC
Try a right join for your query. Left join will indeed get all the rows.

Suggestion for better relational DB Schema [duplicate]

This question already has answers here:
Database design for a survey [closed]
(11 answers)
Closed 3 years ago.
I am here to design a relational database schema that models polling and users. Each
category can have one or many questions. Each user can participate
only once at each category, and can poll (or not) exactly once on
each question. Each poll is yes, no, or abstain (no vote).
I have designed my schema with four tables:
users, [userId, IP]
category, [catId, catTitle]
question, [queId, queTitle]
polls [pollId, queId, userId, answer]
is better or
users, [userId, IP]
category, [catId, catTitle]
question, [queId, queTitle]
polls [pollId, catId, userId]
pollAnswers [pollAndId, queId, pollId, answer]
I would like to know which one is better and why?
as per me since i dun have any extra information about polls i am directly cross joining users and questions with answer.
I also do need to find how many users were abstain for a.) all category question b.) particular category c.) particular question
I have my view as for choice one schema :
select U1.*, Q1.*, P2.*, C1.*
from
( users U1,
questions Q1 )
Left outer Join polls P2 on
Q1.queId = P2.queId AND U1.userId = P2.userId
Left Outer Join category C1 on
Q1.catId = C1.catId
I am trying to worried using above query with cross join between users and question will loose my performance or not?
If second schema is better can u suggest options for my results?
users: rename to user so all entities are singular (or rename the singulars to plural)
category: OK
question: You need a foreign key from question to category
pollAnswers: Rename to pollAnswer, and make it a reference table with three rows: Yes, No, Abstain
polls: Rename to poll, and make this a transaction of a user polling a question, with foreign keys to user, question, and pollAnswer.
(Options: Either validate on insert that the user has no existing polls for questions in the category, or denormalize PollAnswers with the question's foreign key to category and put a unique constraint on user/question. I don't personally like this option because it presents issues if you change the category of a question.)
Then a query for a particular category could look like this:
select *
from category c
LEFT OUTER JOIN question q ON q.catID = c.catID
LEFT OUTER JOIN poll p ON p.queId = q.queId
LEFT OUTER JOIN user u ON u.userId = p.UserID
WHERE c.catID = 'blah blah'