How to merge two tables before doing a inner join? - mysql

TABLE user
- id
- username
- email
- passwd
TABLE user_external
- id
- username
- email
- passwd
TABLE orders
- id
- user_id
- product
I have two tables containg userinformation i want to merge in order to get usersname on a order.
my select only fetches the name from the user table (and leaves the ones from external blank), but not the user_external.
Is there a way to UNION users tables, and then do a left join?
select
orders.product,
merged_user_table.name as name
FROM orders o
LEFT JOIN merged_user_table user_assigned_to ON o.user_id = merged_user_table.id
WHERE
orders.id = 1

The following should work:
SELECT
orders.product
,merged_user_table.name as name
FROM orders o
LEFT JOIN (
SELECT id,username,email,passwd
FROM user
UNION ALL
SELECT id,username,email,passwd
FROM user_external
) merged_user_table user_assigned_to
ON o.user_id = merged_user_table.id
WHERE
orders.id = 1
I have assumed that the user and user_external tables' users are distinct. Using UNION without ALL will effectively perform a SELECT DISTINCT between the two selects in the subquery, which would be less efficient.

While you can use a sub query the get a unioned table, then join that to orders, this does mean the main join won't use an index.
As such I would probably use 2 separate queries, one joining orders with user and the other joining orders with user_external, and union the results together.
This should work (using an INNER JOIN rather than a LEFT OUTER JOIN - can't see why you are using a LEFT OUTER JOIN but there might be a reason). You have specified to bring back a column called name, but neither user table has such a column so not sure if you mean to bring back the user name or the table name - so the below example SQL brings back both.
SELECT orders.product,
user.username as name,
'user' as table_name
FROM orders o
INNER JOIN user
ON o.user_id = user.id
WHERE orders.id = 1
UNION ALL
SELECT orders.product,
user_external.username as name,
'user_external' as table_name
FROM orders o
INNER JOIN user_external
ON o.user_id = user_external.id
WHERE orders.id = 1

Related

Ignore inner join if there are no records?

These two requirements must be met:
Select products that have the status "waiting".
The last e-mail must have been sent 3 days ago.
The following tables and columns are given:
products: id, name, status_id, notification
status: id, name
emaillogs: id, product_id, subject, text, date_created
I tried the following:
SELECT
product.id
FROM
product
LEFT JOIN
status ON product.status_id = status.id
INNER JOIN
emaillog ON product.id = emaillog.product_id
AND (emaillog.date_created <= '2018-11-04 16:32:49')
WHERE
(status.name = 'waiting' AND product.notification = 1)
GROUP BY emaillog.product_id
This works only if there are records in the emaillogs table. If there are no records in the emaillogs table, the products should nevertheless be selected.
Use LEFT JOIN rather than ordinary inner JOIN if you want to preserve unjoined rows in your result set. But, beware, mentioning a column from a left-joined table in your WHERE clause converts the left join to an inner join.

If row exist in a table then use another tables value in SQL

What i would like to archieve:
Getting the correct sum of the total amount of the orders that has been cancelled of user id 2002.
Some pre information:
I am having deals which that has its price in deals.price and its id in deals.ID
I then have orders with a foreign key to deals.ID
Running this SQL:
select SUM(deals.price), orders.* from orders
JOIN deals ON deals.ID = orders.deal_id
where orders.user_id = 2002
and orders.cancelled = 1
Works just fine.
Here is where i get stuck:
As an addition to deals, each deals has products with their own prices.
Table is called deal_products, deal_products.price hold the price and deal_products.product_id has the ID of it.
A order is attached to a deal product in another table called order_products, where order_products.product_id = deal_products.product_id
To sum up: I would like to do is including a if inside the above SQL.
If a order has a row in order_products, get the order_products.product_id and find the price in deal_products (price) and use this instead of deals.price when SUM()'ing.
If there is no row it should use deals.price.
How can this be archieved? To first look in another table if there is a entry, and then further look in to a third table and get a value to use?
You can use COALESCE + LEFT JOIN:
select SUM(coalesce(dp.price, d.price)), o.*
from orders o JOIN deals d ON d.ID = o.deal_id
LEFT JOIN order_products op on op.order_id = o.id
LEFT JOIN deal_products dp on op.product_id = dp.product_id
where o.user_id = 2002 and o.cancelled = 1
group by ...;
COALESCE function returns first not null operand
LEFT [OUTER] JOIN = [INNER] JOIN + all rows of the structure on the left side of the LEFT JOIN keyword, which don't match the ON clause in the right structure.

MySQL Join table and count distinct users with no reference in another table

I am trying to count users that are NOT referenced in another table... Right now, I have something along the lines of this:
SELECT COUNT(DISTINCT u.id) FROM users u INNER JOIN orders o ON o.assigned!=u.id;
However, it's returning an invalid value. Any suggestions?
Thank you!
I would suggest using a LEFT JOIN between the two tables and filter the rows without a matching id in the orders table:
select count(u.id)
from users u
left join orders o
on o.assigned = u.id
where o.assigned is null
See SQL Fiddle with Demo
Use a left join and count the rows with no match:
SELECT COUNT(*)
FROM users u
LEFT JOIN orders o
ON o.assigned = u.id
WHERE o.assigned IS NULL
An alternative is to use a NOT IN check:
SELECT COUNT(*)
FROM users
WHERE id NOT IN (SELECT distinct(assigned) FROM orders)
However, in my experience the left join performs better (assuming appropriate indexes).
Simply use this query, assuming that the id is unique in users table:
select count(*) From Users as u where u.id not in (select assigned from orders)
an inner join explicitly looks for rows that match so that isn't the way to go if you are looking for non matched records
assuming that ORDERS.ASSIGNED is matched with USER.ID an outer join could return values from both and show when there aren't matches like so
select
u.id,
o.*
from users u
full outer join orders o
on o.assigned = u.id;
if you only want to know which USER.ID don't have an ORDERS record you could also INTERSECT or use NOT IN () eg
select u.id from users u where id not in (select o.assigned from orders.o);
SELECT COUNT(1) FROM users u
WHERE NOT EXISTS (SELECT * FROM orders o WHERE o.assigned=u.id);
Are you wanting a straight count (like you mentioned), or do you need values returned? This will give you the count; if you want other values, you should take one of the other approaches listed above.

Select rows that are referenced in another table

I have two tables and they are as follows:
USERS
ORDERS
I want select all users who have at least 1 order or more in the ORDERS table. I know there is an inline query for this in MySQL, but right now I have to select all users and then make another query seeing if each user has an order - all this using a PHP loop.
What I am doing now is not ethically correct, so I basically just want to select all users who have been referenced in the ORDERS table in ONE MySQL query.
This is a query you should be using
select distinct u.* from users u
inner join orders o on o.user_id = u.id;
Note the distinct and u.*. This query will not select fields from orders and it will not select the same user twice (if one has more than one order).
Demo: http://sqlfiddle.com/#!2/6ebcc/3
You can use mysql join syntax. Assuming both of your tables has userid column, this is the example :
SELECT * FROM USERS a JOIN ORDERS b ON
a.UserId = b.UserId
This is a simple database operation, see here for the explanation join

MySQL Queries and 2 separate tables

So I have 2 tables in a MySQL database, one for "Users" and the other for "Orders", where each entry in Orders is an order placed by a User (Some users can have multiple orders, while some might not have any). I am working on reporting queries and one of the reports I want is a list of Users that have never placed any orders. I am still a bit of a beginner when it comes to MySQL queries, so I am not sure how to do this one. The query will be placed via PHP if that makes any difference.
Here are my columns in each table (simplified):
Users:
ID
Name
Orders:
OrderID
OrderName
CustomerID (corresponds to User.ID that placed the order)
Any help here would be great. Thanks!
Use a LEFT JOIN on Orders and check whether OrderId is null:
SELECT U.*
FROM
Users U
LEFT JOIN Orders O ON(U.ID = O.CustomerID)
WHERE
O.OrderId IS NULL
SQLFiddle
SELECT ID, Name
FROM users
WHERE ID NOT IN (SELECT DISTINCT customerID FROM Orders)
So basically you'are looking for orders that are not made by that user
Select * from Orders where CustomerID = 5 //5 is the id of the custumer
If you are doing a search by name
Select * from Orders LEFT JOIN Users on Users.ID Where Users.name ='Mark'
If no results, it mean that customer never ordered anything
Try
SELECT U.*
FROM Orders a
RIGHT JOIN Users b
ON b.ID = a.CustomerID
WHERE a.OrderId IS NULL