Count and group by join - mysql

I have a table for products and a table for users who have bought products. On the products table A there is site_name which determines where the products were bought.
Table B shows the users and what they have bought.
I am using the following to show a list of products bought, by site_name, grouping the product name together.
SELECT product FROM A JOIN B ON A.prod_id = B.prod_id WHERE A.site_name = 'ebay' group by A.product
Table A for products is:
prod_id
site_name
product
Table B for users is:
user_id
prod_id
What i can't figure out is how to get the number of products bought per line.
e.g. in table A there is
prod_id site_name product
------- --------- -------
1 ebay chair
2 amazon desk
3 ebay lamp
and on table b
user_id prod_id
------- -------
1000 1
1001 2
1002 1
1003 3
So I want to show each line where site_name is ebay and how many products were bought, order by most first like:
chair 2
lamp 1

I would use a LEFT JOIN, so that if there is a product that has never been purchased, it will show up with a count of 0.
Also, I would use COUNT(users.prod_id), instead of COUNT(*), so that it will only count rows which have satisfied the LEFT JOIN condition:
SELECT
products.product,
COUNT(users.prod_id) AS productsBought
FROM
A AS products
LEFT JOIN B AS users
ON products.prod_id = users.prod_id
WHERE products.site_name = 'ebay'
GROUP BY products.product

A minor change to Michael's query.
SELECT
products.product,
COUNT(users.prod_id) AS productsBought
FROM
A AS products
INNER JOIN B AS users
ON products.prod_id = users.prod_id
WHERE products.site_name = 'ebay'
GROUP BY products.product
The above query will not return products that haven't been bought.

Related

SQL - Counting how many associated records another table has

As I'm SQL beginner, I can't describe a problem in a simple way, so let me show you an example:
3 Tables:
PRODUCT
id
group_id
person_id
GROUP
id
name
PERSON
id
group_id
As you see, GROUP can have multiple PERSONs and PRODUCT can be connected with GROUP and PERSON.
From this point, I would like to count number of PERSONs having a PRODUCT within a GROUP
I don't really understand the background of IN or using another SELECT within FROM, so if that's the point, then I'm happy that I was one step before it lol.
SELECT
group.name as GROUP_name,
COUNT(DISTINCT person_id) AS PERSON_having_min_one_PRODUCT
FROM products
LEFT JOIN groups ON groups.id = products.group_id
LEFT JOIN persons ON persons.id = products.person_id;
With this data:
GROUP
ExampleGroupName1 has 3 PERSONs, but 2 of them has >0 PRODUCTS
ExampleGroupName2 has 3 PERSONs and all of them has >0 PRODUCTS
ExampleGroupName3 has 2 PERSONs, but none of them has the PRODUCT
ExampleGroupName4 has 2 PERSONs, but only 1 has >0 PRODUCT
I would like to have an output like this:
GROUP_name | PERSON_having_min_one_PRODUCT
ExampleGroupName1 | 2
ExampleGroupName2 | 3
ExampleGroupName4 | 1
I would like to count number of PERSONs having a PRODUCT within a GROUP
Note: I will assume the table product does not have the column group_id, since it is redundant and can lead to a lot of errors.
The following query will show you the result you want by joining the tables person and product:
select
count(distinct x.id)
from person x
join product p on p.person_id = x.id
where x.group_id = 123 -- choosing a specific group
and p.id = 456 -- choosing a specific product
This would rather be simple like below meaning all the groups with some group_id with count(persons) and those count who has some product via id used in having clause
Select group_id,
count( distinct id ) AS "PERSON_WITH_PRODUCT"
from
person group by group_id having id
in (Select id from product);

How to Count multiple records with specific type

I want to filter different records based on its category type
I have two table as
product and product_detail
product
p_id p_name p_cat_id
1 computer1 101
1 computer2 101
2 mobile1 102
2 mobile2 102
2 mobile3 102
product_detail
cat_id cat_name cat_staus
101 computer active
102 mobile active
103 electronics active
I want to count following records based on category type
such as computer1 and computer2 with cat_id so output will be computer = 2
query:
SELECT product_id,cat_name,
COUNT(DISTINCT product_detail.cat_name) AS "my_product"
FROM product
INNER JOIN product_detail ON product.p_id = product_detail.cat_id
GROUP BY product_detail.cat_id
If I understand correctly, you want to count the number of products that have a certain type of category; that is: "For each category, show the name of that category and the number of products with that category"
In that case, use this:
SELECT cat_name,
COUNT(1) AS amount
FROM product
INNER JOIN product_detail ON product.p_id = product_detail.cat_id
GROUP BY product_detail.cat_id
The INNER JOIN will already create a list of all products in a category. The GROUP BY will let you see each category specifically. All you need is the COUNT of rows for each category.
SELECT product.p_cat_id,
product_detail.cat_name,
COUNT(DISTINCT product.p_name) AS "my_product_count"
FROM product
LEFT JOIN product_detail
ON product.p_cat_id = product_detail.cat_id
GROUP BY product.p_cat_id
query:
SELECT product_detail.cat_name,
COUNT(p_cat_id) AS "my_product"
FROM product
INNER JOIN product_detail ON product.p_cat_id = product_detail.cat_id
GROUP BY product_detail.cat_name

MYSQLQuery- How to create a query where we have to list out customers who have bought a specific number of album by the same singer

We have the following tables:
Customer:
customer_id (pk)
customer_name
customer_dob
adress
gender
Album:
Album_id (PK)
album_name
singer_id (FK)
Order_Details:
order_id (Pk)
quantity purchased
customer_id (fk)
Order_Basket:
Order_id (fk)
album_id (fk)
I want to create an SQL query statement where I want to list out customers that have purchased 4 or more albums by the same singer. I'm very new to this and I would like to seek input from the much more professional individuals here.
try this:
select customer.customer_id, album.singer_id , count(*)
from customer ,order_details, order_basket, album
where customer.customer_id = order_details.customer_id
and order_details.order_id = order_basket.order_id
and order_basket.album_id = album.Album_id
group by customer.customer_id, album.singer_id
having count(*) > 3
WITH PurchaseSummary AS (
SELECT d.customer_id, a.singer_id, count(a.album_id) AS album_count
FROM Order_Details d
LEFT JOIN Order_Basket b ON on b.Order_id = d.Order_id
LEFT JOIN Album a ON a.Album_id = b.album_id
GROUP BY d.customer_id, a.singer_id)
SELECT ps.customer_id, ps.singer_id, ps.album_count
FROM PurchaseSummary ps
LEFT JOIN Customer c ON c.customer_id = ps.customer_id
WHERE ps.album_count >= 4
ORDER BY d.customer_id
Use a subquery to look at all of your orders. Because an order may have more than one album, tack on the order_basket table. Now you have all orders with albums. Tack on the Album table and you have the artist name for each of the orders. Because you also have the customer ID, you can group the customer ID and singer ID with a count of the albums. The result will be like:
Customer|Artist|Num Albums
1 A 1
1 B 4
2 A 1
2 B 6
2 C 5
Then, you select your customer ID and artist ID from that table with your condition they have to have bought >=4 albums from that artist. Lastly, join the Customer table on to get further details about that customer. If you have an Artist table too, you can join that on the Artist ID to get things like name, etc.

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

Matching items in one table that don't match in a subset of a second table

Suppose I have a Product table, and a
id product
1 Apple
2 Bag
3 Cat
4 Ducati
and a Cart table
id user_id product_id
1 1 2
2 1 3
3 2 1
4 3 1
So, I want to look at a particular user and see what he/she does NOT have in their Cart.
In other words, in the above example
SELECT ...... WHERE user_id=1 .....
would return Apple and Ducati because User 1 already has Bag and Cat.
(This may well duplicate another question but there are so many variations I couldn't find the exact match and put in these simple terms may help)
Perform a left join from product to all products purchased by user1, which can be retrieved with a subselect in the join. This will cause all product id's that are not in user1's care to have null product ids. The where clause will select all null product id's meaning they will not have been in a users cart, essentially filtering purchased items.
select p.name
from product p
left join (select product_id, user_id
from cart where user_id = 1)
c
on p.id = c.product_id
where c.product_id is null;
SQL Fiddle: http://sqlfiddle.com/#!2/5318eb/17
Select
*
From Product p
Where p.id Not In
(
Select c.product_id
From Cart c
Where User ID = ____
)
SELECT product FROM product_table
WHERE product NOT IN
(SELECT product_id FROM cart_table WHERE user_id = 1);
This will give you all product for all users which are not in there cart.
select c.user_id,a.Product
from cart c Cross Join product a
left Join
cart b on b.product_id=a.id and c.user_id=b.user_Id
where b.product_id is null
group by c.user_id,a.Product
Sql Fiddle Demo