Retrieve unique results from JOIN query - php

I have two tables, one is 'posts' the other is 'images'
posts table
id | article |
1 | post 1 |
2 | post 2 |
3 | post 3 |
images table
project_id | image_name|
1 | img1 |
1 | img2 |
2 | img3 |
2 | img4 |
3 | img5 |
3 | img6 |
My current query is this:
SELECT * FROM `images` RIGHT JOIN `posts` ON images.project_id = posts.id
But it is showing multiple results from the posts table.
I want the results like this, to avoid multiple results.
post 1 - img1
post 2 - img3
post 3 - img5

SELECT
p.article, i.image_name
FROM
`posts` p
JOIN (
select
i2.project_id, min(i2.image_name) as image_name
from
images i2
group by
i2.project_id
) i
on i.project_id=p.id

SELECT * FROM posts RIGHT JOIN images ON posts.id = images.project_id group by posts.id
Use group by Clasue to get unique result.

This will do exactly what you asked for.
SELECT `posts`.id, `posts`.`article`,`images`.`image_name` FROM `posts` INNER JOIN `images` ON `posts`.`id` = `images`.`project_id` GROUP BY id
Check this out.
MariaDB [fbb]> SELECT * FROM `posts`;
+----+---------+
| id | article |
+----+---------+
| 1 | post1 |
| 2 | post2 |
| 3 | post3 |
+----+---------+
3 rows in set (0.00 sec)
MariaDB [fbb]> SELECT * FROM `images`;
+------------+------------+
| project_id | image_name |
+------------+------------+
| 1 | img1 |
| 1 | img2 |
| 2 | img3 |
| 2 | img4 |
| 3 | img5 |
| 3 | img6 |
+------------+------------+
6 rows in set (0.00 sec)
MariaDB [fbb]> SELECT `posts`.id, `posts`.`article`,`images`.`image_name` FROM `posts` INNER JOIN `images` ON `posts`.`id` = `images`.`project_id` GROUP BY id
-> ;
+----+---------+------------+
| id | article | image_name |
+----+---------+------------+
| 1 | post1 | img1 |
| 2 | post2 | img3 |
| 3 | post3 | img5 |
+----+---------+------------+
3 rows in set (0.00 sec)
MariaDB [fbb]>

Related

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

How to select multiple data from other table from each id separated by comma in codeigniter

I have the tables like this
tbl_post
+-----------+--------------+
| post_id | post_content |
+-----------+--------------+
| 1 | contentone |
+-----------+--------------+
tbl_category
+-------------+---------------+
| category_id | category_name |
+-------------+---------------+
| 1 | Politic |
| 2 | Social |
| 3 | Economy |
+-------------+---------------+
tbl_category_post
+------------------+-------------+---------+
| category_post_id | category_id | post_id |
+------------------+-------------+---------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 3 | 1 |
+------------------+-------------+---------+
then I want the output like this
+--------------+--------------------------+
| post_content | category |
+--------------+--------------------------+
| 1 | Politic, Social, Economy |
+--------------+--------------------------+
and then how to show the data like this using codeigniter, I really confused at all, anyone please help me!
Edit: With Codeigniter (not tested):
$this->db->select('post_id, GROUP_CONCAT(tc.category_name) AS category_name')
->from('tbl_category_post tcp')
join->('tbl_category tc', 'tc.category_id=tcp.category_id', 'left')
->group_by('tcp.post_id');
I suppose You need PHP loop method to loop this.
Use mysql GROUP_CONCAT function:
SELECT post_id, GROUP_CONCAT(tc.category_name) AS category_name
FROM tbl_category_post tcp
LEFT JOIN tbl_category tc ON tc.category_id=tcp.category_id
GROUP BY tcp.post_id

mysql fetch data in where condition

I have 3 table now:
First is : member_username
+-------------+------------------+
| uid | username |
+-------------+------------------+
| 1 | theone |
| 2 | ohno |
| 3 | prayforpr |
+-------------+------------------+
Second is : member_data
+-------------+-------------------+-----------------+
| uid | talk | etc |
+-------------+-------------------+-----------------+
| 1 | talk1 | |
| 2 | talkeee | |
| 3 | iojdfnl | |
+---------------------------------------------------+
Third is : member_level
+-------------+-------------------+-----------------+
| uid | level | fid |
+-------------+-------------------+-----------------+
| 1 | 2 | 1 |
| 1 | 10 | 2 |
| 2 | 1 | 1 |
| 2 | 99 | 2 |
| 1 | 40 | 3 |
| 3 | 50 | 1 |
| 1 | 44 | 4 |
+---------------------------------------------------+
I would like to query data and display the only one uid when member_level is higher in when SUM member_level.level Where fid in 1,2,3.
my query now is like below, but this query is sum all the level including fid 4 also, how to specify only sum in fid 1,2,3? and how do I assign the SUM of member_level.level Where fid in 1,2,3 to $levelKingTotalLevel?
$levelKing = DB::query("SELECT t1.uid,t1.username,t2.talk FROM ".DB::table('member_level')." t3 JOIN ".DB::table('member_username')." t1 ON(t3.uid = t1.uid) JOIN ".DB::table('member_data')." t2 ON (t1.uid = t2.uid) GROUP BY t3.uid ORDER BY SUM(t3.level) DESC LIMIT 1");
while($rowlevelKing = DB::fetch($levelKing)) {
$levelKingTotalLevel = $rowlevelKing['???'];
$levelKingN = $rowlevelKing['username'];
$levelKingUID = $rowlevelKing['uid'];
$levelKingT = $rowlevelKing['talk'];
};
echo "The ".$levelKingN." total level is ".$levelKingTotalLevel." and he talk about ".$levelKingT;
Thank you.
To filter records having fid values as 1, 2 or 3, use IN statement in WHERE clause. Alias totalLevel in select statement will give you total level for a user.
SELECT t1.uid, t1.username, t2.talk, SUM(t3.level) AS totalLevel
FROM member_level t3
JOIN member_username t1
ON (t3.uid = t1.uid)
JOIN member_data t2
ON (t1.uid = t2.uid)
WHERE t3.fid IN (1,2,3)
GROUP BY t3.uid
ORDER BY totalLevel DESC
LIMIT 1

Php/SQLite , use a parameter for the JOIN taken from a query?

I have to do this with PHP on a simple SQLite database , with PDO
i have 3 table, tableA - tableB, TableC
tableA
the column TYPE represents the name of the other tables
___________________________________
|ID_OBJ | TYPE | PROP_1 | PROP_2 |
-----------------------------------
| 1000 | tableB | 0 | 10 |
| 1001 | tableB | 1 | 10 |
| 1002 | tableC | 1 | 10 |
-----------------------------------
tableB
____________________________
| ID | PROPA | PROPB |
----------------------------
| 1000 | ... | .... |
| 1001 | ... | .... |
----------------------------
tableC
____________________________
| ID | PROPAA | PROPBB |
----------------------------
| 1002 | ... | .... |
----------------------------
what I wanted to know is: Can i , through a JOIN (for example a LEFT JOIN) do a query that return something like this?
_______________________________________________________________________
|ID_OBJ | TYPE | PROP_1 | PROP_2 | PROPA | PROPB | PROPAA | PROPBB|
-----------------------------------------------------------------------
| 1000 | tableB | 0 | 10 | ... | ... | | |
| 1001 | tableB | 1 | 10 | ... | ... | | |
| 1002 | tableC | 1 | 10 | | | ... | ... |
-------------------------------------------------------------------------
I don't know how to do this, having to take the name of the table on which to perform a join from a table. So let me know if I can run a JOIN, and not having to do a query for each row present in the table tableA
thanks
An outer join also returns rows for which no match was found:
SELECT tableA.ID_OBJ,
tableA.TYPE,
tableA.PROP_1,
tableA.PROP_2,
tableB.PROPA,
tableB.PROPB,
tableC.PROPAA,
tableC.PROPBB
FROM tableA
LEFT JOIN tableB ON tableA.TYPE = 'tableB' AND tableA.ID_OBJ = tableB.ID
LEFT JOIN tableC ON tableA.TYPE = 'tableC' AND tableA.ID_OBJ = tableC.ID
If the are no 'wrong' rows in tableB/C, it is not necessary to check the type:
SELECT tableA.ID_OBJ,
tableA.TYPE,
tableA.PROP_1,
tableA.PROP_2,
tableB.PROPA,
tableB.PROPB,
tableC.PROPAA,
tableC.PROPBB
FROM tableA
LEFT JOIN tableB ON tableA.ID_OBJ = tableB.ID
LEFT JOIN tableC ON tableA.ID_OBJ = tableC.ID

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/

Categories