PHP how to use where in to replace left join in mysql? - php

I have 2 table, records and common_member.
records just store a plugin data. (Not frequently queried) but common_member was a huge data table and frequently queried.
Sample data of common_member
+--------+-----------+
| uid | username |
+--------+-----------+
| 1 | admin |
| 2 | test1 |
+--------------------+
Sample data of records
+--------+-----------+-----------+
| uid | amount |createtime |
+--------+-----------+-----------+
| 1 | 50 |1234567 |
| 1 | 100 |5555555 |
| 2 | 2000 |9999999 |
+--------------------------------+
Normally I am using $lrecord = mysqli_fetch_all("SELECT t1.*,t2.username FROM records t1 LEFT JOIN common_member t2 ON (t1.uid = t2.uid) ORDER BY t1.createtime").
But after that I was be informed if using leftjoin connect with common_member, It will be very inefficient and there was a way just using where in the get the username from common_member.
So, how to get the username from common_member without using leftjoin?
I want the final result of records array to be: (Means username from common_member join to records)
+------+-------------+-----------+-----------+
| uid | username | amount | createtime|
+------+-------------+-----------+-----------+
| 1 | admin | 50 | 1234567 |
| 1 | admin | 100 | 5555555 |
| 2 | test1 | 2000 | 9999999 |
+--------------------------------------------+
My question is, how to use where in get the username in common_member without leftjoin ?
Thank you.

But after that I was be informed...
(with respect...) who informed you ? phpMyAdmin ? another interface ? your friend ? a blog.. ?
there is no problem with the left join, but you must check the indexes of your tables.
It is necessary that in both tables, there is an index (preferably primary) on the field uid.
Otherwise, the request will not be optimized and can be slow.

The answer to your question, how to use where in get the username in common_member without leftjoin ?, is that you can't.
The where clause is used for filtering results, not to add information to them. This could be usefull if you just want to retrive all rows in records which have an existing user. However, if database was properly designed, such a question wouldn't be asked, because records.uid would be an non-nullable foreign key referencing common_member.uid.
Hence, it wouldn't be necessary to make a left join, but only a join.
But, supposing this isn't your case, and the database isn't properly designed, and records.uid isn't a foreign key, then
select *
from records
where uid in (
select uid
from common_member
)
would return all records of existing users. But still, no username.
The only solution is to execute a join, as you are already doing:
SELECT t1.*,t2.username
FROM records t1
JOIN common_member t2 ON (t1.uid = t2.uid)
ORDER BY t1.createtime

Related

Check if value exists in MySQL table and then select [Laravel 5]

Here is my pivot table project_group:
+-----+----------+------------+----------+---------+
| ids | group_id | project_id | admin_id | user_id |
+-----+----------+------------+----------+---------+
| 4 | 115 | 1 | 1 | [3,4,5] |
| 5 | 115 | 2 | 1 | [5,2,1] |
| 6 | 115 | 3 | 1 | [1,3,6] |
This table represent group linked to the projects....user_id is which users can see projects/group... Is there any way to display correct projects/group only to the users defined in user_id?
Also content in user_id field can be changed....
The best way to handle this would be to first normalize your database. Storing comma separated lists in a cell is allowed, but generally bad practice, as explained in this question.
If you can have multiple users per project, you should have a linking table with a column for project and a column for user, like this:
project_users:
| project_id | user_id |
and you can make (project_id, user_id) a composite primary key.
That way, you can select the users for a project (say, project 1) like this:
SELECT user_id
FROM project_users
WHERE project_id = 1;
Once you have these, you can display the project data only to users whose id is returned in the above list.
I have built an SQL Fiddle that helps demonstrate this visually, if it helps.
It is good to note that this proper normalization gives the opportunity to a lot of useful data as well, as it becomes easier to search for users by project, but also you can search for project information based on a user.

Omit / ignore any records that have been purchased by a user

I'm currently in the process of developing a site that amongst other things allows a user to filter a marketplace by showing or hiding items they have already purchased. This works on a basic AJAX call that passes through the current conditions of those filters available, and then using CodeIgniter's active record, it builds the appropriate query.
My issue is wrapping my head around the query so that if a user selects to hide purchased items the query omits / ignores any relevant records (i.e. if user_id = 5 and hide purchased is true, any scenes that user_id = 5 owns are not returned in the query).
Tbl: scenes
-------------------------------------------------------------------------
| design_id | scene_id | scene_name | ... [irrelevant columns to the Q] |
|-----------|----------|------------|-----------------------------------|
| 1 | 1 | welcome | |
| 1 | 2 | hello | |
| 2 | 3 | asd | |
-------------------------------------------------------------------------
The designs table is very similar to this and includes references to the game, game type, design name and so forth.
Tbl: user_scenes
----------------------------------------------------------------------
| design_id | scene_id | user_id | ... [irrelevant columns to the Q] |
|-----------|----------|---------|-----------------------------------|
| 1 | 1 | 5 | |
| 1 | 2 | 5 | |
| 1 | 1 | 9 | |
----------------------------------------------------------------------
Query
SELECT `designs`.`design_id`, `designs`.`design_name`, `scenes`.`scene_id`, `scenes`.`scene_name`, `scenes`.`scene_description`, `scenes`.`scene_unique_code`, `scenes`.`date_created`, `scenes`.`scene_cost`, `scenes`.`type`, `games`.`game_title`, `games`.`game_title_short`, `games_genres`.`genre`
FROM (`scenes`)
JOIN `designs` ON `designs`.`design_id` = `scenes`.`design_id`
JOIN `games` ON `designs`.`game_id` = `games`.`game_id`
JOIN `games_genres` ON `games`.`genre_id` = `games_genres`.`genre_id`
WHERE `scenes`.`private` = 0
ORDER BY `designs`.`design_name` asc, `scenes`.`scene_name` asc
LIMIT 6
The query uses CodeIgniter's active record ($this->db->select() / $this->db->where()) but that is somewhat irrelevant.
--
I've tried things like an INNER JOIN with user_scenes and then grouping by scene_id, but that presents an issue with only returning scenes that are present in user_scenes. I then made an attempt at a subquery but then questioned whether that was the correct route.
I understand there are other ways - looping through the returned data and querying whether that record exists for a specific user, but that I suspect would be highly inefficient. As such, I'm at a loss as to what to try and would appreciate any help.
I don't know if your setup permits it, but I would do a subselect:
Either via a NOT IN:
SELECT * FROM `scenes`
WHERE `scenes`.`scene_id` NOT IN (SELECT `scene_id` FROM `user_scenes` WHERE `user_id` = 5)
Or maybe via a LEFT JOIN:
SELECT * FROM `scenes`
LEFT JOIN (SELECT `scene_id`, `user_id` FROM `user_scenes` WHERE `user_id` = 5) AS `user_scenes`
ON `scenes`.`scene_id` = `user_scenes`.`scene_id`
WHERE `user_scenes`.`user_id` IS NULL
Bit I guess the first way is faster.

Have SQL Table Fields Automatically Link to Lookup Tables

I have a few tables in a MySQL database similar to this setup:
major table
---------------------
| id | name |
|-------------------|
| 0 | Architecture |
| 1 | Biology |
| 2 | Chemistry |
---------------------
college table
----------------------
| id | name |
|--------------------|
| 0 | Georgia Tech |
| 1 | Virginia Tech |
| 2 | Cal Tech |
----------------------
users table
----------------------------------------------
| id | name | major_id | college_id |
|--------------------------------------------|
| 0 | John Smith | 2 | 0 |
| 1 | Kevin Lee | 2 | 1 |
| 2 | Matt Anderson | 0 | 2 |
----------------------------------------------
Using PHP, I want to get all the information for a user using a query similar to this:
SELECT * FROM users WHERE name=`$user`
Is there someway for MySQL to automatically link the "major_id" and "college_id" columns to the "major" and "college" tables in a way where the query above would return the appropriate values?
If it is not possible with a single query, would multiple queries slow down performance considerably?
SELECT * FROM users WHERE name='$user'
This query (yours has back ticks around $user, back ticks are for column names, use double/single quotes) will only return values from the users table. You can't make MySQL "automagically" construct your joins. You have to do it explicitly, otherwise, how would you get information only from the users table if you wanted to? Use a JOIN like this:
SELECT users.name AS Username, college.name AS College, major.name AS Major
FROM users
INNER JOIN college ON users.college_id = college.id
INNER JOIN major ON users.major_id = major.id
Limit the retrieved columns by only selecting the ones you really need. So instead of the asterisk, write users.name etc.
The JOIN syntax is described in the MySQL Docs.
Joins are what your looking for, in this case your SQL would be:
SELECT `users`.`name`, `major`.`name`, `college`.`name`
FROM `users` WHERE `users`.`name`='name'
INNER JOIN `major` ON `major`.`id`=`users`.`major_id`
INNER JOIN `college` ON `college`.`id`=`users`.`college_id`
You can also alias your field names so you get something a bit more usable out:
SELECT `users`.`name` AS `applicant_name`, `major`.`name` AS `major_name`, `college`.`name` AS `college_name`
FROM `users` WHERE `users`.`name`='name'
INNER JOIN `major` ON `major`.`id`=`users`.`major_id`
INNER JOIN `college` ON `college`.`id`=`users`.`college_id`
More on Joins at http://dev.mysql.com/doc/refman/5.0/en/join.html

MySQL Data from 3 tables

I have three MySQL tables which relate to a messaging system. The schema and sample data is shown below for each table relating to my question:
`messages`:
+----+---------+----------+
| id | subject | senddate |
+----+---------+----------+
| 1 | Testing | 12344555 |
+----+---------+----------+
`message_senders`:
+------------+---------+---------+
| message_id | user_id | trashed |
+------------+---------+---------+
| 1 | 1 | 1 |
+------------+---------+---------+
`message_recipients`:
+------------+---------+------+----------+---------+
| message_id | user_id | type | readdate | trashed |
+------------+---------+------+----------+---------+
| 1 | 1 | to | 12344555 | 1 |
+------------+---------+------+----------+---------+
| 2 | 1 | cc | 12344555 | 1 |
My question is how would I select all messages sent by or received by a user, where the trashed parameter is set to 1, without selecting duplicate messages. For example, consider the following scenario:
I want to get the message IDs for all messages trashed by user_id 1, but I don't want to retrieve duplicate IDs (in the data above for example, user_id 1 is the sender AND recipient of message_id 1. I don't want to return the message_id of 1 twice, but want to get all messages for that user.
I think I need to use a combination of JOIN and UNION, but my brain isn't functioning after a long day of PHP!
Try this and see if it only returns one row for each message in the messages table...
select * from messages
left join message_senders on messages.id = message_senders.message_id
left join message_recipients on messages.id = message_recipients.message_id
where message_senders.trashed = 1 or message_recipients.trashed = 1 and messages.user_id = <value>
Assuming you got the query in your mind - I'll just hint you can use DISTINCT keyword to force the DB not to return duplicates.
I am sure you can work it out yourself, because self-conclusions work the best.
Also, a piece of advice - always store dates as datetime or date instead of int. You avoid daylight savings time problems and you can use various date functions provided by MySQL.
Dates are saved internally as 4 byte integers, same as int fields.
Here you go, give this a shot:
select distinct m.id
from messages m
left join message_senders s on m.id = s.message_id
left join message_recipients r on m.id = r.message_id
where ((s.user_id = 1 and s.trashed = 1) or (r.user_id = 1 and r.trashed = 1))
The solution that leaps to my mind is to use a UNIONd subquery:
SELECT DISTINCT * FROM messages WHERE id IN (
(SELECT message_id FROM message_recipients WHERE user_id=1 AND trashed=1)
UNION
(SELECT message_id FROM message_senders WHERE user_id=1 AND trashed=1)
)

query to imlement block list

I have two tables a and b as follows to implement a simple block list where users can block other users.....
Table A
+------------+--------------+------+
| Name | phone |userid|
+------------+--------------+------+
| Mr Sasi | 01225 708225 | 1 |
| Miss Brown | 01225 899360 | 2 |
| Mr Black | 01380 724040 | 3 |
+------------+--------------+------+
Table B
+------------+--------------+
| blockedbyid| blockedid |
+------------+--------------+
| 1 | 2 |
| 2 | 3 |
| 1 | 3 |
+------------+--------------+
"blockedbyid" is id of user who has blocked the user in "blockedid".
I need to join the two tables and fetch all records from table A such that the result has all users who are not blocked by a particular user [ie blockedbyid='XXX'].. Can you guys give the SQL query so that i can fetch the records as a recordset??? I dont want to fetch two different rowsets and compare it in php....
Something like this should work
Parameter :USERID
SELECT * FROM TABLEA WHERE userid NOT IN (SELECT blockedid FROM TABLEB WHERE blockedbyid = :USERID)
Using join
SELECT u.* FROM TABLEB b, TABLEA u WHERE b.blockedbyid = 'XXX' AND b.blockedid = NULL
It may work like that, give it a try.
Roadie57 solutions seems better though.

Categories