LEFT OUTER JOIN with INNER JOIN to Equal Total Rows - mysql

I have a Producer and Product table. I'm trying to write 2 queries, Producers that have Products and Producers that don't have Products.
The rows returned from each Query should add up to the total rows in the Producer Table, but this is not the case with my code. The sum of both queries is 819 but there are only 766 rows in the Producer table. Where are the duplicates coming from?
What am I doing wrong with my JOINs?
PRODUCER TABLE
+------+--------+------+------+
| producerID | producerName |
+------+--------+------+------+
| 123 | Toys R Us |
| 234 | GameStop |
| 345 | Amazon |
+------+--------+------+------+
PRODUCT TABLE
+------+--------+------+--------+------+
| productID | productName | producerID |
+------+--------+------+--------+------+
| 1 | Mega Man | 123 |
| 2 | Lemmings | 234 |
| 3 | Mario Kart | 234 |
+------+--------+------+--------+------+
/*STORES CARRYING Products*/
/*This query returns 169*/
SELECT producerName, pt.producerID, productName
FROM Product pt
INNER JOIN Producer pd ON pt.producerID = pd.producerID
/*STORES NOT CARRYING Products*/
/*This query returns 650 */
SELECT producerName, pt.producerID, productName
FROM Producer pd
LEFT OUTER JOIN Product pt ON pt.producerID = pd.producerID
WHERE pt.producerID IS NULL
/*Count all rows returns 766*/
SELECT COUNT(*) FROM Producer

Instead of using a Join, you could use a Subquery.
For example, this query would return all the producers that have a product.
SELECT *
FROM Producer
WHERE producerID IN (SELECT producerID FROM Products)
And this query would return all the producers that do not have a product.
SELECT *
FROM Producer
WHERE producerID NOT IN (SELECT producerID FROM Products)

Related

Displaying Latest Record and Join Multiple table

how do I join multiple tables and displaying each users sold item, display the latest record who sold the items
I need output like this
Sold by:
"jon" item "#1" "book" with a price of "1000"
tried :
SELECT uid , users.name AS uname, transact.transaction_id AS transacted INNER JOIN users on transaction_table.c_id=c_table.c_id
User table
--------------------------
| uid | name | timezone |
--------------------------
| 1 | jon | +1 gmt |
| 2 | mix | +2 gmt |
| 3 | vic | +1 gmt |
--------------------------
transaction table
-------------------------------
| transaction_id | uid | c_id |
-------------------------------
| dafsf22sdfssgs | 2 | 1 |
| 23425asda3afaa | 1 | 1 |
-------------------------------
C-table
------------------------
| c_id | c_name | price |
------------------------
| 1 | book | 1000 |
| 2 | comic | 100 |
| 3 | notes | 10 |
-------------------------
If you want to group by item name and get the total
select u.name,count(*) as count, c.c_name, c.price*count(*) as totalPrice from user u
inner join transaction t on u.uid=t.uid
inner join ctable c on c.c_id=t.c_id
group by c.c_name
If you want to query all the transactions
select u.name, c.c_name, c.price from user u
inner join transaction t on u.uid=t.uid
inner join ctable c on c.c_id=t.c_id
If you just want to return the last transaction info
select u.name, c.c_name, c.price from user u
inner join transaction t on u.uid=t.uid
inner join ctable c on c.c_id=t.c_id
order by t.transaction_id desc limit 1
And one more thing. It is a much much more better practice if your field names are consistent.

MySQL - Selecting Duplicates across 3 columns and joining with another table to filter

I have a Purchases table, where I'm trying to select all rows where first name, surname and email are duplicates (for all 3).
Purchases table:
| purchase_id | product_id | user_id | firstname | surname | email |
| ------------- | -----------| ------------- | ----------- | --------- | ----------- |
| 1 | 1 | 777 | Sally | Smith | s#gmail.com |
| 2 | 2 | 777 | Sally | Smith | s#gmail.com |
| 3 | 3 | 777 | Sally | Smith | s#gmail.com |
| 4 | 1 | 888 | Bob | Smith | b#gmail.com |
Further to this, each product ID corresponds to a product type in a 'Products' table, and I'm trying to filter by 'lawnmower' purchases (so only product ID 1 & 2)
Products table:
| product_type | product_id |
| ------------- | -----------|
| lawnmower | 1 |
| lawnmower | 2 |
| leafblower | 3 |
I'm hoping to write a query that will return all purchases of the 'lawnmower' type where first name, last name, and email are duplicates (so would return the first two rows of the Purchases table).
This is where my query is at so far, however it's not returning accurate data (e.g. I know I have around 350 duplicates and it's returning 10,000 rows):
SELECT t. *
FROM database_name.purchases t
JOIN (
SELECT firstname, surname, email, count( * ) AS NumDuplicates
FROM database_name.purchases
GROUP BY firstname, surname, email
HAVING NumDuplicates >1
)tsum ON t.firstname = tsum.firstname
AND t.surname = tsum.surname
AND t.email = tsum.email
INNER JOIN database_name.products p2 ON t.product_id = p2.product_id
WHERE p2.product_type = 'lawnmower'
Just wanting to know what I need to tweak in my query syntax.
You know that you should be returning Sally Smith. Create a table from the results of your query above. Then Select * from that table where first_name=sally and surname=Smith. See if you can figure out where you are going wrong based on that. This will help you debug these type of issues yourself in the future.
Your inner SELECT does not filter on the product type. It gets all customers who have purchased any two items. Then you join it to purchases and therefore also get the purchases of customers who have bought any two items and, possibly only one, lawnmower. Add a filter on the product type in the subquery too:
SELECT t.*
FROM database_name.purchases t
INNER JOIN (SELECT purchases.userid
FROM database_name.purchases
INNER JOIN database_name.products
ON products.product_id = purchases.product_id
WHERE products.product_type = 'lawnmower'
GROUP BY userid
HAVING count(*) > 1) s
ON t.user_id = s.user_id
INNER JOIN database_name.products p
ON t.product_id = p.product_id
WHERE p.product_type = 'lawnmower';
Your schema also is problematic -- denormalised. firstname, surname and email depend on user_id (Note that I only grouped and joined using the user_id, that's enough,). So they shouldn't be in purchases, only user_id. product_type better by an ID referencing to some product type table too.

SQL query for overview of purchased products per user

I have three tables: User, Product and Purchase
User: id, email
Product: id, name
Purchase: user_id, product_id, transaction_id
The idea is that I can find out for any given user which products he has purchased so that (in my view) I can loop over all the products and indicate which ones have been purchased already by that user. For the purchased products, I would present 'watch this product', for all other I want to display 'purchase this product'.
Right now I'm using the following query, this is to retrieve the list of products for a given user
select p1.product_id as id, p2.name, p2.price, u1.id as user_id, p1.stripe_transaction_id
from users u1
right join purchases p1 on u1.id = p1.user_id and u1.id = <user_id>
right join products p2 on p1.product_id = p2.id
Based on this, I get the following:
+------+---------------------+-------+---------+-----------------------+
| id | name | price | user_id | stripe_transaction_id |
+------+---------------------+-------+---------+-----------------------+
| 100 | Product 1 | 1999 | 3 | _jbshvScW_8961 |
| 100 | Product 1 | 1999 | NULL | _zrtdXU_6811 |
| 101 | Product 2 | 1999 | 3 | _zvgvKS_2536 |
| 102 | Product 3 | 1999 | NULL | _asgvMP_6811 |
| 103 | Bundle all products | 4999 | NULL | _bffgMXX_6811 |
+------+---------------------+-------+---------+-----------------------+
The problem with this query is that it is giving me back multiple entries for product_id (if more people have purchased that product is will display a line with product_id and user_id is NULL). In this particular example, another user has also purchased product with id 100.
Ideally I get to the following (per user):
+------+---------------------+-------+-----------+-----------------------+
| id | name | price | purchased | stripe_transaction_id |
+------+---------------------+-------+-----------+-----------------------+
| 100 | Product 1 | 1999 | false | _zrtdXU_6811 |
| 101 | Product 2 | 1999 | true | _zvgvKS_2536 |
| 102 | Product 3 | 1999 | false | _asgvMP_6811 |
| 103 | Bundle all products | 4999 | false | _bffgMXX_6811 |
+------+---------------------+-------+-----------+-----------------------+
Been trying already a while but not getting there. Any help is appreciated!
As I understand, you want to input a user_id and get an output of every product they could have purchased, and if they did.
If that's so, you could CROSS JOIN users to products, then fill-in purchase data from purchases. But CROSS JOINs are dangerous and easy to muck up, so I avoid.
Instead, why not just use product data and fill in with purchase data?
SELECT
p.id as product_id
,p.name
,p.price
,r.stripe_data
FROM products p
LEFT JOIN purchases r ON p.id = r.product_id AND r.user_id = <your user>
This assumes a user can only purchase a product once though.
You can use a nested query, rather than the right join, like the following:
select * from products where product_id in (select product_id from purchase where user_id = <user_id>)
You can also customize the resulted view as you like to get the prices and the other data.
select prod.product_id as id, prod.product_name as name, prod.price as price,
case when u.user_id is null then 'false' else 'true' end as pruchased,p.transcation_id
from products prod left join purchases p on p.product_id=prod.product_id
left join users u on u.user_id = p.user_id and u.user_id=101;

SQL Join vs Sub-query

I'm running MySQL 5.1.71. In my database there are three tables - load, brass and mfg with load being my "main" table. My goal is to query load and have mfg.name included in the results. I've tried various iterations of JOIN clauses vs sub-queries both with and without WHERE clauses. It seems this should be pretty trivial so I'm not sure how I can't arrive at the solution.
load
-------------------------
| id | desc | brass_id |
-------------------------
| 1 | One | 2 |
| 2 | Two | 1 |
-------------------------
brass
---------------
| id | mfg_id |
---------------
| 1 | 6 |
| 2 | 8 |
---------------
brass_mfg
------------------------
| id | name |
------------------------
| 6 | This Company |
| 8 | That Company |
------------------------
My desired results would be...
results
---------------------------
| load | mfg |
---------------------------
| One | That Company |
| Two | This Company |
---------------------------
A load ID will always have only a single brass ID
A brass ID will always have only a single mfg ID
EDIT
The previously provided sample data (above) has been updated. Also, below are the query I'm running and the results I'm getting. The company is wrong in each record that is returned. I've included in the query and the results the IDs across the tables. The company names that appear are not the names in for the IDs in the mfg table.
SELECT
load.id AS "load.id",
load.brass_id AS "load.brass_id",
brass.id AS "brass.id",
brass.mfg_id AS "brass.mfg_id",
brass_mfg.id AS "brass_mfg.id",
brass_mfg.name AS "brass_mfg.name"
FROM `load`
LEFT JOIN brass ON load.brass_id = brass.id
LEFT JOIN brass_mfg ON brass.id = brass_mfg.id
-----------------------------------------------------------------------------------------
| load.id | load.brass_id | brass.id | brass.mfg_id | brass_mfg.id | brass_mfg.name |
-----------------------------------------------------------------------------------------
| 1 | 2 | 2 | 6 | 2 | Wrong Company |
| 2 | 1 | 1 | 8 | 1 | Incorrect Company |
-----------------------------------------------------------------------------------------
Look at your tables and see what data relates to one another then build up joins table by table to get your desired output.
SELECT p.desc AS Product, m.name AS mfg
FROM product p
INNER JOIN lot l ON p.lot_id = l.id
INNER JOIN mfg m ON l.mfg_id = m.id
If this is single - single relationship, why having middle table?
In your case the best scenario is simple join.
SELECT pt.desc as Product, mfg.name as Mfs
FROM Product pt
Join Lot lt on lt.id = pt.lot_id
Join Mfg mf on mf.id = lt.mfg_id
You have an error in your join query.
Try this one:
Select
l.id AS "load.id",
l.brass_id AS "load.brass_id",
b.id AS "brass.id",
b.mfg_id AS "brass.mfg_id",
m.id AS "brass_mfg.id",
m.`name` AS "brass_mfg.name"
FROM `load` as l
LEFT JOIN brass as b ON l.brass_id = b.id
LEFT JOIN brass_mfg as m ON b.mfg_id = m.id
You need LEFT JOIN only

MYSQL SELECT on two tables with MIN Value

I have two tables, one is a products table, and the other is an offers table for different vendors offering the same product.
Table1:
sku name
----|-----
a | Iphone
b | Galaxy 5
c | Nexus 6
Table2:
sku price vendor
----|-------|--------
a | 5.00 | storeX
a | 6.00 | storeY
a | 7.00 | storeZ
b | 15.00 | storeP
b | 20.00 | storeQ
b | 30.00 | storeR
c | 11.00 | storeD
c | 12.00 | storeF
c | 13.00 | storeG
I am trying to run a SELECT on these tables so I can get the lowest offer for each item. So my result would be:
sku price vendor
----|--------|--------
a | 5.00 | storeX
b | 15.00 | storeP
c | 11.00 | stored
I have tried SELECT table1.sku,table2.price FROM table2 JOIN table1 ON table2.sku = table1.sku WHERE table2.sku IN ('a','b','c');
But that just give me all offers. Any help with this query is appreciated.
You need two queries: one to determine the min price per product, and then a parent query to select the other fields related to that min price:
SELECT table2.*, table1.name
FROM table2
LEFT JOIN (
SELECT MIN(price) AS min, sku
FROM table2
GROUP BY sku
) AS child ON ((table2.price = child.min) AND (table2.sku = child.sku))
LEFT JOIN table1 ON (table2.sku = table1.sku)
This also has the advantage of showing if multiple stores have the same minimum price.