understanding sql left outer join - mysql

I've got the following tables:
Articles:
Nr Name Price
1011 DU 10
1012 DA 5
1013 DO 20
Clients
Nr Name Street Zip
123 John ... ...
234 Will ... ...
Orders
Nr Client_Nr Art_Nr Quantity
1 123 1011 1
2 123 1012 2
3 234 1012 2
4 234 1013 5
To know the total sum of orders per customer,
I use the following statement:
SELECT Clients.Name,
SUM(Orders.Quantity * Article.Price) AS "Total"
FROM Orders
LEFT OUTER JOIN Articles
ON Orders.Art_Nr = Articles.Nr
LEFT OUTER JOIN Clients
ON Orders.Client_Nr = Clients.Nr
GROUP BY Clients.Name;
Is left outer joins used when there are rows in one table that may not be referenced in the second table.
What is the better way of writing the above query?
Can I do this:
SELECT clients.name, SUM(orders.quantity * articles.price)
FROM orders
INNER JOIN articles ON orders.art_nr = articles.nr
INNER JOIN clients ON orders.client_nr = clients.nr
GROUP BY clients.name;

Related

MySQL Show results where not all conditions are met

I have three tables
Table A (orders)
order_number order_id
9999 123
Table B (order_items)
order_id product_id price
123 111 10
123 112 11
123 113 12
123 114 13
and Table C (product_customfields)
product_id customfield_id customfield_value
111 10 A
112 10 A
113 10 B
113 9 xyz
As a result I would like to get the product_id the price and in case a product has the customfield_id = 10 also the customfield_value
So in this case as a result I expect:
product_id price customfield_value
111 10 A
112 11 A
113 12 B
114 13 (empty)
In general my query looks like the following:
select B.product_id, B.price, C.customfield_value from orders A
left join order_items B on A.order_id=B.order_id
left join product_customfields C on B.product_id=C.product_id where A.order_number=9999 and C.customfield_id = 10
Of course the result will not show the product_id 114 because it has no customfield_id assigned in the database table with a value of "10"
Nevertheless could someone point me in the right direction how to build the query in a way to also show all products of the orders also if they are not assigned to a condition in the table.
Thank you
Does
select B.product_id, B.price, C.customfield_value from orders A
left join order_items B on A.order_id=B.order_id
left join product_customfields C on B.product_id=C.product_id
where A.order_number=9999 and (C.customfield_id = 10 or C.customfield_id IS NULL)
solves your issue?
You need a left outer join on the product_custom_fields like this
select B.product_id, B.price, C.customfield_value
from orders A
left join order_items B
on A.order_id=B.order_id
left outer join product_customfields C
on B.product_id=C.product_id
where A.order_number=9999 and
(C.customfield_id = 10 or C.customfield_id IS NULL)

Propel2; how to use querybuilder for subselect query

Problem:
I'm having trouble finding a solution building a query with QueryBuilder (perhaps getting it done with regular sql query first will help):
Trying to retrieve all customers for a user (has shop credits at one of the shops user is linked to), need the total credits (sum of credits at shops belonging to that user) as virtual column (to be able to order on), using paginate().
Database structure:
Table customers
id email other_fields
1 1#email.com f
2 2#email.com o
3 3#email.com o
Table users
id email other_fields
1 1#user.com b
2 2#user.com a
3 3#user.com r
Table shops
id name other_fields
1 Shop 1 m
2 Shop 1 o
3 Shop 1 o
Table user_shops
user_id shop_id
1 1
1 2
3 3
Table customer_shop_credits
customer_id shop_id credits
1 1 55
1 2 45
2 2 3
3 3 44
Expected result:
When retrieving customers for user 1, I'd expect to get back customer 1 with 100 credits and customer 2 with 3 credits
Closest I got:
$credits_query = CustomerShopCreditQuery::create()
->useShopQuery()
->useUserShopQuery()
->filterByUserId($user->getId())
->endUse()
->endUse()
;
$customers = CustomerQuery::create()
->addSelectQuery($credits_query, 'credits_alias', false)
->useCustomerShopCreditQuery()
->useShopQuery()
->useUserShopQuery()
->filterByUserId($user->getId())
->endUse()
->endUse()
->endUse()
->withColumn('sum(credits_alias.credits)', 'credits')
->groupById()
->orderBy($order_by_column, $direction)
->paginate($page, $page_size);
Which results in the following query:
SELECT customers.id, customers.email, sum(credits_alias.credits) AS credits
FROM customers
CROSS JOIN (
SELECT customer_shop_credits.id, customer_shop_credits.customer_id, customer_shop_credits.shop_id, customer_shop_credits.credits
FROM customer_shop_credits
INNER JOIN shops ON (customer_shop_credits.shop_id=shops.id)
INNER JOIN user_shops ON (shops.id=user_shops.shop_id)
WHERE user_shops.user_id=159
) AS credits_alias
INNER JOIN customer_shop_credits ON (customers.id=customer_shop_credits.customer_id)
INNER JOIN shops ON (customer_shop_credits.shop_id=shops.id)
INNER JOIN user_shops ON (shops.id=user_shops.shop_id)
WHERE user_shops.user_id=159
GROUP BY customers.id
ORDER BY customers.id DESC
LIMIT 25
But gives me results with wrong sum of credits.
Not to sure about the CROSS JOIN. When I edit this query and make it a JOIN and use ON (credits_alias.customer_id = customers.id) as a condition, the sum of credits is better, but seems to have the classic join problem of doubling the sum

Mysql query LEFT JOIN unexpected result

mysql SELECT query with left join is not producing the result I am expecting.
I hope someone can show me or point me to the right direction,
I am trying to build a query where I get all the users name from the "users" table and
fetch the sum of all the time they spent for a particular date from the master table. I've used the left join but I am not getting the result as expected.
SUM(m.time_spent) as sum_total_time
FROM master as m
LEFT OUTER JOIN users as u ON u.user_id = m.user_id
WHERE m.date_created >= '2016-05-09'
AND m.date_created <= '2016-05-13'
GROUP BY name
ORDER BY name
master table
master_id user_id time_spent date_created
1 1 40 2016-05-01
2 2 36 2016-05-02
3 3 56 2016-05-03
4 2 33 2016-05-03
5 1 32 2016-05-05
nth nth nth number nth date
users table
user_id first_name last_name
1 James Green
2 Robert Cox
3 Andy Roger
etc etc etc
I want the output result should look like this:
user_id Name sum_total_time
1 James Green 62
2 Robert Cox 69
3 Andy Roger 56
4 Brian Harper 0
5 Angel Lee 0
6 Andrew Martin 55
.....
.....
Nth Name Nth value
You have to select data directly from the master table, group by user and calculate the sum. Then you can join this result with the user table to get all the information about the user.
Could be date conversione issue ..
SUM(m.time_spent) as sum_total_time
FROM master as m
LEFT OUTER JOIN users as u ON u.user_id = m.user_id
WHERE m.date_created >=STR_TO_DATE( '2016-05-09', '%Y-%m-%d)
and/or you have also incomplete sql
SUM(m.time_spent) as sum_total_time
FROM master as m
LEFT OUTER JOIN users as u ON u.user_id = m.user_id
WHERE m.date_created >= '2016-05-09'
AND m.date_created // this condition don't match with nothing..
// could be you forgot a part
Update 1
If you want user totale then
select u.id, u.name, SUM(m.time_spent) as sum_total_time
FROM master as m
Inner JOIN users as u ON u.user_id = m.user_id
WHERE m.date_created >=STR_TO_DATE( '2016-05-09', '%Y-%m-%d)
AND m.date_created <= =STR_TO_DATE('2016-05-13'', '%Y-%m-%d)
Group by u.id

Many-to-Many Select

I have 3 tables:
users:
id name
1 Jack
2 Vasya
3 John
4 Robert
5 Dmitry
6 Dylan
cities:
id city
1 London
2 Kyiv
3 New-York
4 Chicago
5 Moscow
6 Dubai
users_cities:
user_id city_id
1 1
3 1
5 6
2 3
4 5
6 6
I need to select users with Jack in London by Jack's id(users.id = 1) or users in Dubai with Dmitry(users.id = 5) using JOIN.
How could I do it?
What I have tried:
SELECT `u`.`username`, `uc`.`city_id` FROM `users` as `u`
INNER JOIN `users_cities` as `uc` ON `u`.`id` = `uc`.`user_id`
INNER JOIN `users_cities` as `uc1` ON `uc1`.`city_id` = `uc`.`city_id`
WHERE `u`.`id` = 1
It returns:
username city_id
Jack 1
Jack 1
You're so very close. You only need to JOIN to user_cities once for your query. Then use the WHERE clause to determine the users or cities you wish to filter on.
If you want the city name in the result set then make an additional join from user_cities to cities.
As you are joining twice on the same result set (user_cities) you are effectively querying that result twice, which is why you are getting duplicate 'Jacks'.
If this is not exactly what you need, then adjust your WHERE clause to determine how you would like to filter the result set.
SELECT
u.username,
c.city
FROM
users as u
INNER JOIN users_cities as uc ON u.id = uc.user_id
INNER JOIN cities as c ON uc.city_id = c.id
WHERE
u.id = 1 -- Jack
OR u.id = 5 -- Dimitry

MySQL multiple inner join not returning rows

I'm trying to create a query which selects from three tables.
m_release
---------------------------
release_id name
---------------------------
1 release1
2 release2
3 release3
mk_release_artist
---------------------------
release_id artist_id
---------------------------
1 134
2 135
mk_release_remix
---------------------------
release_id artist_id
---------------------------
3 134
I've created the following query so far, but it doesn't return any rows:
SELECT * FROM m_release A
JOIN mk_release_artist B ON A.release_id = B.release_id AND B.artist_id = 134
JOIN mk_release_remix C ON A.release_id = C.release_id AND C.artist_id = 134
It is working when i'm selecting from two tables using one JOIN
SELECT * FROM m_release A
JOIN mk_release_artist B ON A.release_id = B.release_id AND B.artist_id = 134
The output i'm expecting to see is:
---------------------------
release_id name
---------------------------
1 release1
3 release3
SELECT A.*
FROM m_release A
LEFT JOIN mk_release_artist B ON A.release_id = B.release_id
LEFT JOIN mk_release_remix C ON A.release_id = C.release_id
WHERE 134 in (B.artist_id, C.artist_id)
So, in B, author_id is the author, while in C, it's the remixer. Then your query selects entries where BOTH the author and the remixer are the id=134. Which has no matching entries in your example.
The juergen d's query would select entries where either author or the remixer is the id. Since it uses LEFT JOINs, it will even get the releases that have no corresponding entry in either B or C (the corresponding columns will be NULL).