This question already has answers here:
MySQL Results as comma separated list
(4 answers)
Closed 4 years ago.
I have a PHP/MySQL scenario where I want to display a list of events but also show all users assigned to an event. In MySQL I have an events, eventusers and users tables.
I can SELECT event_id, event_name FROM events then loop through results in PHP and then SELECT user_id FROM eventusers WHERE event=[event_id] in each result loop to get that particular event's users.
I am wondering if there is way to do this in one single SQL query (and it's also performance decent) so I get data from the events table as well as all the user IDs attached to the event from the eventusers table. Something like:
event id | event name | Users from eventusers table
------------------------------------------
1 | Soccer match | 3,56,79
2 | Cycling | 46,77,88,126,78
You should make use of a JOIN statement, which merges your tables:
SELECT column_name(s)
FROM table1
INNER JOIN table2 ON table1.column_name = table2.column_name;
In your case, you should do something like:
SELECT event_name, user
FROM events
INNER JOIN eventusers
ON events.event_id = eventusers.event_id
I hope this is helpful for you
You can use the join function:
select * from
table1 JOIN table2
ON table1.pk=table2.fk
and then add the condition
where table1.column= something
however you need to have both tables joined with a column (.pk and .fk), in this case it could be the eventuserid
select * from
events JOIN eventusers
ON events.eventuserid=eventusers.userid
where event.id= [event_id]
Also you can subtitue the * with the columns you'll need: tablename.column and youll only get those column values in return
I'm sorry I dont understand the second part about the CSV file, can you clarify?
Related
table1
----------------|------------------|-------------------|-------------------|
| email | selection1 | selection2 | selection3
|
|---------------------|------------------|-------------------|-------------------|
| test#test.com | 4 | 7 9
|---------------------|------------------|-------------------|------------------|
|test2#test.com 2 9 6
---------------------|------------------|--------------------|-------------------|
table2
|---------------------|------------------|-------------------|-------------------|
| race1| race2 | race3 | race4
|
|---------------------|------------------|-------------------|-------------------|
| 5 | 7 | 9 2
|---------------------|------------------|-------------------|------------------|
So, I have two tables.
One is based on user input selecting 3 races for the number of the winner.
The second table is the number of the race winner.
I want to compare the two tables and create a third table. If the person's selection matches the winning race then they receive 50 points. So the third table would display "email" and "points"
This will continue for 4 days so if the same email matches another race winner they gain an extra 50 points.
I've tried INNER JOIN, but there are too many combinations. I'm new to PHP and SQL, so I really don't know what approach to take.
You can pull the values out of the database, then loop through each user and compare their submissions to the results in the second table. Something like this should be able to help you with the first part (pulling the data out of MySQL and into arrays).
Then let's say that after pulling them out of the database that you have a $users array with all of the users and their submissions, then a $results array with the winners for each race (table2's contents). You can then use a for loop or foreach to go through each user and compare each of their selections to the results. Something like this, for example:
<?
//Loop through each of the users in the $users array
foreach($users as $user)
{
if($user['selection1'] == $results['race1'])
{
//Add to their points or whatever you would like to do
}
if($user['selection2'] == $results['race2'])
{
//Add to their points or whatever you would like to do
}
if($user['selection3'] == $results['race3'])
{
//Add to their points or whatever you would like to do
}
}
?>
However all that being said, you may want to look at re-organizing your database structure. As it is this isn't very flexible if you want to change things in the future. Also the example you provided has 3 races in the first table but 4 in the second.
Your first task is to create a subquery that delivers your table1 in the form of email, selection. That looks like this (https://www.db-fiddle.com/f/mbXAqAo6Y4MPd3jH9vAY4Q/0)
SELECT email, selection1 AS selection FROM table1
UNION ALL
SELECT email, selection2 AS selection FROM table1
UNION ALL
SELECT email, selection3 AS selection FROM table1
Next, do the same for your table2. (https://www.db-fiddle.com/f/mbXAqAo6Y4MPd3jH9vAY4Q/1)
SELECT race1 AS race from table2
UNION ALL
SELECT race2 AS race from table2
UNION ALL
SELECT race3 AS race from table2
UNION ALL
SELECT race4 AS race from table2;
Then, you need to figure out how many race values match each selection value. That takes an aggregate function. The outline of your query is
SELECT email, COUNT(race) races_chosen
FROM selections
JOIN races ON selections.selection = races.race
GROUP BY email
Here, with the JOIN operation you're creating a result set that shows each email along with a selection that also turned up in the races. Then you're counting them.
The actual query here needs to use your subqueries. It looks like this. (https://www.db-fiddle.com/f/mbXAqAo6Y4MPd3jH9vAY4Q/2)
SELECT email, COUNT(race) races_chosen
FROM (
SELECT email, selection1 AS selection FROM table1
UNION ALL
SELECT email, selection2 AS selection FROM table1
UNION ALL
SELECT email, selection3 AS selection FROM table1
) selections
JOIN (
SELECT race1 AS race from table2
UNION ALL
SELECT race2 AS race from table2
UNION ALL
SELECT race3 AS race from table2
UNION ALL
SELECT race4 AS race from table2
) AS races ON selections.selection = races.race
GROUP BY email
Finally, you can change your SELECT line to this to get your points. (https://www.db-fiddle.com/f/mbXAqAo6Y4MPd3jH9vAY4Q/3)
SELECT email, COUNT(race) races_chosen, COUNT(races)*50 points
A couple of things for you to consider.
Don't create another table to contain this result data. Instead, use the query to generate it whenever you need it. That's easier because you don't have to figure out what changed to update your extra table; you just generate the results on the fly. SQL is made for that kind of operation.
The subqueries I gave you to use had the effect of taking your denormalized tables and normalizing them. Without denormalizing them, the query to generate your results would have been much more complex. Your tables are denormalized because they contain multiple facts on each row.
Here's what I mean. Your table2 uses one row to show four different races. Instead you should have one row per race. Then it's much easier to add another race to the table with an INSERT, or to remove one with a DELETE. It also makes the query easier.
Your table1 is denormalized because it's a way to enforce your rule that each email address may pick up to three races. That's a tolerable software design decision. But, if you want to let them add a fourth race in the future, fixing your app gets harder.
This question already has answers here:
How to resolve ambiguous column names when retrieving results?
(11 answers)
Closed 2 years ago.
I have some big tables which I need to combine into a single very large table, to form a single-page data export for a statistical package.
This is easy with INNER JOIN but the some of the tables have the same column names and these are being overwritten by each other when I fetch them as an array in PHP.
There are 4 tables being joined with 30-200 columns in each so there are far too many field names to manually include in the query with aliases, as would be the norm in this situation.
Here's the query:
SELECT * FROM logs
INNER JOIN logdetail ON logdetail.logID = logs.id
INNER JOIN clients ON clients.id = logs.clientID
INNER JOIN records ON records.id = logdetail.id
WHERE logs.userID=1
Is there any way around this? I don't actually mind what the column names are as long as I have the data so if I could prepend the table name to each field, that would do the trick.
I would create a view, your view would be comprised of your long query with aliases
Here is an example taken from the manual
mysql> CREATE TABLE t (qty INT, price INT);
mysql> INSERT INTO t VALUES(3, 50);
mysql> CREATE VIEW v AS SELECT qty, price, qty*price AS value FROM t;
mysql> SELECT * FROM v;
+------+-------+-------+
| qty | price | value |
+------+-------+-------+
| 3 | 50 | 150 |
+------+-------+-------+
This has always worked for me, unless you have one to many or some other relationship among these tables, which will duplicate records.
SELECT * FROM logs l
INNER JOIN logdetail ld ON ld.logID = l.id
INNER JOIN clients c ON c.id = l.clientID
INNER JOIN records r ON r.id = ld.id
WHERE l.userID=1
As andrew says you can also use a View to get this thing working which is much cooler.
I found a solution for this. Simply, fetch each duplicate column a second time, this time using an alias. This way, the overwritten values are selected again and aliased:
SELECT * FROM logs,
clients.name as clientName,
logs.name as logName,
etc...
INNER JOIN logdetail ON logdetail.logID = logs.id
INNER JOIN clients ON clients.id = logs.clientID
INNER JOIN records ON records.id = logdetail.id
WHERE logs.userID=1
Note: There is no need to do this for the final instance of the duplicate, because this column will not have been overwritten. So, in the example above, there is no need to include a line like records.name as recordName because, since there are no columns after it which have the same name, the record.name field was never overwritten and is already available in the name column.
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.
How can I run a select query on a multivalue attribute? Does mysql have a function do select certain data from a multivalue field? Much help is appreciated. Here's a sample of the problem:
Table
userid groups
-------------------
2 2,3,5
4 1
9 2,5,10
datatype is char(250) for groups
I want to do a query to select all userids that belong to group 5, in this example it would be userid 2 and 9. So:
userid
------
2
9
Any way to go about it with a mysql query? or with php/mysql?
In case the groups datatype is SET
You can use
SELECT * FROM users WHERE FIND_IN_SET('5', groups);
UPDATE
In case of char or varchar. You can use this
SELECT * FROM users
WHERE
groups LIKE '5,%'
OR groups LIKE '%,5'
OR groups LIKE '%,5,%'
OR groups = '5'
This is ugly, but if you want to do it completely in MySQL, you could do:
SELECT *
FROM users
WHERE groups LIKE '%,5,%'
OR groups = '5'
OR groups LIKE '%,5'
OR groups LIKE '5,%'
You'd be better off having a separate table with one group per row and a reference back to the user. You could do a join with a much simpler condition with that schema.
SELECT users.*
FROM users
INNER JOIN users_groups ON (users.user_id = users_groups.group_id)
WHERE users_groups.group_id = 5
I know I can do joins but its not exactly what I want.
I'm making a live chat system that has 2 tables mainly: the main chat table (call it table a), and then a mod table (call this one table b). If a user gets suspended, messages reach over 100 for that channel, or they are over 1 week, the messages get moved from the main chat table to the mod table.
I store the ID of the chat messages as ID(primary) on the main chat table and as chatID on the mod table.
What I'm doing is making a separate page for my Mods and I want to be able to combine the two tables into 1 area but I want them to be ordered by their respective tables.
So lets say we had the following:
Main table ID's: 1,2,4
Mod table ID: 3
I want my results to show up 1,2,3,4 no matter which table the ID is in.
Any help is greatly appreciated!
Edit: I got the answer and this is what I used to do so:
SELECT ab.* FROM
((SELECT ID as table_id FROM a
WHERE roomID = 'newUsers' ORDER BY ID ASC)
UNION ALL
(SELECT chatID as table_id FROM b
WHERE roomID = 'newUsers' ORDER BY chatID ASC)) ab
ORDER BY ab.table_id
Use a UNION in a subselect.
SELECT ab.* FROM (
SELECT 1 as table_id, * FROM a
UNION ALL
SELECT 2 as table_id, * FROM b
) ab
ORDER BY ab.id
If you want the result of table A to appear before table B, change the query to:
SELECT ab.* FROM (
SELECT 1 as table_id, * FROM a
UNION ALL
SELECT 2 as table_id, * FROM b
) ab
ORDER BY ab.table_id, ab.id
Some background
UNION ALL will merge two tables resultsets into one resultset.
UNION will do the same but will eliminate duplicate rows.
This takes time and slows things down, so if you know there will be no duplicate records (or you don't care about dups) use UNION ALL.
See also: http://dev.mysql.com/doc/refman/5.5/en/union.html