Select things from three different tables with inner join - mysql

Well, I have three tables:
Cart:
ID | Product | Quantity
1 S1FG 3
1 C0K0 1
1 SLM1 6
2 S1FG 2
2 S94A 2
Products:
Code | Price
S1FG 10.00
C0K0 8.00
SLM1 19.50
S94A 2.00
And Users:
ID | Nickname
1 Mark
2 Steve
I want this:
Nickname | Products | Total
Mark 10 155.00
Steve 4 24.00
In words, I want a list of users that has something in Cart, a count of their items and a sum of the prices of their items.
I tried this:
SELECT DISTINCT b.Nickname, SUM(a.Quantity) as Products, SUM(a.Quantity*c.Price) as Total
FROM Cart a
INNER JOIN Users b ON (a.ID = b.ID)
INNER JOIN Products c ON (a.Product = c.Code)
But it didn't work...
What can I do?

You need to GROUP BY the nickname or you'll just get a single line:
SELECT DISTINCT b.Nickname, SUM(a.Quantity) as Products, SUM(a.Quantity*c.Price) as Total
FROM Cart a
INNER JOIN Users b ON (a.ID = b.ID)
INNER JOIN Products c ON (a.Product = c.Code)
GROUP BY b.Nickname

Related

SQL Filter products from one table basing on attributes from second one

So I have table with products
id | product_name
1 | Product 1
2 | Product 2
3 | Product 3
... table with atributtes:
id | attribute
1 | big
2 | orange
3 | expensive
and table with products and their attributes
id | product_id | attribute_id
1 | 1 | 1
2 | 1 | 2
3 | 2 | 3
4 | 3 | 2
and what I want is to filter big, orange products.. in this case: Product 1
Something like:
SELECT product_name
FROM products as a
JOIN products_attributes as b ON a.id=b.product_id
WHERE b.attribute_id = 1 OR b.attribute_id=2
will not work as it returns Product 3 as well..
This doesn't work too, of course:
SELECT product_name
FROM products as a
JOIN products_attributes as b ON a.id=b.product_id
WHERE b.attribute_id = 1 AND b.attribute_id=2
Please help :)
You need to add atributtes table into your SELECT statement and
filter by attribute IN ( 'big','orange' )
GROUPing with HAVING clause should be added to satisfy the both conditions at the same time
SELECT p.product_name
FROM products as p
JOIN products_attributes as pa
ON p.id = pa.product_id
JOIN attributes a
ON a.id = pa.attribute_id
WHERE a.attribute IN ( 'big','orange' )
GROUP BY p.product_name
HAVING COUNT(DISTINCT a.attribute) = 2
using IN rather than OR operator is more straightforward to use .
Demo
In order to find products that have multiple attributes, first we need to join the attributes table with itself:
SELECT pa1.product_id FROM products_attributes as pa1
JOIN products_attributes as pa2 ON pa1.product_id = pa2.product_id
AND pa1.attribute_id = 1 AND pa2.attribute_id = 2
This will output 1, which is the correct id. Note that it doesn't matter which of the two tables you will select the product_id from, since you're joining it with itself and both will contain it.
Now all we need is the name, so we're going to join the products table as well and change our selection:
SELECT p.product_name FROM products p
JOIN products_attributes as pa1 ON pa1.product_id = p.id
JOIN products_attributes as pa2 ON pa1.product_id = pa2.product_id
AND pa1.attribute_id = 1 AND pa2.attribute_id = 2
This should output "Product1".

Query on two tables merged with same column names

I have these tables in my MySQL database:
BUYERS
ID|SELLER
----------------
0 |Paul
1 |Jean
2 |David
3 |Jack
4 |John
5 |Fred
6 |Peter
PARIS
ID|CAR
---------
0 |Toyota
1 |BMW
2 |Honda
LONDON
ID|CAR
---------
3 |Ford
4 |BMW
5 |Honda
6 |Honda
I use the followinq query :
SELECT b.id, b.seller, p.car
FROM buyers b
JOIN paris p
ON b.id = p.id
UNION ALL
SELECT b.id, b.seller, l.car
FROM buyers b
JOIN london l
ON g.id = l.id;
To get the following result :
ID|SELLER |CAR
----------------
0 |Paul |Toyota
1 |Jean |BMW
2 |David |Honda
3 |Jack |Ford
4 |John |BMW
5 |Fred |Honda
6 |Peter |Honda
I wanted to retrieve rows with "Honda" as "CAR" and I Tried to append the query with "Where car = 'Honda'" but without success..
Thanks for any help
Adding
WHERE car = 'Honda';
to your query only refers to the second query, i.e. the one after UNION ALL.
So either:
SELECT b.id, b.seller, p.car FROM buyers b JOIN paris p ON b.id = p.id
WHERE p.car = 'Honda'
UNION ALL
SELECT b.id, b.seller, l.car FROM buyers b JOIN london l ON b.id = l.id
WHERE p.car = 'Honda'
;
or
SELECT id, seller, car
FROM
(
SELECT b.id, b.seller, p.car FROM buyers b JOIN paris p ON b.id = p.id
UNION ALL
SELECT b.id, b.seller, l.car FROM buyers b JOIN london l ON b.id = l.id
) data
WHERE car = 'Honda';
Just appending WHERE car = 'Honda' is ambiguous. Which car column should be checked?
The easiest way to achieve this is to wrap your existing query within another select statement so that the query is applied on the resulting table, i.e.
SELECT * FROM
(
SELECT b.id, b.seller, p.car
FROM buyers b
JOIN paris p
ON b.id = p.id
UNION ALL
SELECT b.id, b.seller, l.car
FROM buyers b
JOIN london l
ON g.id = l.id;
)
WHERE car = 'Honda'
Can you please try below query:
select * from (
SELECT b.id, b.seller, p.car
FROM buyers b
JOIN paris p
ON b.id = p.id
UNION ALL
SELECT b.id, b.seller, l.car
FROM buyers b
JOIN london l
ON g.id = l.id;
)
where car = 'HONDA'
This is not an answer, but mere advice.
Just in case this is your real database (I'm pretty sure it isn't), here is some advice:
The table names tell us what entities you are dealing with. In your database this is buyers, parises, and londons. You probably see your mistake ;-)
Then looking into the buyers table we see the main column is called seller. What the heck? Is it buyer or seller?
Then a column called ID should be the table's ID and uniquely identify a record in the table. You, however, are using the buyers IDs in other tables and still call them ID.
In your example each buyer has only one other record either in London or in Paris. If this is the case, then you can simply make the car a column in the buyers table instead. If you do need an n:m relation, then call the IDs by what they are, i.e. buyer_id or the like.
In any case there should be a car table containing one record per car, in order to avoid misspellings like 'Homda' in some records.
You are showing car brands, but call the table cars. If it's really about brands only, a better name would hence be brands or car_brands or the like.
Here is an example on how to design the database:
Cars
id_car | name
-------+-------
1 | BMW
2 | Ford
3 | Honda
4 | Toyota
Sellers
id_seller | name
----------+------
0 | Paul
1 | Jean
2 | David
3 | Jack
4 | John
5 | Fred
6 | Peter
Sellers_Cars
id_seller | id_car
----------+-------
0 | 1
0 | 2
0 | 4
1 | 1
2 | 3
3 | 2
4 | 1
5 | 3
6 | 3
6 | 4
A possible query:
select name as honda_seller
from sellers
where id_seller in
(
select id_seller
from sellers_cars
where car_id = (select car_id from cars where name = 'Honda')
);

How to select rows, which have all or none corresponding values in another table?

I'm not sure I phrased the question correctly, so feel free to correct me. Here are the tables with their data:
product category category_product
------- -------- ----------------
id_product id_category active id_category id_product
1 1 1 1 1
2 2 1 2 1
3 3 0 1 2
4 0 2 2
3 2
3 3
4 3
I need to select only those products, which have all categories as inactive.
For example:
Product 1 is good, since it belongs to active categories (1, 2).
Product 2 is good, since it has at least one active category (1, 2; 3 - inactive)
Product 3 must be selected, since all its categories are inactive (3, 4).
I have the following query, which is obviously incorrect, since it selects both products: 2 and 3:
SELECT p.id_product
FROM product p
JOIN category_product cp
ON p.id_product = cp.id_product
JOIN category c
ON c.id_category = cp.id_category
WHERE
c.active = 0;
Here is the SQL Fiddle: http://sqlfiddle.com/#!2/909dd/2/0
How can I solve this?
This way you can select product without active category.
SELECT p.id_product
FROM product p
WHERE NOT EXISTS
(SELECT * FROM
category_product cp
INNER JOIN category c ON c.id_category = cp.id_category
WHERE p.id_product = cp.id_product AND c.active = 1);
SQL Fiddle
Consider the following:
SELECT p.*
, COUNT(*)
, SUM(c.active = 1) active
, SUM(c.active = 0) inactive
FROM product p
JOIN category_product cp
ON cp.id_product = p.id_product
JOIN category c
ON c.id_category = cp.id_category
GROUP
BY p.id_product;
+------------+----------+--------+----------+
| id_product | COUNT(*) | active | inactive |
+------------+----------+--------+----------+
| 1 | 2 | 2 | 0 |
| 2 | 3 | 2 | 1 |
| 3 | 2 | 0 | 2 |
+------------+----------+--------+----------+
http://sqlfiddle.com/#!2/909dd/55
The last part of this problem has been left as an exercise for the reader
This is what i get while trying...apologies if anything is wrong
set #count:=0;
select a.id_product,a.times from
(SELECT count(p.id_product)times, p.id_product, c.active,
if(c.active!=0, #count:=#count+1, #count:=0) x
From category_product cp
join product p
on (p.id_product = cp.id_product)
join category c
on(c.id_category = cp.id_category )
group by id_product )a
where a.x=0;

Duplicated Data When Joining 4 Tables in MySql [duplicate]

This question already has answers here:
Sum total of table with two related tables
(2 answers)
Closed 9 years ago.
I have 4 tables, with the relevant columns summarized here:
customers:
id
name
credits:
id
customer_id # ie customers.id
amount
sales:
id
customer_id # ie customers.id
sales_items:
id
sale_id # ie sales.id
price
discount
The idea is that customers lists all of our customers, credits lists each time they have paid us, sales lists each time they have bought things from us (but not what things they bought) and sales_items lists all of the items they bought at each of those sales. So you can see that credits and sales both relate back to customers, but sales_items only relates back to sales.
As an example dataset, consider:
customers:
id | name
5 | Carter
credits:
id | customer_id | amount
1 | 5 | 100
sales:
id | customer_id
3 | 5
sales_items:
id | sale_id | price | discount
7 | 3 | 5 | 0
8 | 3 | 0 | 0
9 | 3 | 10 | 0
I have tried this in MySQL:
SELECT c.*,
SUM( cr.amount ) AS paid,
SUM( i.price + i.discount ) AS bought
FROM customers AS c
LEFT JOIN sales AS s ON s.customer_id = c.id
LEFT JOIN sales_items AS i ON i.sale_id = s.id
LEFT JOIN credits AS cr ON cr.customer_id = c.id
WHERE c.id = 5
But it returns:
id | name | paid | bought
5 | Carter | 300 | 15
If I omit the SUM() functions, it returns:
id | name | paid | bought
5 | Carter | 100 | 5
5 | Carter | 100 | 0
5 | Carter | 100 | 15
So it looks like it's returning one row for every record matched in sales_items, but it's filling in the amount column with same value from credits each time. I see that this is happening, but I'm not understanding why it's happening.
So, two questions:
1. What is happening that it's smearing that one value through all of the rows?
2. What SQL can I throw at MySQL so that I can get this back:
id | name | paid | bought
5 | Carter | 100 | 15
I know that I could break it all up in subqueries, but is there a away to do it just with joins? I was hoping to learn a thing or two about joins as I tackled this problem. Thank you.
Edit: I created an SQL Fiddle for this: http://sqlfiddle.com/#!2/0051b/1/0
select distinct (c.id, c.name), sum(i.price+i.discount) AS bought, cr.amount AS paid
from customer c, credits cr, sales s, sales_items i
where s.customer_id = c.id
and i.sale_id = s.id
and cr.customer_id = c.id and c.id = 5
group by c.id, c.name;
I'm not very sure, but try this. Use group by; that is surely the solution.
Please try this
SELECT c.*,( SELECT SUM( cr.amount ) FROM customer c INNER JOIN credits cr ON
cr.customer_id = c.id WHERE c.id = 5 GROUP BY cr.id ) AS paid
,SUM( i.price + i.discount ) AS bought
FROM customers AS c INNER JOIN sales s ON s.customer_id = c.id
INNER JOIN sales_items i ON i.sale_id = s.id
INNER JOIN credits cr ON cr.customer_id = c.id
WHERE c.id = 5 GROUP BY s.id,cr.id

JOIN bills ON bills.item_id = cars.id

There are two tables:
TABLE bills
item_id | price
c1 | 10000
m1 | 9000
m2 | 8000
TABLE cars
id | model
1 | toyota
2 | bmw
I need JOIN both tables, where item_id=id AND the first letter in item_id is 'c', so I need to get: c1 | 10000 | 1 | toyota
select *
from cars c
join bills b on b.item_id = concat('c', c.id)
Note that performance is orders of magnitude better (and acceptable) joining in this order, because the calculation to generate the composite key is done once per car, rather than once per car/bill combination had I joined bills first then cars.
Do it like this:
select b.*, c.*
from bills b
inner join cars c on convert(substring(b.item_id, 2, 8000), int) = c.id
where b.item_id like 'c%'