MySQL Query Inner Join Inverse? - mysql

How can we show the 'inverse' of the Inner Join. For example, I have a list of actual transactions of customers that went thru the payment processor, in this case 'Paypal' but they never clicked the 'Back to Merchant' tab so that we can process their userid and password.
This script shows ALL the people that are in the customer list and their associated place in the users database:
SELECT
`Transactions List`.`Customer Email`,
users.Email,
`Transactions List`.`Transaction ID`,
users.`Name`,
users.Phone
FROM
`Transactions List`
INNER JOIN users ON `Transactions List`.`Customer Email` = users.Email
What I'm seeking to do is show the INVERSE of that. i.e. all the people who LOST their way. They DO appear in the TRANSACTIONS LIST table but do NOT appear in the USERS table.
Anyone have an idea how to convert this MYSQL Query into the Inverse so we can quickly identify which customers did not get user accounts?
There's an existing post "Inner join inverse Php MySQL" here that wasn't answered that asks a similar question. Perhaps the person asking the question was not clear enough: Inner join inverse Php mysql
also
What is the difference between “INNER JOIN” and “OUTER JOIN”?
What is the difference between "INNER JOIN" and "OUTER JOIN"?
but neither of these methods actually do what I want the script to do.

What I'm seeking to do is show [...] all the people who [...] appear in the TRANSACTIONS LIST table but do NOT appear in the USERS table.
You could use not exists:
select t.*
from transactions_list t
where not exists (
select 1 from users u where t.customer_email = u.email
)
Another way to phrase this is to use an anti-left join (this is more in the spirit of your question, that relates to joins):
select t.*
from transactions_list t
left join users u on t.customer_email = u.email
where u.email is null
This means: try to join each transaction with a user, and filter on those that did not match.

select t.*
from `Transactions List` t
left join users u on t.`Customer Email` = u.email
where u.email is null
Given the above syntax and the name of the table in the database as specified above this is the correct answer. Thank you to GMB for answering the question. For other readers, keep in mind that if your database tables include spaces in their names or field names then you must use the scare quotes to identify your table or field names. This is commonly used when importing tables into MySQL from 3rd party tools.

Related

learning mysql, JOIN query

i'm a beginner on MYSQL db and i'm trying to play around with the query and relations.
i have created 2 tables, one is 'users' which contain the field staff_ID and the other is 'reports' which also contain the table field staff_ID of the user submitting the reports.
on the relations (see picture) i have connect the 2 staff id field.
every user can submit more than one reports, so i'm try to query and get only the reports of one users(staff_ID).
I understood i have to use the JOIN keyword in order to obtain the data..
i tried the following query but it gave me all the result for all the users.
SELECT u.staff_ID
, u.Name
, r.id_report_show
, r.date_report
FROM users u
JOIN reports r
ON r.staff_ID = u.staff_ID
but I would like to have the report only of one specific user like staff_ID = 04033
probably i understood wrong how this query JOIN work, i'm looking for some help.
Thanks
You are almost there. Your join is perfect. You just need a where clause.
SELECT users.staff_ID, users.Name, reports.id_report_show, reports.date_report
FROM `users` INNER JOIN reports ON reports.staff_ID = users.staff_ID
where users.staff_ID = 04033
Or you can also mention it within on clauses:
SELECT users.staff_ID, users.Name, reports.id_report_show, reports.date_report
FROM `users` INNER JOIN reports
ON reports.staff_ID = users.staff_ID and users.staff_ID = 04033
Since it's inner join both the query will produce same output. But for left join those might produce different result. It's a good practice to use where clause instead of mentioning the condition in on clause.

Translate SQL query to mongoDB containing joins and a nested table

I'm completely new to mongoDB, and wondering if it's even possible to query something like this in the mongo language:
SELECT
stg.emp_user_id as emp_user_id,
stg.mgr_user_id as mgr_user_id,
stg.emp_email as emp_email,
stg.employeetype as employeetype,
s.shift_start_time as shift_start_time,
s.shift_end_time as shift_end_time,
s.days_worked as days_worked,
s.num_employees as num_employees,
FROM(
#nested table to link the employee to the manager, based on employee email
SELECT
u.userid as emp_user_id,
p.userid as mgr_user_id,
u.email as emp_email,
u.employeetype as employeetype,
FROM Users u
LEFT JOIN Peoples p on u.email = p.email) stg
#bring in shifts table linked to mgr, now that we have mgr-emp relationship
LEFT JOIN shifts s ON stg.mgr_user_id = s.user_id;
I've been looking around and have been able to find simple conversion references (querymongo.com, stackoverflow examples, etc), but haven't found anything for joins and nested tables. Any help/direction would be appreciated!

Subtle difference between queries?

In the article Why Arel?, the author poses the problem:
Suppose we have a users table and a photos table and we want to select all user data and a *count* of the photos they have created.
His proposed solution (with a line break added) is
SELECT users.*, photos_aggregation.cnt
FROM users
LEFT OUTER JOIN (SELECT user_id, count(*) as cnt FROM photos GROUP BY user_id)
AS photos_aggregation
ON photos_aggregation.user_id = users.id
When I attempted to write such a query, I came up with
select users.*, if(count(photos.id) = 0, null, count(photos.id)) as cnt
from users
left join photos on photos.user_id = users.id
group by users.id
(The if() in the column list is just to get it to behave the same when a user has no photos.)
The author of the article goes on to say
Only advanced SQL programmers know how to write this (I’ve often asked this question in job interviews I’ve never once seen anybody get it right). And it shouldn’t be hard!
I don't consider myself an "advanced SQL programmer", so I assume I'm missing something subtle. What am I missing?
I believe your version would produce an error, at least in some database engines. In MSSQL your select would generate [Column Name] is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.. This is because you select can only contain values in the group by or the count.
You could modify your version to select users.id, count(photo.id) and it would work, but it would not be the same result as his query.
I would not say you have to be particularly advanced to come up with a working solution (or the specific solution he came up with) but it is necessary to do the group in a separate query either in the join or as #ron tornambe suggests.
In most DBMSs (MySQL and Postgres are exceptions) the version in your question would be invalid.
You would need to write the query which does not use the derived table as
select users.*, CASE WHEN count(photos.id) > 0 THEN count(photos.id) END as cnt
from users
left join photos on photos.user_id = users.id
group by users.id, users.name, users.email /* and so on*/
MySQL allows you to select non aggregated items that are not in the group by list but this is only safe if they are functionally dependant on the column(s) in the group by.
Whilst the group by list is more verbose without the derived table I would expect most optimisers to be able to transform one to the other anyway. Certainly in SQL Server if it sees you are grouping by the PK and some other columns it doesn't actually do group by comparisons on those other columns.
Some discussion about this MySQL behaviour vs standard SQL is in Debunking GROUP BY myths
Maybe the author of the article is wrong. Your solution works as well, and it may very well be faster.
Personally, I would drop the if alltogether. If you want to count the number of pictures, it makes sense that 'no pictures' results in 0 rather than null.
As an alternative, you can also write a correlated sub-query:
SELECT u.*, (SELECT Count(*) FROM photos p WHERE p.userid=u.id) as cnt
FROM users u

Need Help writing a MySQL query

I have a database with customer information, orders, etc. I need to run a query that returns all customers who have not placed an order at all.
Relevant tables: login and orders
Relevant Columns: login.loginID, login.loginFirstName, login.loginLastName, login.loginEmailAddress AND orders.OrderuserID
So essentially - in psuedocode: compare table login, column loginID for matches in the orders table under orders.OrderUserID. If no match exists (as in no orders placed) then output the users First Name, Last Name and Email address.
I have been racking my brain but having some real issues with the language. I'm a big time N00B when it comes to SQL.
Basically it'll look like that:
SELECT l.login_id
FROM login l
LEFT JOIN orders o
ON l.login_id = o.login_id
WHERE o.login_id IS NULL
The key is using LEFT JOIN with WHERE ... IS NULL condition. In other words, you specifically look for the rows in login table that don't have any information 'extended' within orders table.
That's just a general description, but I hope it should be helpful in your process of constructing the big query specific to your case. )
select loginFirstName, loginLastName, loginEmailAddress
from login
where loginID not in
(select distinct OrderuserID from orders)
You can also do it with a left join:
select loginFirstName, loginLastName, loginEmailAddress
from login left join orders on loginID = OrderuserID
where OrderuserID is null
Not sure which will execute faster; give it a try. The first is easier to understand, IMHO.
EDIT: "select distinct" means "return me the set of unique values of the field". So, the subquery in the first SQL returns the set of users (their IDs) who do have orders. If a user has multiple orders, DISTINCT makes sure her ID is returned only once.
This should do it:
select *
from login l
left join orders o on l.loginId = o.OrderuserID
where o.OrderuserID is null
Try:
select login.loginFirstName, login.loginLastName, login.loginEmailAddress
FROM login
LEFT OUTER JOIN orders ON login.loginID = orders.OrderuserID
WHERE orders.OrderuserID IS NULL;
or something like that. I suspect the trick for a newer SQL user is the LEFT OUTER join. Without that specifier, a join will only return rows from the first table IF there are matches in the second. This way you get them all (and then filter out matches with the IS NULL phrase).
Though you should try first yourself and you could search on google first :):) .
Anyways you can use it in this way,
SELECT l.loginFirstName,l.loginLastName,
l.loginEmailAddress FROM login AS l LEFT JOIN orders as o
ON l.loginID = o.OrderuserID where OrderuserID is NULL

Mysql fetching data from multiple tables

I am having three tables
user(id,fname,lname)
picture(picid,pic_path,userid)
friends(friend_of,friends_id,status)
I want to fetch id,fname,lname,pic_path for all friends_id of friends_of=1
picture path may be null
Thankx in advance.
What you're looking for is called a join. In particular, you're looking for a JOIN and a LEFT JOIN.
SELECT
user.id, user.fname, user.lname, picture.pic_path
FROM
friends
JOIN user
ON user.id = friends_id
LEFT JOIN picture
ON userid = user.id
WHERE
friends.friend_of = 1
This will only work though if there's a maximum of 1 entry in picture.
Though this answers your immediate question, I suggest you become very familiar with joins. They're one of the fundamental operations of a relational database. (Note that a join essentially is a mathematical relation)
Try this
SELECT u.*,p.*,f.*
FROM USER u
LEFT JOIN picture p ON p.user_id = id
INNER JOIN friends f ON f.friends_of = u.id
WHERE f.friends_id = 1
For querys like that you need to understand and employ the relations between your entities. Then you work in two steps: selection and projection and contrary to what SQL-syntax may imply the part before the FROM keyword is the projection.
First we compile data. Clearly we need the data from all three tables and we need it once. So at first we construct all possible combinations, by joining all three tables. In SQL this is done in the FROM part, i.e.
FROM friends f, picture p, user u
f, p and u are aliases which serve the purpose of saving us the efford of typing the full table names in the following.
Now we have all possible combinations. Let's select the ones we want:
I suppose every picture in your DB belongs to a user which is stored in your DB as well. So my assumption is that you only want pictures associated to a user. Hence we have a first restrictions on all the combinations we made before! The restriction derived from the (probable) meaning of the data stored in you database and stated as:
u.id = p.userid
(Notice: by applying this restriction to combination above we "select" only certain combinations.)
Then you already stated another restrictions as a request "friends_of=1" to associate this constraint on the combination we write:
f.friends_of=1
Then we combine your request "friends_of=1" with the other data by:
f.friend_of = u.id
This constraint selects only those users who are a friend of somebody. Now we can combine these constraints. As we want all constraints to be satisfied we AND them in a WHERE statement:
WHERE u.id = p.userid AND f.friend_of = u.id AND f.friends_of=1
The ordering does not affect meaning (in this case. But let's rethink those constraints:
u.id = p.userid : we want information about the user and the pictures associated with that user
f.friend_of = u.id : we are looking for a users who are friends of somebody
f.friends_of=1 : we are looking for friends of a particular somebody
Now we project the data stored in our DB to what we want. We want all the user data and picture paths. In SQL:
SELECT u.*,p.pic_path
Now we put everything together.
SELECT u.*,p.pic_path FROM friends f, picture p, user u WHERE u.id = p.userid AND f.friend_of = u.id AND f.friends_of=1
To allow for friends that don't have a picture associated with them (note: that's very different to pic_path being NULL) you need an outer join, which means you also want combinations with empty sets. That's where my MySQL is not so good but I'd guess you'd generate all combinations you want (and many more) with:
FROM friends f JOIN user u LEFT JOIN picture p ON u.id = p.userid
and
SELECT u.*,p.pic_path FROM friends f JOIN user u LEFT JOIN picture p WHERE f.friend_of = u.id AND f.friends_of=1
Notice, that the constraint that may be violated has been made explicit by moving it from the general selection to the generation of the data combinations as a rule on how to create combinations. And yes, it's a shortcut instead of following through the idea of selection and projection.