Calculate sum from two Tables for a specific User - php

i have an Table with Users and an Table with events that is related to the id from the Users Table. In each Event you can make points and i want to get the total points from an specific User.
It looks like this:
Users
+----+----------+
| id | username |
+----+----------+
Events
+----------+---------+--------+
| event_id | user_id | points |
+----------+---------+--------+
// The event_id is related to an Event Table with specific data about the Event. but that not relevant.
The best could be to get the data from the user and the total points that he got in one query.
Thanks and Greetings,
Mottenmann

"..to get the data from the user and the total points that he got in one query."
You need to join both tables first so you can manipulate the data. The query below uses INNER JOIN which only includes users on the result list if it has atleast one matching record on the Events. If you want to get all users even without a single matching record on the other table, use LEFT JOIN instead.
SELECT a.ID, a.username, SUM(b.points) totalPoints
FROM Users a
INNER JOIN Events b
ON a.ID = b.user_ID
GROUP BY a.ID, a.username
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins

"In each Event you can make points and i want to get the total points
from a specific User."
You could do something like this:
select sum(e.points) as points from users u
left join events e ON (u.id = e.user_id)
WHERE u.id = {$id}
where {$id} is the id of user.

Related

Joining three tables with a circular relationship between them in mysql or sqlserver

So I've been back and forth between NoSQL databases and relational ones, and I can't solve some problems that are solvable pretty easily in NoSql databases. So here's the issue that I'm struggling with right now:
We have an article table with articles' information in it, and a user will submit an article to the system. Each user can submit many articles but each article is written by only one user, so we have a one-to-many relationship here. Now there should be favorites list for users' favorite articles, meaning that any user can have many articles as his/her favorite ones, and each article can be favorited (if that's a verb) by many users. Hence we have a many-to-many relationship and we create a new table called favorites with user_id and article_id in it as columns. Here's a summary of my current design of the tables which have a circular relationship currently.
Users:
id | name
----------
Articles:
id | title | text | user_id | //here user_id is the writer of the article
-----------------------------
Favorites:
id | user_id | article_id | //here user_id the id of the user
--------------------------- //who favorited the article that article_id
//that article_id points to
So what I want to query now is a result table, that will give me a user's favorite articles' information about the article itself, its writer information AND information of the user to whom this favorite item belong. Something like this:
userName | favoriteArticleTitle | favoriteArticleText | favoriteArticleWriter
-----------------------------------------------------------------------------
Because the user in the first column and the user from the last column come from the same table, I cannot think of a way to join these three tables and get the user.name column without causing an ambiguity.
So my question is how can I achieve a result like I want (if it is even possible)?l
Simply alias the columns in your SELECT
SELECT [userName] = u.name
, [favoriteArticleTitle] = a.title
, [favoriteArticleText] = a.text
, [favoriteArticleWriter] = au.name
FROM users u
INNER JOIN favorites f ON u.id = f.user_id
INNER JOIN articles a ON f.article_id = a.user_id
INNER JOIN users au ON a.user_id = au.id
You need a left join the user table twice, one with the favourites and the other with the article table for as follows:
SELECT b.name AS userName, c.title AS faverateArticleTitle, c.text AS favoritArticleText, d.name AS favorateArticleWriter
FROM Favorites AS a
LEFT JOIN users AS b ON (a.user_id = b.id)
LEFT JOIN Articles AS c ON (a.article_id = c.id)
LEFT JOIN users AS d ON (c.user_id = d.id)

Best way to store "Other" data into MySQL database

I have a form with radio buttons which stores the value (which is the ID) in my MySQL database along with the necessary information from the user.
INSERT INTO table (user_id, name, address, prefer_id) VALUES ('', ?, ?, ?);
So when I try to fetch the data, I use LEFT JOIN, to get the necessary description from table2:
SELECT a.name, a.address, b.prefer_desc FROM table a
LEFT JOIN table2 b ON a.prefer_id = b.prefer_id
WHERE a.user_id = ?
But I have created an other option, in case the option the user prefers is not in the list. A textbox will appear when the user selects Other in the list of radio buttons so they can type-in freely their preferred data. Check this fiddle to see an example.
The first logic that I've thinked of is to create a separate table which stores the typed-in data of the user.
other_tb:
other_id | user_id | typed_in |
----------+---------+----------+
1 | 1 | cake |
2 | 3 | pizza |
So when I fetch the data, I use php's if() condition if the prefer_id is 4 (or other), and if it does, I will use another SELECT query to get the other data in other_tb table.
SELECT typed_in FROM other_tb WHERE user_id = ?
Is there a way to do all of this in a single query?
OR
Is this the best option, or is there a right or better way in this kind of situation?
try this
SELECT
a.name,
a.address,
IF(a.prefer_id=4,(SELECT typed_in FROM other_tb WHERE user_id = a.user_id),b.prefer_desc) as prefer_desc
FROM table a
LEFT JOIN table2 b
ON a.prefer_id = b.prefer_id
WHERE a.user_id = ?
If you are using the second table as you described, and you want to keep the same format of the output and assuming the records in other_tb are unique for each user_id, you could use something like this:
SELECT a.name, a.address,
CASE
WHERE a.prefer_id = 4 THEN c.typed_in
ELSE b.prefer_desc
END CASE AS prefer_desc
FROM table a
LEFT JOIN table2 b ON a.prefer_id = b.prefer_id
LEFT JOIN other_tb c ON a.user_id = c.user_id
WHERE a.user_id = ?
I think this can also be written as:
SELECT a.name, a.address,
CASE a.prefer_id
WHERE 4 THEN c.typed_in
ELSE b.prefer_desc
END CASE AS prefer_desc
FROM table a
LEFT JOIN table2 b ON a.prefer_id = b.prefer_id
LEFT JOIN other_tb c ON a.user_id = c.user_id
WHERE a.user_id = ?
There are two approaches that I was able to practice depending on the situation:
Allow users to add more options so that their answer is still indexed to table2. So when fetching data, you may still use LEFT JOIN to get the user's preferred option without any other condition. But this method will allow users to see the options that was added by other users.
If the options are "fixed" and only the administrator is allowed to add options to table2, have another column to table1, which stores the other answer of the user (let say other_option column). This method allows the user to still freely state their option without adding options to table2.
Here is table1:
+---------+------+---------+-----------+--------------+
| user_id | name | address | prefer_id | other_option |
+---------+------+---------+-----------+--------------+
What I do is I put 0 to prefer_id if the user prefers to answer other_option. So your program expects that if the prefer_id is 0, you have an input in other_option.

Select newest entry from two tables in addition to left join and union mysql query

I have three tables that record conversation activity and one table containing user info
I am trying to put a query together that summarises a users conversations (like an inbox with the last comment visible)
my tables are set up like the below
users
---
company | contact_person | pic_small
alerts
---
comment_id | user_id | poster_id | timestamp
activity
---
comment_id | user_id | comment | timestamp
comments
---
comment_id | user_id | comment | timestamp
When a user initially makes contact, the timestamp, comment_id and id's of the users (person sending and person receiving) get inserted into the alerts table. The user_id, comment_id, timestamp and actual comment also get inserted into the activity table.
Then once the conversation has started, all comments (comment_id, user_id,comment, timestamp) get inserted into the comments table.
As mentioned above, what I am trying to do is summarise a users activity so it looks like their inbox.
I have come up with the below query that gives me the user id's, comment id's and user details of all the conversation activity received or sent by logged in user.
SELECT alerts.comment_id,
alerts.user_id,
alerts.poster_id,
alerts.timestamp,
users.contact_person,
users.company,
users.pic_small
FROM alerts
LEFT JOIN users ON users.user_id = alerts.user_id
WHERE alerts.user_id = %s
GROUP BY alerts.comment_id
UNION
SELECT alerts.comment_id,
alerts.user_id,
alerts.poster_id,
alerts.timestamp,
users.contact_person,
users.company,
users.pic_small
FROM alerts
LEFT JOIN users ON users.user_id = alerts.poster_id
WHERE alerts.user_id = %s
GROUP BY alerts.comment_id
ORDER BY TIMESTAMP DESC
The part I am stuck on is getting the last comment (comment with newest timestamp) from either the activity or comments table (It could be either). Happy to change the above query completely if needed.
Below is what I am trying to achieve, I only want to see the user details of people that have contacted me or who I have contacted - not my own details in my inbox (I can do this with php if needed) - It doesn't matter if the last comment was mine however.
Still it is not clear to me why you are using union.
You can get latest comment by below query, if you want to join some other results of other user_id then you can union these results in same way or let me know if you need different results.
SELECT
comment_id,comment, user_id,poster_id,TIMESTAMP, contact_person,company,pic_small
FROM
(SELECT
alerts.comment_id,alerts.user_id,alerts.poster_id,alerts.timestamp,users.contact_person,users.company,users.pic_small,act.comment
FROM alerts
JOIN activity act
ON act.comment_id=alerts.comment_id
LEFT JOIN users ON users.user_id = alerts.user_id
WHERE alerts.user_id = %s
ORDER BY act.timestamp DESC) a
GROUP BY comment_id;

mysql Search data from multiple table

I have 2 tables:
user
ID | Name | Class
Category
ID | user_id | cat_id
If user inputs data from a text field how do I search data from both tables?
You will need a basic query with joins. Something like this:
SELECT * FROM user u
LEFT JOIN category c ON c.user_id = u.id
WHERE ...
SELECT * from user, category
WHERE user.id=[text field]
or category.user_id=[text field]
or category.cat_id=[text field]
You need to join the two tables together.
Select *
from User , Category
where user.id = Category.user_id
Basicly you are linking the two together by the based upon the user_id that they both share. This way you get the information back from both tables.
Here is a link to help you understand the concept. http://www.w3schools.com/sql/sql_join.asp
Try this way
SELECT * FROM user
LEFT JOIN category ON category.user_id = user.ID
WHERE user.Name LIKE '%lorem%'
Try it
you need the time of insertion use mysql_insert_id for user_id to table2.
In the selection time use JOIN in mysql
eg
"select * from tb1,tb2 where tb1.ID=tb2.user_id and where tb1.ID='userid' "
for a specific user
Even you can do like this:
SELECT * from user
LEFT JOIN category ON user.id = category.user_id
WHERE text_field IN (user.id,category.user_id,category.cat_id)

Retrieve values from multiple tables relationed

So, I have a table named clients, another one known as orders and other two, orders_type_a and orders_type_b.
What I'm trying to do is create a query that returns the list of all clients, and for each client it must return the number of orders based on this client's id and the amount of money this customer already spent.
And... I have no idea how to do that. I know the logic behind this, but can't find out how to translate it into a MySQL query.
I have a basic-to-thinkimgoodbutimnot knowledge of MySQL, but to this situation I've got really confused.
Here is a image to illustrate better the process I'm trying to do:
Useful extra information:
Each orders row have only one type (which is A or B)
Each orders row can have multiple orders_type_X (where X is A or B)
orders relate with client through the column client_id
orders_type_X relate with orders through the column order_id
This process is being made today by doing a query to retrieve clients, and then from each entry returned the code do another query (with php) to retrieve the orders and yet another one to retrieve the values. So basically for each row returned from the first query there is two others inside it. Needless to say that this is a horrible approach, the performance sucks and I thats the reason why I want to change it.
UPDATE width tables columns:
clients:
id | name | phone
orders:
id | client_id | date
orders_type_a:
id | order_id | number_of_items | price_of_single_item
orders_type_b:
id | order_id | number_of_shoes_11 | number_of_shoes_12 | number_of_shoes_13 | price_of_single_shoe
For any extra info needed, just ask.
If I understand you correctly, you are looking for something like this?
select c.*, SUM(oa.value) + SUM(ob.value) as total
from clients c
inner join orders o on c.order_id = o.id
inner join orders_type_a oa on oa.id = o.order_type_id AND o.type = 'A'
inner join orders_type_b ob on ob.id = o.order_type_id AND o.type = 'B'
group by c.id
I do not know your actual field names, but this returns the information on each customer plus a single field 'total' that contains the sum of the values of all the orders of both type A and type B. You might have to tweak the various names to get it to work, but does this get you in the right direction?
Erik's answer is on the right track. However, since there could be multiple orders_type_a and orders_type_b records for each order, it is a little more complex:
SELECT c.id, c.name, c.phone, SUM(x.total) as total
FROM clients c
INNER JOIN orders o
ON o.client_id = c.id
INNER JOIN (
SELECT order_id, SUM(number_of_items * price_of_single_item) as total
FROM orders_type_a
UNION ALL
SELECT order_id, SUM((number_of_shoes_11 + number_of_shoes_12 + number_of_shoes_13) * price_of_single_shoe) as total
FROM orders_type_b
) x
ON x.order_id = o.id
GROUP BY c.id
;
I'm making a few assumptions about how to calculate the total based on the columns in the orders_type_x tables.

Categories