Selecting multiple tables MySQL and retrieving different data - php

I have 4 tables that I need to pull data from. I need to count how many people are signed for a single event and see if a user is applied for an event.
These are my table setups:
TABLE: users
+----+----------+-------+--------+-------+
| id | username | level | class | guild |
+----+----------+-------+--------+-------+
| 1 | example1 | 100 | Hunter | blah |
| 2 | example2 | 105 | Mage | blah2 |
| 3 | example3 | 102 | Healer | blah |
+----+----------+-------+--------+-------+
ID is primary
TABLE: event_randoms
+----+----------+-------+--------+----------+----------+
| id | username | level | class | apped_by | event_id |
+----+----------+-------+--------+----------+----------+
| 1 | random1 | 153 | Hunter | 3 | 3 |
| 2 | random2 | 158 | Healer | 3 | 1 |
| 3 | random3 | 167 | Warrior| 1 | 3 |
+----+----------+-------+--------+----------+----------+
ID is primary
apped_by should be foreign key to users.id
event_id should be foreign key to events.id
TABLE: events
+----+------------+------------+-----------+-----------+-----------+
| id | event_name | event_date | initiator | min_level | max_level |
+----+------------+------------+-----------+-----------+-----------+
| 1 | event1 | date1 | 1 | 100 | 120 |
| 2 | event2 | date2 | 1 | 121 | 135 |
| 3 | event3 | date3 | 1 | 100 | 120 |
| 4 | event4 | date4 | 1 | 150 | 200 |
+----+------------+------------+-----------+-----------+-----------+
ID is primary
TABLE: event_apps
+----+----------+--------------+
| id | event_id | applicant_id |
+----+----------+--------------+
| 1 | 3 | 2 |
| 2 | 4 | 2 |
| 3 | 3 | 1 |
| 4 | 1 | 3 |
+----+----------+--------------+
ID is primary
event_id should be foreign key to events.id
applicant_id should be foreign key to users.id
I will be the first to admit that I am very new to this. I just learned how to use MySQL a few days ago. I can grab stuff from a single table, but I am unsure how to grab from multiple tables.
This is the SQL query I tried
SELECT DD_events.id, event_id, applicant_id, guild, level, class, DD_users.id
FROM DD_events, DD_event_apps, DD_users
WHERE DD_event_apps.event_id = DD_events.id
AND DD_event_apps.applicant_id = DD_users.id
and tried to print_r an array but the array turns up empty.
So a few questions pertain to this:
1: How would I count and display as a number how many people (users and randoms) are signed up for an event?
eg: event 3 should have 4 total (2 users and 2 randoms)
2: How do I see if a particular individual is signed for an event and display text based if they are or not?
eg: user 1 is signed up for event 3 so it would be "Registered" but user 2, who is not signed, would display "Not Registered"
3: I want to display info for who is signed for a particular event in 2 tables, 1 for users and another for randoms.
eg: Event 3 would have 2 users info (username, guild, class, level) under the users table and then 2 random users info (name, class, level, what user applied this person) in the random table.
Any and all help is appreciated even if you can answer 1 part.

I'm thinking this would be your base query:
SELECT
event.id,
app.applicant_id,
usr.guild,
usr.level,
usr.class,
usr.id AS Userid
FROM
DD_events event
JOIN
DD_event_apps app
ON (event.id = app.event_id)
LEFT JOIN
DD_users usr
ON (app.user_id = usr.id)
You can make modifications to this to aggregate it, like so:
SELECT
event.id,
COUNT(app.applicant_id) AS ApplicantCount,
COUNT(DISTINCT usr.guild) AS UniqueGuilds,
COUNT(DISTINCT usr.level) AS UniqueLevels,
COUNT(DISTINCT usr.class) AS UniqueClasses,
COUNT(DISTINCT usr.id) AS UniqueUsers
FROM
DD_events event
JOIN
DD_event_apps app
ON (event.id = app.event_id)
LEFT JOIN
DD_users usr
ON (app.user_id = usr.id)
GROUP BY
event.id
I could write those scripts for you, but I think this provides a good starting point for you to continue from. You'll find that T-SQL is fairly simple when you are trying to get the results you are looking for. Hope this helps!

<?php $query = "SELECT count(*) AS numbuh FROM DD_event_apps WHERE event_id = {$row['id']}";
try
{
// These two statements run the query against your database table.
$stmt = $db->prepare($query);
$stmt->execute();
}
catch(PDOException $ex)
{
// Note: On a production website, you should not output $ex->getMessage().
// It may provide an attacker with helpful information about your code.
die("Failed to run query: " . $ex->getMessage());
}
echo($query);
// Finally, we can retrieve all of the found rows into an array using fetchAll
$count = $stmt->fetchAll();
echo($count['numbuh']); ?>

Related

Issue with order by and group by with two foreign keys in same table

I need to develop chat application in php for this i have created two tables likes users and message. every user details will be stored in users table and every message will be stored in messages table.I have done storing part it is working fine. Now i need to display messages.So as per my requirement.
when any user logs into his portal he/she will be able to see latest messaged users list.And if he want to message any of other users ,he just clicks on there profile pic than a message panel will be opened .Untill here i completed everything.
But my issue is i need to display
latest messaged users list,
in this i need to show user first name, profile picture,last message, last message date.
And one more condition is i need to display the list like latest messaged user first.
I have tried in many ways but i got users list with first message i don't want like that i need last message for that user
My tables are
Users table
uid | firstname | email | mobile
---------------------------------------------
1 | kumar | kumar#gmail.com | 9876543210
----------------------------------------------
2 | jack | jack#gmail.com | 8876543216
----------------------------------------------
3 | rams | rams#gmail.com | 7876543215
----------------------------------------------
4 | devid | devid#gmail.com | 9876543220
----------------------------------------------
5 | joe | joe#gmail.com | 8876543212
----------------------------------------------
messages table
mid| from_id | to_id | message | created_at
----------------------------------------------------------------
1 | 1 | 2 | hello jack | 2017-02-03 09:00:52
----------------------------------------------------------------
2 | 2 | 1 | hi kumar | 2017-02-03 09:10:30
----------------------------------------------------------------
3 | 2 | 3 | ram where are you | 2017-02-03 09:15:02
----------------------------------------------------------------
4 | 3 | 2 | at home | 2017-02-03 09:35:20
----------------------------------------------------------------
5 | 1 | 2 | hello how are you | 2017-02-03 09:42:55
----------------------------------------------------------------
6 | 4 | 2 | good morning | 2017-02-03 09:50:45
----------------------------------------------------------------
8 | 1 | 3 | hi | 2017-02-03 09:54:22
----------------------------------------------------------------
7 | 3 | 1 | hello kumar | 2017-02-03 09:58:38
----------------------------------------------------------------
For example i have logged in as kumar(uid=1)
Expected output:
firstname | message | mid | uid
-----------------------------------------
rams | hello kumar | 7 | 3
-----------------------------------------
jack | hello how are you | 5 | 2
-----------------------------------------
I have tried like this :
SELECT DISTINCT
`u`.`firstname`,
`u`.`profile_photo`,
`u`.`uid`,
`u2`.`firstname`,
`u2`.`profile_photo`,
`u2`.`uid`,
`message`,
`messages`.`created_at`,
`messages`.`from_id`,
`messages`.`to_id`,
`messages`.`mid`
FROM
`messages`
INNER JOIN
`users` AS `u` ON `u`.`uid` = `messages`.`from_id`
INNER JOIN
`users` AS `u2` ON `u2`.`uid` = `messages`.`to_id`
WHERE
(from_id = 1 OR to_id = 1)
GROUP BY
`u`.`uid`,
`u2`.`uid`
ORDER BY
`messages`.`mid` DESC
But got output like this
firstname | message | mid | uid
-----------------------------------------
jack | hello jack | 1 | 2
-----------------------------------------
rams | hi | 5 | 2
-----------------------------------------
Thanks in advance
try this way
SELECT DISTINCT `u`.`firstname`,`u`.`profile_photo`, `u`.`uid`, `u2`.`firstname`,`u2`.`profile_photo`,`u2`.`uid`, `message`,`messages`.`created_at`, `messages`.`from_id`,`messages`.`to_id`,`messages`.`mid`
FROM `messages`
INNER JOIN `users` AS `u` ON `u`.`uid` = `messages`.`from_id`
INNER JOIN `users` AS `u2` ON `u2`.`uid` = `messages`.`to_id`
WHERE (from_id = 1 OR to_id = 1)
GROUP BY `u`.`uid`, `u2`.`uid`
ORDER BY `messages`.`created_at` DESC
It appears that you want to put messages in the same group if they're between the same two users, regardless of the direction. To do this, change your GROUP BY to:
GROUP BY GREATEST(u.uid, u2.uid), LEAST(u.uid, u2.uid)
Use this along with the solutions in SQL Select only rows with Max Value on a Column to get the first or last message in each conversation found using this grouping.
You should also give aliases to the columns from u and u2 in the SELECT clause, so you can distinguish the sender and receiver information in the result.
SELECT u.firstname AS sender_name, u.profile_photo AS sender_photo, ...
Or since one of the users is always kumar, you could just select only the information about the other user:
SELECT IF(from_id = 1, u2.firstname, u1.firstname) AS firstname,
IF(from_id = 1, u2.profile_photo, u1.profile_photo) AS profile_photo,
...

is it safe to run a another query in side a mysql loop

I have a left join query to get posts liked by a users. if 2nd logged in user visit the 1st user profile will show the likes by 1st user and also will show a text on the post if 2nd user (logged in user) like the same post
user table
user_id | username
likes table
like_id | post_id | uid
MySQL
$SQL = "SELECT * FROM likes LEFT JOIN users ON users.user_id = likes.uid WHERE likes.uid = 'user1'"
If i run another query inside the while loop of above query it will work
$check_id = row['post_id']; //get post id from 1st loop
if(isset($_SESSION['userid'])){
$check = "SELECT * FROM likes WHERE post_id='$check_id' AND uid='LOGED-IN-USER-ID'"
}
Then i can get the num_rows and add text. This work perfectly fine but i like to know is there a better way to do this without running so many queries inside the while loop. Is there a way to combine the queries or do the 2nd query outside of the loop.
That's "safe" from "data consistency point of view", but querying in a while after a query is called a "1+N" and is typically a performance killer, you may easily find documentation about SQL 1+N problem.
The solution is to let the SQL server do the job for you in a single query, avoiding playing ping pong with it (read: TCP packets back-and-forth, query parsing, ...).
Given:
> SELECT * FROM user;
+---------+----------+
| user_id | username |
+---------+----------+
| 1 | root |
| 2 | user2 |
| 3 | user3 |
+---------+----------+
> SELECT * FROM `like`;
+---------+---------+---------+
| like_id | post_id | user_id |
+---------+---------+---------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 3 | 1 |
| 4 | 4 | 1 |
| 5 | 2 | 2 |
+---------+---------+---------+
> SELECT * FROM `post`;
+---------+--------+
| post_id | text |
+---------+--------+
| 1 | post 1 |
| 2 | post 2 |
| 3 | post 3 |
| 4 | post 4 |
+---------+--------+
There's multiple way to request what you want, but one way may be:
> SELECT like_id, like.post_id, text,
(SELECT 1 FROM `like`
WHERE post_id = post.post_id AND
user_id = 2 /* logged in user */) AS I_like_it_too
FROM `like`
JOIN post USING (post_id)
WHERE user_id = 1 /* user id of seen profile */;
+---------+---------+--------+---------------+
| like_id | post_id | text | I_like_it_too |
+---------+---------+--------+---------------+
| 1 | 1 | post 1 | NULL |
| 2 | 2 | post 2 | 1 |
| 3 | 3 | post 3 | NULL |
| 4 | 4 | post 4 | NULL |
+---------+---------+--------+---------------+
The use the I_like_it_too alias to display post differently as needed.
From a performance point of view you'll need an index on like.user_id to restrict the selected rows on a little subset, the dependent subquery will only be ran for this subset, so that's OK.
Another possibility may be:
> SELECT displayed.like_id, displayed.post_id, text, my_likes.like_id is not null AS i_also_like
FROM `like` AS displayed
JOIN post USING (post_id)
LEFT JOIN `like` AS my_likes ON
displayed.post_id = my_likes.post_id AND
my_likes.user_id = 2 /* logged user */
WHERE displayed.user_id = 1 /* user id of seen profile */;
+---------+---------+--------+-------------+
| like_id | post_id | text | i_also_like |
+---------+---------+--------+-------------+
| 1 | 1 | post 1 | 0 |
| 2 | 2 | post 2 | 1 |
| 3 | 3 | post 3 | 0 |
| 4 | 4 | post 4 | 0 |
+---------+---------+--------+-------------+
Do u mean like this ?
Table SO_LIKES ( ur "Like" Table )
like_id | post_id | uid
1 | 1 | 1
2 | 2 | 1
3 | 1 | 2
Table SO_USERS ( ur "Users" Table )
user_id | username
1 | User1
2 | User2
SQL
SELECT * FROM SO_LIKES as t1 LEFT JOIN SO_USERS as t2 ON t1.uid = t2.user_id INNER JOIN SO_LIKES as t3 ON t1.post_id = t3.post_id WHERE t2.user_id = 1 AND t3.uid = 2
SO Simply call the Same Table in ur query again and use the ID of user 2 there
WHERE t2.user_id = 1 AND t3.uid = 2
Output Looks then like this
like_id | post_id | uid | user_id | username | like_id | post_id | uid
1 | 1 | 1 | 1 | User1 | 3 | 1 | 2
SO u get the POST_id 1 That both Users has Liked

SQL: get data spread over 3 tables

I am trying to get some statistics for an online game I maintain. I am searching for an SQL statement to get the result on the bottom.
There are three tables:
A table with teams, each having a unique identifier.
table teams
---------------------
| teamid | teamname |
|--------|----------|
| 1 | team_a |
| 2 | team_x |
---------------------
A table with players, each having a unique identifier and optionally an affiliation to one team by it's unique teamid.
table players
--------------------------------
| playerid | teamid | username |
|----------|--------|----------|
| 1 | 1 | user_a |
| 2 | | user_b |
| 3 | 2 | user_c |
| 4 | 2 | user_d |
| 5 | 1 | user_e |
--------------------------------
Finally a table with events. The event (duration in seconds) is related to one of the players through their playerid.
table events.
-----------------------
| playerid | duration |
|----------|----------|
| 1 | 2 |
| 2 | 5 |
| 3 | 3 |
| 4 | 8 |
| 5 | 12 |
| 3 | 4 |
-----------------------
I am trying to get a result where the durations of all team members is summed up.
result
--------------------------
| teamid | SUM(duration) |
|--------|---------------|
| 1 | 14 | (2+12)
| 2 | 15 | (3+8+4)
--------------------------
I tried several combinations of UNION, WHERE IN, JOIN and GROUP but could not get it right. I am using PostgreSQL and PHP. Can anyone help me?
Just use sum with group by:
select t.teamid, sum(e.duration)
from team t
join players p on t.teamid = p.teamid
join events e on p.playerid = e.playerid
group by t.teamid
If you need all teams to be returned even if they don't have events, then use an outer join instead.
Try this
SELECT teamid, Sum(duration),
AS LineItemAmount, AccountDescription
FROM teams
JOIN teams ON teams.teamid = players.teamid
JOIN events ON players.playersid = events.playersid
JOIN GLAccounts ON InvoiceLineItems.AccountNo = GLAccounts.AccountNo
GROUP BY teamid
http://www.w3computing.com/sqlserver/inner-joins-join-two-tables/

mysql group by select with conditional value

In my messages table I have following rows for example,
|----|---------|--------------|------|
| id | user_id | message |status|
|====|=========|==============|======|
| 1 | 2 | msgs 11 | r |
|----|---------|--------------|------|
| 2 | 3 | msgs 12 | r |
|----|---------|--------------|------|
| 3 | 2 | msgs 13 | r |
|----|---------|--------------|------|
| 4 | 3 | msgs 14 | u |
|----|---------|--------------|------|
Now, I need to know two things for each user_id
Whether it has any status u or not.
How many messages are there
For example, a query like below
select user_id, status, count(*) as totalMsg from messages group by user_id
Would brought me following rows
| user_id | status| totalMsg |
|=========|=======|==========|
| 2 | r | 2 |
|---------|-------|----------|
| 3 | r | 2 |
^
|------> I need this value to be 'u' because user 3 has a message u
My current query doesnt really gurantee that it will look for a u in the status column.
Is that possible to do? If so how?
MAX() will work on this since r is the least value based on the lexicographical order.
SELECT user_ID,
MAX(status) status,
COUNT(*) totalMsg
FROM messages
GROUP BY user_ID

I need to create a query using MySQL and PHP to get a result of two tables

I'm new to MySQL and PHP. I have two tables, one to hold all the company names and the other table has only the company name below the user:
Table 1
| # | Company name |
--------------------
| 1 | Microsoft |
| 2 | HP |
| 3 | Asus |
| 4 | Apple |
| 5 | Amazon |
| 6 | CCN |
table 2
| # | Company name | User name |
--------------------------------
| 1 | Asus | x1 |
| 2 | Apple | x1 |
| 3 | HP | x2 |
| 4 | Asus | x2 |
| 5 | Apple | x2 |
I need to create a query that achieves the following. First of all the companies are shown which are associated with a specific user (say Asus and Apple for user x1). After that, the remaining companies from table 1 are shown.
For example, the result of the query I'm looking for, for user X1 will display the rows in this way:
| # | Company name |
--------------------
| 1 | Asus |
| 2 | Apple |
| 3 | Microsoft |
| 4 | HP |
| 5 | Amazon |
| 6 | CCN |
How can I achieve this?
It looks like you want to include all companies, but for a given user, list the companies associated with that user first. If that's the case, you do not want to use an INNER JOIN.
Here's some SQL that should work. I've provided reasonable table and field names since you didn't give those. I'm also assuming that you have a reasonably sane table design with no duplicate rows.
SELECT c.company_name,
CASE
WHEN u.company_name IS NULL THEN 'N'
ELSE 'Y'
END AS user_has_company
FROM companies c
LEFT JOIN (
SELECT *
FROM users
WHERE user_name = 'x1'
) u
ON u.company_name = c.company_name
ORDER BY user_has_company DESC, c.company_name
This query will return an extra column - user_has_company. I'd use that to indicate whether the current user is associated with a given company, but you can ignore it if you want.
You will need a JOIN Statement to join another in the SELECT-Statement of table1
Quick example:
SELECT * FROM table2 INNER JOIN table1.id = table2.id WHERE table2.username = 'x1'
You'll find everything you need in the Documentation of JOINs.
http://dev.mysql.com/doc/refman/5.1/en/left-join-optimization.html
If you're just after the MySQL query for this then something like this would work
SELECT company_name,SUM(IF(user_name='x1',1,0)) as ordering
FROM `table2`
GROUP BY company_name
ORDER BY ordering DESC
But you should look at your schema before you go much further. If you have a column (company_name) in one table that refers to another table you should make that column refer to the PRIMARY KEY of the other table, i.e.
Table1
| # | company_name |
--------------------
| 1 | microsoft |
| 2 | hp |
| 3 | asus |
| 4 | apple |
| 5 | amazon |
| 6 | CCN |
table2
| # | company_id | user_name |
--------------------------------
| 1 | 3 | x1 |
| 2 | 4 | x1 |
| 3 | 2 | x2 |
| 4 | 3 | x2 |
| 5 | 4 | x2 |
This is one of the first things you learn in database design/normalisation. You will need to change your query in this case. Something like this:
SELECT company_name,SUM(IF(user_name='x1',1,0)) as ordering
FROM `table1`
LEFT JOIN `table2` ON table2.company_id=table1.id
GROUP BY company_name
ORDER BY ordering DESC
Create your query like this:
$sql = "SELECT b.companyName FROM table1 a INNER JOIN table2 b ON a.companyName = b.companyName WHERE b.userName = 'x1'";
Then, using PHP, use:
$con = mysql_connect("localhost","peter","abc123");
if (!$con)
{
die('Could not connect: ' . mysql_error());
}
mysql_select_db("my_db", $con);
$result = mysql_query($sql);
while($row = mysql_fetch_array($result))
{
echo $row['companyName'];
echo "<br />";
}
mysql_close($con);
Try this query:
SELECT company_name FROM table2 ORDER BY user_name ASC
In the HTML table, using PHP code:
$result = mysql_query(" SELECT company_name, user_name FROM table2 ORDER BY user_name ASC");
echo "<table>
<tr><th>Company Name</th><th>username</th></tr>";
while($row = mysql_fetch_array($result) {
echo "<tr><td>{$row['company_name']}</td><td>{$row['user_name']}</td></tr>";
}
echo "</table>"

Categories