exclude records that exist in another table - php

I got 2 tables like these:
emails:
emailID int(10) auto_increment, memberID int(10), emailData text, and so on
members:
memberID int(10) auto_increment, user_name char(40), password char(50), and so on
My query is this:
select
emails.emailID, emails.emailData,
members.memberID, members.user_name
from emails, members where
emails.memberID = members.memberID
Now I've added two more tables like these:
blocked:
id int(10) auto_increment, memberID int(10), blocked_memberID int(10)
markedAsRead:
id int(10) auto_increment, memberID int(10), emailID int(10)
I want to modify my original query so that it excludes memberID which are in blocked.blocked_memberID and also excludes emailID which are in markedAsRead.emailID
How can I do this?

You can use NOT EXISTS :
SELECT ....
FROM ....
WHERE ..... // Replace the dots with Your Query
AND NOT EXISTS(SELECT 1 FROM blocked
WHERE emails.memberID = blocked.memberID)
AND NOT EXISTS(SELECT 1 FROM markedAsRead
WHERE emails.emailID = markedAsRead.emailID)
You could also lookup for LEFT JOINS or NOT IN to exclude records that doesn't exists in a particular table.
EDIT: Usually EXISTS() and LEFTJOIN have similar performaces, sometime it can even perform better than a join.
LEFT JOIN sulotion:
SELECT ...
FROM ...
LEFT JOIN blocked
ON(WHERE emails.memberID = blocked.memberID)
LEFT JOIN markedAsRead
ON(emails.emailID = markedAsRead.emailID)
WHERE ...
AND blocked.memberID IS NULL
AND markedAsRead.emailID IS NULL

Related

How can i combine these queries into single query with where clause from another parent table?

How can I combine these queries into a single query with where clause from another parent table? Please consider my SQL code and suggest a better method to work with
//look my code
CREATE TABLE IF NOT EXISTS first (
fid int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
p_name varchar(60) NOT NULL
);
CREATE TABLE IF NOT EXISTS second (
sed int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
firstname varchar(20) NOT NULL,
fid int(11) NOT NULL,
FOREIGN KEY (fid) REFERENCES first(fid)
);
CREATE TABLE IF NOT EXISTS third (
thid int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
start_date date NOT NULL,
end_date date NOT NULL,
sed int(11) NOT NULL,
FOREIGN KEY (sed) REFERENCES second(sed),
fid int(11) NOT NULL,
FOREIGN KEY (fid) REFERENCES first(fid)
);
CREATE TABLE IF NOT EXISTS fourth (
fid int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
start_date date NOT NULL,
end_date date NOT NULL,
sed int(11) NOT NULL,
FOREIGN KEY (sed) REFERENCES second(sed),
fid int(11) NOT NULL,
FOREIGN KEY (fid) REFERENCES first(fid)
);
CREATE TABLE IF NOT EXISTS fifth (
fiid int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
start_date date NOT NULL,
end_date date NOT NULL,
sed int(11) NOT NULL,
FOREIGN KEY (sed) REFERENCES second(sed),
fid int(11) NOT NULL,
FOREIGN KEY (fid) REFERENCES first(fid)
);
CREATE TABLE IF NOT EXISTS sixth (
sid int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
start_date date NOT NULL,
end_date date NOT NULL,
sed int(11) NOT NULL,
FOREIGN KEY (sed) REFERENCES second(sed),
fid int(11) NOT NULL,
FOREIGN KEY (fid) REFERENCES first(fid)
);
//As you can see above, I want to create a single query to query all data at the samee time i.e
//All table from third table depend on first and second table, but the second table have column firstname and the first table has the p_name column
//I want
SELECT second.*, third.* FROM second INNER JOIN third ON third.sed = second.sed
SELECT second.*, fourth.* FROM second INNER JOIN fourth ON fourth.sed = second.sed
SELECT second.*, fifth.* FROM second INNER JOIN fifth ON fifth.sed = second.sed
SELECT second.*, sixth.* FROM second INNER JOIN sixth ON sixth.sed = second.sed
....WHERE fid = 1;
I want to combine these queries into a single query ie, $newqueries = '.....';
The concept
The second table is used to carry all details, ie student details, but the third to sixth tables are tables with few different details but they took all other details from the second table, ie a student can be a chairman, secretary and vice secretary but not all students so that I classified them in third to sixth table. The first table used to keep few info about i.e classes so I want to differentiate chairman etc base on class tables but all of them are students
In short
A chairman, secretary and vice secretary are students but not all students have these role in a class but we have more than one classes, how to differentiate these leaders based on class
in a single query
You can use left join
SELECT second.*, third.*,fourth.*,fifth.*,sixth.* FROM second
LEFT JOIN third ON third.sed = second.sed
LEFT JOIN fourth ON fourth.sed = second.sed
LEFT JOIN fifth ON fifth.sed = second.sed
LEFT JOIN sixth ON sixth.sed = second.sed
WHERE second.fid = 1;
I assume that if student is chairman then there will be an entry of that student in third table. Above query will return null if the student is normal student. You can use CASE Statement if you want role as well. For example,
CASE WHEN third.startdate IS NULL THEN '' ELSE 'Chairman' END

PHP MySQLi Check if user voted if so other users can vote also

I have this working fine(I'm a relatively new coder) as long as there is 1 vote. How can I get other users to vote? code below:.
SELECT
b.id,
b.image_1_file,
b.your_name,
b.your_votes,
b.image_2_file,
b.battling_with_name,
b.battling_with_votes
FROM
battles b left outer join
votes v
on
b.id = v.battle_id
where
v.battle_id is null
order by
rand()
limit 1
and I tried:
SELECT
b.id,
b.image_1_file,
b.your_name,
b.your_votes,
b.image_2_file,
b.battling_with_name,
b.battling_with_votes
FROM
battles b
WHERE
b.id NOT IN (
SELECT
v.battle_id
FROM
votes v
WHERE
v.voters_id != '$myid'
)
order by
rand()
of course the latter will only look for b.id
other users have an id variable: $my_id
I don't want the member to see the image again after they have voted.
Thanks a lot for your help and have a blessed day!
My table structures are:
my images(to vote on) table:
id int(10) unsigned NO PRI auto_increment
image_1_file varchar(40) NO
image_2_file varchar(40) NO
your_name varchar(50) NO
your_votes int(10) NO 0
battlingwithname varchar(15) NO
battlingwithvotes int(10) NO 0
my votes(votes are stored) table:
id int(10) unsigned NO PRI auto_increment
battle_id int(10) unsigned NO
vote_type tinyint(1) unsigned NO
voters_id varchar(30)
just use not in operator, you have t ignore those id from projection who is already voted, so you have to pick up those id who voted and remove from projection by using not in note:another operator exist can also be used but i used not in my query
SELECT
b.id,
b.image_1_file,
b.your_name,
b.your_votes,
b.image_2_file,
b.battling_with_name,
b.battling_with_votes
FROM
battles b
where b.id not in( select v.battle_id from votes v)

Select last distinct pair

Ok we have inbox table where we keep messages that users send to each other. Here is the table:
CREATE TABLE IF NOT EXISTS `inbox` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`fromid` int(10) unsigned NOT NULL DEFAULT '0',
`toid` int(10) DEFAULT NULL,
`message` text CHARACTER SET utf8 NOT NULL,
`time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
KEY `toid` (`toid`),
KEY `fromid` (`fromid`),
KEY `fromid_2` (`fromid`,`toid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
fromid and toid are id's of the users. We have their id's, times when the message is sent. What we need is a query that would return all messages that are not replied by 'our users' (admins).
Table accounts keeps track of users. To simplify:
CREATE TABLE IF NOT EXISTS `accounts` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`our` int(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
So basically, we need a query that gives us the users WHOSE messages WERE NOT ANSWERED by admins (our users), their count and the date of the last message they sent to ADMIN, ordered from last to oldest.
So far we only have some basic queries, we didn't come up with anything reasonable that I could post.
Thanks in advance.
EDIT: From what I see we first need to find last interaction from two DISTINCT users in inbox table... then check & filter only those that were sent TO our users
How about this?
SELECT i.* FROM inbox as i
WHERE (i.toid, i.fromid) NOT IN
(SELECT i2.fromid, i2.toid FROM inbox as i2 WHERE i2.`time` >= i1.`time` AND i2.id = 1);
Another way using join:
SELECT DISTINCT i1.*
FROM inbox as i1 LEFT JOIN inbox as i2
ON i1.toid = 1 AND
i1.fromid = i2.toid AND
i1.toid = i2.fromid AND
i1.`time` <= i2.`time`
WHERE i2.id IS NULL;
Two possible solutions presented below: LEFT JOIN solution should perform better.
LEFT JOIN solution
SELECT
i.fromid, COUNT(*) AS unread, MAX(i.time) AS lastmsg
FROM inbox AS i
INNER JOIN accounts AS a
ON i.toid = a.id
LEFT JOIN inbox AS i2
ON i.fromid = i2.toid AND i.toid = i2.fromid AND i.time <= i2.time
WHERE a.our = 1 AND i2.id IS NULL
GROUP BY i.fromid
ORDER BY lastmsg DESC;
NOT IN solution
SELECT
i.fromid, COUNT(*) AS unread, MAX(i.time) AS lastmsg
FROM inbox AS i
INNER JOIN accounts AS a ON i.toid = a.id
WHERE a.our = 1 AND
(i.toid, i.fromid)
NOT IN (SELECT i2.fromid, i2.toid FROM inbox AS i2 WHERE i2.time >= i.time)
GROUP BY i.fromid
ORDER BY lastmsg DESC;

How do I select MySQL records based on results from a related table?

I have two tables in this scenario: members and team_members. The members table is pretty self explanatory. The team members table stores the member's team information if they are a member of the team. If there is no row in the team members table that has a member_id of a user, then they are not in a team. What I want to do is get all the users that are not members of a team. Should I use left join, inner join, outer join, or just join? What would this query look like?
CREATE TABLE IF NOT EXISTS `members` (
`member_id` int(15) NOT NULL AUTO_INCREMENT,
`group_id` int(15) NOT NULL,
`display_name` text NOT NULL,
`email_address` text NOT NULL,
`password` text NOT NULL,
`status` tinyint(1) NOT NULL,
`activation_code` varchar(16) NOT NULL,
`date_joined` text NOT NULL,
PRIMARY KEY (`member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `team_members` (
`team_member_id` int(15) NOT NULL AUTO_INCREMENT,
`member_id` int(15) NOT NULL,
`team_id` int(15) NOT NULL,
`date_joined` text NOT NULL,
`date_left` text NOT NULL,
`total_xp` int(15) NOT NULL,
PRIMARY KEY (`team_member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
There's several ways to write this query.
To me this is the easiest to read and understand:
select * from members where member_id not in (select member_id from team_members).
This is a really simple way to write it. If you decide you want everything you can quickly comment out the where clause:
select m.* from members m left outer join team_members tm on m.member_id = tm.member_id
where tm.member_id is null
This way doesn't seem very popular from the SQL I read but I think it's straightforward:
select m.* from members m where not exists
(select member_id from team_members tm where tm.member_id = m.member_id)
On the face of it, the below query is fine
SELECT members.member_id
FROM members
LEFT OUTER JOIN team_members
ON team_members.member_id = members.member_id
WHERE team_members.member_id IS NULL
This will do, but on reading your question again, you seem to have a date_left column and if you want only those members who have not yet left a team then
SELECT members.member_id
FROM members
LEFT OUTER JOIN (SELECT *
FROM team_members
WHERE team_members.date_left != '') CURRENT_TEAMS
ON CURRENT_TEAMS.member_id = members.member_id
WHERE CURRENT_TEAMS.member_id IS NULL
SQLFiddle example
http://www.sqlfiddle.com/#!2/46b25/6/0

Implementing a tag system for my news system

I'm trying to build a tag system for my news system. I have finalized a table structure like this:
CREATE TABLE article_tags (
id int(11) unsigned NOT NULL auto_increment,
tag varchar (255) not null,
primary key (id));
CREATE TABLE article_tags_map (
id int(11) unsigned NOT NULL auto_increment,
tag_id int(11) unsigned not null,
article_id int(11) unsigned not null,
primary key (id));
Now I'm just wondering if it would make sense to add a full text index to the tag column in article_tags table ?
$search = $_POST['search_string'];
$search_result = mysql_query ("SELECT *, MATCH(tag) AGAINST ($search) AS score
from article_tags
WHERE MATCH (tag) AGAINST($search)
order by score desc");
Or would I be better off with using LIKE and % wildcard characters ? If I were to use fulltext search, I'm not really sure what threshold should I use for the score ?
Try this.
SELECT *
from article_tags
WHERE tag like '%$search%'
order by tag desc
or
SELECT *
from article_tags
WHERE match(tag) against ('%$search%')
order by tag desc
also take a look to this page where they talk about full text searching: http://devzone.zend.com/26/using-mysql-full-text-searching/

Categories