How to exclude matching records in a MySQL query? - php

I'm trying to get a list of customers waiting on service and idle agents based on the following tables:
Customers Table
|Customers_ID||Customer Name|
|1 ||John |
|2 ||Sam |
|3 ||Kuji |
Agents Table
|AGENT_ID||AGENT Name|
|99 ||Kelly |
|98 ||Raji |
|97 ||Mertle |
Service Table (Customers being served by Agents)
|QUE_ID||AGENT Name||Customer|
|1001 ||Kelly ||Kuji |
|1002 ||Raji ||Sam |
SELECT Customer.custname
FROM Customer LEFT JOIN Service ON ( Customer.custname = Service.custname)
UNION
SELECT Agent.agentname
FROM Agent RIGHT JOIN Service ON ( Agent.agentname = Service.agentname)
WHERE
(Agent.agentname = service.agentname) IS NULL
GROUP BY Customer.custname";
This is returning all the values in the customer table and not the customers without agents. How can I exclude the records that already have a match?

You can use NOT EXISTS to check for agents and customers that are not yet in Service table:
SELECT custname
FROM Customer c
WHERE NOT EXISTS(
SELECT 1
FROM Service s
WHERE s.custname = c.custname
)
UNION ALL
SELECT agentname
FROM Agent a
WHERE NOT EXISTS(
SELECT 1
FROM Service s
WHERE s.agentname = a.agentname
)

It looks like you are trying to do a full outer join. While MySQL does not have a FULL OUTER JOIN keyword, you can simulate it by taking the union of two left joins. The left joins in the query below give the number of idle customers and agents. The critical piece is the WHERE ... IS NULL condition, which will match a customer or agent not already assigned.
SELECT c.custname
FROM Customer c LEFT JOIN Service s
ON c.custname = s.custname
WHERE s.custname IS NULL
UNION ALL
SELECT a.agentname
FROM Agent a LEFT JOIN Service s
ON a.agentname = s.agentname
WHERE s.agentname IS NULL

LEFT or RIGHT JOIN will ensure to return all records with none or some columns having NULL values (in the final table).
You can use NOT EXISTS as per the following (that will reduce the number of records, instead of all):
SELECT custname
FROM Customer
WHERE NOT EXISTS (SELECT custname
FROM Service
WHERE Customer.custname = Service.custname)
UNION ALL
SELECT agentname
FROM Agent
WHERE NOT EXISTS(SELECT agentname
FROM Service s
WHERE s.agentname = a.agentname)

Related

Query to fetch data from two different tables

I have two tables. Table A and B.
I have a log-in form where I will get the username,password, assign, assign2 of the user from table A and fetch data depending on the user's assign1 and assign2 from table B.
How my query would look like?
Looking for answers. Thankyou so much.
Table A -THIS IS THE TABLE FOR LOG-IN FORM
==========================================
username | password | assign1 | assign2 |
------------------------------------------
SANDRA | SANTOS | 1 | 1 | //Values
--------------------------------------------
Table B -
=======================================
name | assign1 | assign 2 |
------------------------------
DADA | 1 | 1 | //this will be displayed
------------------------------
gorg | 2 | 2 |
//this must not be displayed since the user assign1 and assign2 who logged in did not match to this
You are using $sql variable in
$result = $con->query($sql);
It should be $queryagain.
Your question is not clear, but if you want to fetch data from Table B which depends on assign1 and assign2 you can do it like this:
$queryagain = mysqli_query("SELECT * FROM tableB INNER JOIN tableA ON tableB.name=tableA.username WHERE tableA.assign1 = tableB.assign1 AND tableA.assign2 = tableB.assign2");
When you use JOIN it's best practice to JOIN by primary key (id). If tableB.name=tableA.username are not columns with same value you can join by other columns, like assign1, or assign2:
assign1:
$queryagain = mysqli_query("SELECT * FROM tableB INNER JOIN tableA ON tableB.assign1=tableA.assign1 WHERE tableA.assign2 = tableB.assign2");
assign2:
$queryagain = mysqli_query("SELECT * FROM tableB INNER JOIN tableA ON tableB.assign2=tableA.assign2 WHERE tableA.assign1 = tableB.assign1");
Notice: Where clause is not necessay, you can edit WHERE clause depends of the result you want.
I think your are very very new to database programing. First of all I recomend you to read https://www.w3schools.com/sql/sql_join.asp this page and work on examples using try it yourself part.
Join Types:
INNER JOIN: Returns records that have matching values in both tables. That means if assign field is filled in Table A and the value is included in table B then this type of join should match the rows.
LEFT JOIN: Return all records from the left table, and the matched records from the right table. That means all rows in Table A will match either the value is included in table B or not.
RIGHT JOIN: Return all records from the right table, and the matched records from the left table. That means all rows in Table B will match either the value is included in table A or not.
FULL JOIN: Return all records when there is a match in either left or right table. All rows in table A and table B will be included in te result set either they match or not.
Your SQL query may look like:
$sql = "SELECT * FROM table_a a INNER JOIN table_b b on a.assign1 = b.assign1 INNER JOIN table_b b2 on a.assign2 = b2.assign2";
execution part of the sql can be different depending your database engine or other libraries.
I think this thread also helps you: Join two mysql tables with php

mysql join two different tables

I have two tables in my MySql database:
user
- sid
- userid
- username
log
- sid
- userid
- login_time
As you can guess, there's a lot more records in log tables than in user table.
I am using php to present these records on my website in a table format as shown below.
no | userid | username | number of login |
1 | inzo | harvey | 233 |
2 | chae | schmidts | 433 |
3 | hibro | swainy | 12 |
To get the number of login for each user, I can send another queries in a for statement. But it's consuming resources and making the server slow in the end.
Can I have this result in one single join query?
Yes you can, you have to use count the logins for each user with a group by
select t1.userid, t1.username, count(t2.sid)
from user t1
left join
log t2
on t1.userid = t2.userid
group by t1.userid, t1.username
The left join ensures you that users without logins will still be returned, wit 0 as count.
Edit
About the question in the comment: if you want to only count the logins with a specific flag value, you can just add where flag = x before the group by; if you want to have a separate count for each value of the flag, you have to add that flag to both group by and select.
I guess best and by that I mean least resource consuming way would be to add "number_of_login" to user table and just increase it every time he/she is logged in, because any other solution will require looping
SELECT TABLE_A.row_id, TABLE_A.category, TABLE_A.val_1, TABLE_B.val_2
FROM TABLE_B
LEFT OUTER JOIN TABLE_A ON TABLE_B.row_id = TABLE_A.row_id
ORDER BY row_id;
If you want all the results, you need an outer join, not an inner one.
select a.sid,a.userid,a.username,COUNT(b.sid) from user a
Left join log b ON b.sid =a.sid group by a.sid

MySql CROSS JOIN between two tables and match with another

first of all sorry for my bad english. The scenario i have is the following:
I am developing a notification services that sends notifications messages to many users. I have the following 3 tables on MySql
users(user_id)
notifications(notification_id, notification)
notifications_log(notification_log_id, notification_id, user_id)
Every time that a user read a notification, i insert a record on notifications_log table, ex. John user with user_id = 2 read the notification with notification_id =3: "This is a notification", and then i insert a record on notifications_log with user_id = 2 and notification_id = 3.
There is all ok, but i have to create a query to get all the notifications for all the users that not are inserted on notifications_log. What i have is:
SELECT u.user_id, n.notification_id, n.notification, nl.notification_log_id
FROM users as u
LEFT JOIN notifications_log as nl ON nl.user_id = u.user_id
CROSS JOIN notifications as n
WHERE u.user_id NOT IN (SELECT nl.user_id FROM notifications_log as nl)
AND u.user_id = 1 /* test with user 1 */
If there is no records on notifications_log table of user 1, query results show me
user_id | notification | notification_id | notification_log_id
------------------------------------------------------------------------------
- 1 | Notification_1 | 1 | null
- 1 | Notification_2 | 2 | null
But if i insert at least 1 record on notifications_log for user and notification_2, then i get empty results, and i should get:
user_id | notification | notification_id | notification_log_id
----------------------------------------------------------------------------
- 1 | Notification_1 | 1 | null
It seems that the query joins the notification_log_id to the other record with null notification_log_id...
In short, what I need it is get all the notifications from a especific user that there are not on inserted on the table notifications_log
Thanks in advance!
The query you want is probably this one:
select n.notification_id, u.user_id
from notifications n
cross join users u
left join notifications_log nl
on n.notification_id = nl.notification_id
and nl.user_id = u.user_id
where nl.notification_log_id is null
demo here
This query eliminates your derived table, reducing the execution time, and performs the cross join as early as possible to reduce the total number of rows being operating on.
But i'd suggest rethinking this altogether. Once notifications and users table reaches critical mass this is going to create millions upon millions of rows to filter.
A better idea would be to have a notification_inbox table, as a counterpart to your notifications_log table. When a notification is created, place it in the inbox table for each user. That way you can perform a simple query on a single table to determine unread notifications per user, rather than a potentially horrendously performing cross join.
Alternatively again, a single notification_delivery table, rather than inbox and log tables, which has a 'read' flag. This would also allow targeted notifications, as well as bulk delivery to all users.
It seems like you are on the right track but should just be changing user_id to notification_id in the 2nd to last line:
SELECT u.user_id, n.notification_id, n.notification, nl.notification_log_id
FROM users as u
LEFT JOIN notifications_log as nl ON nl.user_id = u.user_id
CROSS JOIN notifications as n
WHERE n.notification_id NOT IN (SELECT nl.notification_id FROM notifications_log as nl)
AND u.user_id = 1 /* test with user 1 */

Select records from one table and sort the result using a column from another table

I'm working on payroll system for the CRM located at my work and I'm trying to save having to store redundant data which over a period of years will stack up.
I tried to relate it to "how to get value from mysql table ordered by another table?" but had no luck.
I have a Users table
===========================================
# id | username | first_name | last_name #
===========================================
# 1 | joe | Joe | Blow #
===========================================
I also have a Timesheets table which stores the data of each individual session which for the sake of keeping short I have condensed a little in this question and obviously misses the full date/time in start and finish.
============================================
# id | username | start | finish #
============================================
# 1 | joe | 00:00 | 23:59 #
============================================
What I want to achieve is to order the results from the Timesheets table by the last_name column in the Users table with just the username that is derived the Timesheets table.
What I am trying to attempt here:
SELECT * FROM `Timesheets` WHERE `start` >= '{$monday}' AND `finish` <= '{$sunday}' ORDER BY (`Users`.`last_name` WHERE `username` = `Timesheets`.`username`) ASC
MySQL is clearly not my niche, what query would provide the desired result?
You'd have to use a JOIN and then ORDER BY, like this:
SELECT ts.*
FROM timesheets ts
JOIN users
ON ts.username = users.username
ORDER BY users.last_name
You may add the WHERE clause as required before the ORDER BY.
Use JOIN:
SELECT *
FROM Timesheets T
JOIN Users U ON T.username = U.username
WHERE T.start >= '{$monday}' AND `finish` <= '{$sunday}'
ORDER BY U.last_name ASC
use join for this:
SELECT t.*
FROM timesheets t
JOIN users
ON t.username = users.username WHERE t.start >= '{$monday}' AND t.finish <= '{$sunday}'
ORDER BY users.last_name

PHP MySQL Select ID from one table and information from another table

I have two tables, one table is called queuelist and the other is call info. In the queuelist table it just lists different IDs. I am trying to get the 'clientID' from that table and match it with the 'ID' in the other table that contains all of the info and display it back on the page. Here is how the tables look:
Table - queuelist
ID | clientID
-------------
1 | 589
2 | 254
3 | 486
Table - info
ID | Name | Phone
--------------------
256 | Bob | 5551231234
486 | Jack | 5551231234
589 | Jill | 5551231234
This is what they call joining tables, you should use a query like this:
SELECT i.ID, i.Name, i.Phone FROM `queuelist` AS q
LEFT JOIN `info` AS i ON (
q.clientID = i.ID
);
I'm using aliases for shorter notation in the above query (queuelist becomes q and info becomes i) and then set the join condition (the bit between the ON()) to be the clientID from the queuelist table should match the ID in the info table.
Also see http://dev.mysql.com/doc/refman/5.0/en/join.html for more details.
You need to use an inner join
select * from queuelist as ql inner join info as i on ql.clientID = i.ID
Though you might want to replace * with specific field names e.g
select ql.clientID, i.fieldname FROM....
Well, I see no difficulty in this using a JOIN.
SELECT * FROM queuelist JOIN info ON clientID = info.ID WHERE queuelist.ID = 2
"Where" would be another option.
SELECT Name, Phone FROM queuelist,info WHERE clientID = ID
Assuming you want only name and phone

Categories