MySQL : Find Count of Column joined from sum of different column - mysql

I have 2 tables:
table a
+----------+------------+------------+
|session_id| product_id | orders |
+----------+------------+------------+
| 1 | 11 | 0 |
| 1 | 22 | 2 |
| 1 | 34 | 1 |
| 2 | 11 | 0 |
| 3 | 43 | 0 |
| 3 | 11 | 1 |
+----------+------------+------------+
table b:
+-----------+--------------+
|product_id |category_id |
+-----------+--------------+
| 11 | 100 |
| 12 | 101 |
| 34 | 102 |
| 22 | 103 |
| 43 | 104 |
| 13 | 105 |
+-----------+--------------+
What I want is a table which consists of how many category_id were there in each session_id and also total orders placed in that session_id
+-----------+--------------------+--------+
|session_id | count(category_id) | orders |
+-----------+--------------------+--------+
| 1 | 3 | 3 |
| 2 | 1 | 0 |
| 3 | 2 | 1 |
+-----------+--------------------+--------+
I tried:
select a.session_id,count(b.category_id),sum(a.orders) from a
join table b
on a.product_id = b.product id
is this query right?
Please help me. I am a beginner

I tried with 2 methods
1)...SELECT a.session_id,COUNT(b.category_id),SUM(a.orders) FROM #a a
LEFT JOIN #b b
ON a.product_id = b.product_id GROUP BY a.session_id
GROUP BY a.Session_ID
2...) SELECT D.SESSION_ID,COUNT(CATEGORY_ID),SUM(D.ORDERS) FROM #A D
OUTER APPLY
(
SELECT CATEGORY_ID,PRODUCT_ID FROM #B B
WHERE D.PRODUCT_ID = B.PRODUCT_ID
) A
GROUP BY D.SESSION_ID
GO

Just use left join for showing all result from table A
by using only join its show the result exist in both table only.
SELECT a.session_id,COUNT(b.category_id),SUM(a.orders) FROM a
LEFT JOIN b
ON a.product_id = b.product_id GROUP BY a.`session_id`

Ofcourse you have t join tha tables, then group with the field you want.
SELECT a.Session_ID, Count(Category_ID) CategoryCount, SUM(Orders) NumberOfOrders
FROM a
LEFT OUTER JOIN b
ON a.Product_ID = b. Product ID
GROUP BY a.Session_ID
Personally, and since I don't have any info on the data structure I prefered using the LEft outer join since in case the product_id had no category, then no results of this product will show.
(unless each product should have a category, or the user needs only the products that has a category, you have to use the INNER JOIN)

Related

SQL - How can I JOIN two tables and SUM a column based on IDs between them?

I have two tables. One table is with master data
Table tbl1:
+-------------+------------+------------+
| ID | Name | Total |
+-------------+------------+------------+
| 1 | a | 10 |
| 2 | b | 5 |
| 3 | c | 4 |
| 4 | a | 4 |
+-------------+------------+------------+
Second table tbl2 contains child data. The key between tables is ID
Table tbl2:
+-------------+------------+
|id | qty |
+-------------+------------+
| 1 | 4 |
| 1 | 3 |
| 1 | 1 |
| 3 | 1 |
| 3 | 3 |
+-------------+------------+
I need to get output like this:
Output:
+-------------+------------+------------+
| name | sum_tot | sum_qty |
+-------------+------------+------------+
| a | 14 | 8 |
| b | 5 | 0 |
| c | 4 | 4 |
+-------------+------------+------------+
I had tried with this:
select tbl1.name, SUM(tbl1.total), SUM(tbl2.qty)
from tbl1
left join tbl2 ON tbl1.id = tbl2.id
GROUP by tbl1.name
The output that I get is:
Output:
+-------------+------------+------------+
| name | sum_tot | sum_qty |
+-------------+------------+------------+
| a | 34 | 8 |
| b | 5 |null |
| c | 8 | 4 |
+-------------+------------+------------+
Which is not correct.
Here is the sql fiddle:
The summary from first table is not in relation with second table. It seems that somehow query runs three times.
You can simply have a correlated sub-query that calculates the tbl2 sum:
select tbl1.name,
SUM(tbl1.total),
SUM(COALESCE((select SUM(tbl2.qty)
from tbl2
where tbl1.id = tbl2.id), 0)) as qty_tot
from tbl1
GROUP by tbl1.name
SELECT A.name, SUM(A.total) as sum_tot, COALESCE(B.sum_qty, 0) as sum_qty
FROM tbl1 A
LEFT JOIN (
SELECT id, SUM(qty) as sum_qty
FROM tbl2
GROUP BY id
) B ON B.id = A.id
GROUP BY A.name
select tbl1.name, SUM(tbl1.total), SUM(COALESCE(tbl2.qty, 0))
from tbl1
left join tbl2 ON tbl1.id = tbl2.id
GROUP by tbl1.name

show alternating rows in mysql

Let's say I have these tables:
tblPerson
id | name |
1 | A |
2 | B |
3 | C |
tblB
id | personId | loan |
1 | 1 | 100 |
2 | 1 | 50 |
3 | 2 | 25 |
tblC
id | personId | payment |
1 | 1 | 20 |
2 | 1 | 10 |
How do I produce this output:
Output
id | name | loan | payment | balance |
1 | A | 100 | 0 | 100 |
1 | A | 0 | 20 | 80 |
1 | A | 50 | 0 | 130 |
1 | A | 0 | 10 | 120 |
2 | B | 25 | 0 | 25 |
I need the output to sbow the loan first then the payment the loan again and so on.
This sort of query (http://sqlfiddle.com/#!2/759df4/3/0) will generate an interleaved set of loans and payments.
SELECT id,name,loan,payment
FROM (
SELECT p.id id,
p.name name,
0 type,
b.id detail_id,
b.loan loan,
0 payment
FROM person p
JOIN b ON p.id = b.personId
UNION ALL
SELECT p.id id,
p.name name,
1 type,
c.id detail_id,
0 loan,
c.payment payment
FROM person p
JOIN c ON p.id = c.personId
) q
ORDER BY id, detail_id, type
Then, I suppose you can use variables to generate the running totals. But Dr. Linoff is right (see his comment) that the dataset you've shown doesn't have enough information reliably to interleave loan and payment records. I've used ID fields to do this. The last ORDER BY really ought to mention posting_date or some other information instead of detail_id, if you have it elsewhere in your tables
try this:
select *, (sum(tb.loan) / sum(tc.payment)) as balance
from tblPerson tp
join tblB tb on tp.id = tb.personId
join tblC tc on tp.id = tc.personId
this is what comes to my head.

MySQL: how to transform this using INNER JOIN

Is it possible to write this query with INNER JOINs?
SELECT links.product_id AS entity_id, products.sku, links.`linked_product_id` AS linked_entity_id, products2.`sku` AS linked_skus
FROM catalog_product_entity AS products,
catalog_product_link AS links,
catalog_product_entity AS products2
WHERE links.`product_id` = products.`entity_id`
AND links.`linked_product_id` = products2.`entity_id`
Also, catalog_product_link has a column type_id, and I wanted to get only rows with type_id value 1 with AND catalog_product_link.type_id = 1 condition at the end, but it doesn't work. How do I go about getting only records with type_id=1?
I'm having a problem where when I add WHERE links.type_id=1 to the statement, the result comes out wrong. Everything under product_id is the same number (same entity_id/product_id), and everything under sku is NULL. linked_product_id and linked_skus are correct, though.
More information:
catalog_product_entity
| entity_id | sku | ... |
-------------------
| 1 | abc | |
| 2 | qwe | |
| 3 | yui | |
catalog_product_link
| product_id (same as entity_id) | linked_product_id | type_id |
----------------------------------------------------------------
| 1 | 5 | 1 |
| 1 | 6 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 1 |
| 3 | 2 | 1 |
| 3 | 4 | 1 |
Something like...
SELECT
p.sku,
l.product_id AS entity_id, l.linked_product_id AS linked_entity_id
FROM catalog_product_entity AS p
INNER JOIN catalog_product_link AS l
ON p.entity_id= l.product_id
WHERE l.type_id = 1
SELECT
links.product_id AS entity_id,
products.sku,
links.linked_product_id AS linked_entity_id,
products2.sku AS linked_skus
FROM catalog_product_link AS links
INNER JOIN
catalog_product_entity AS products ON products.entity_id = links.product_id
INNER JOIN
catalog_product_entity AS products2 ON products2.entity_id = links.linked_product_id
WHERE links.type_id = 1

mysql trying to get a count with a one to many tables

I have tables like
products product_attributes
================== ========================================
| id | name | | id | product_id | attribute | value |
================== ========================================
| 1 | product 1 | | 1 | 1 | min | 2 |
| 2 | product 2 | | 2 | 1 | max | 5 |
| 3 | product 3 | | 3 | 2 | min | 10 |
| 3 | product 3 | | 4 | 2 | max | 15 |
| .. | ... | | 5 | 3 | min | 1 |
================== | 6 | 3 | max | 100 |
| .. | ... | ... | ... |
========================================
I want to get all the products that fall within a range
I can successfully get a list of the ids that fall with-in the range using
SELECT p.id
FROM `products` p INNER JOIN `product_attributes` AS pa ON p.id = pa.product_id
WHERE pa.`min` <= 5 AND pa.`max` >= 5 GROUP BY p.id
This gives me a list of the ids that i need.
What i can not get to work is to get a TOTAL count of the ids instead of a list so i can not use the group by and then when i do that it messes up the count.
Is the only way to do this is by using the select above in a subselect and counting the
results?
Thanks
Given the structure above, where min and max are on different rows, I would use this:
select count(id) from (
select p.id
from
`products` p INNER JOIN `product_attributes` AS pa
ON p.id = pa.product_id
where (pa.attribute='min' and pa.value>=5) OR
(pa.attribute='max' and pa.value<=5)
group by p.id
having count(*)=2
) s
Just replace p.id with COUNT(1) in the query.
SELECT COUNT(1)
FROM `products` p
INNER JOIN `product_attributes` AS pa
ON p.id = pa.product_id
WHERE pa.`min` <= 5
AND pa.`max` >= 5
GROUP BY p.id
One approach is to apply the veneer of normalisation to the eav model before attempting to extract any information from it. In this case that might look like this:
SELECT product_id
, MAX(CASE WHEN attribute = 'min' THEN value END) `min`
, MAX(CASE WHEN attribute = 'max' THEN value END) `max`
FROM product_attributes
GROUP
BY product_id;
+------------+------+------+
| product_id | min | max |
+------------+------+------+
| 1 | 2 | 5 |
| 2 | 10 | 15 |
| 3 | 1 | 100 |
| ... | ... | ... |
+------------+------+------+
Now, what was your question again?
Try a select count(*) from your select statement.

Categorize the identical rows without repeating one-to-many relationship using LEFT JOIN

pardon my question title, I'm not sure what should I put it, I have these two tables as below.
products orders
+------+----------+ +--------+------+-------+
| id | name | | id | qty | pid |
+------+----------+ +--------+------+-------+
| 1 | mouse | | 10001 | 20 | 1 |
| 2 | keyboard | | 10002 | 15 | 3 |
| 3 | headset | | 10004 | 5 | 3 |
+------+----------+ | 10005 | 12 | 2 |
| 10006 | 18 | 1 |
+--------+------+-------+
This is the LEFT JOIN query I am using and the output
SELECT p.id AS No, p.name AS ProductName, o.qty AS Quantity
FROM products AS p
LEFT JOIN orders AS o ON p.id = o.pid
+------+-------------+----------+
| No | ProductName | Quantity |
+------+-------------+----------+
| 1 | mouse | 20 |
| 1 | mouse | 18 |
| 2 | keyboard | 12 |
| 3 | headset | 15 |
| 3 | headset | 5 |
+------+-------------+----------+
What I am trying to achieve is an output as below:
+------+-------------+----------+
| No | ProductName | Quantity |
+------+-------------+----------+
| 1 | mouse | 20 |
| | | 18 |
| 2 | keyboard | 12 |
| 3 | headset | 15 |
| | | 5 |
+------+-------------+----------+
My question is it possible to do so? Any reply and suggestions is greatly appreciate. Thanks.
P/S: I also have tried using the GROUP_CONCAT(qty SEPARATOR ",") but it returns the result in one row as I may have more additional column to add in the Orders table in the future and it will be difficult to read.
Sure, it's possible — and without needing to use variables:
SELECT IF(c.min_oid IS NOT NULL, a.id, NULL) AS No,
IF(c.min_oid IS NOT NULL, a.name, NULL) AS ProductName,
b.qty AS Quantity
FROM products a
JOIN orders b ON a.id = b.pid
LEFT JOIN (
SELECT MIN(id) AS min_oid
FROM orders
GROUP BY pid
) c ON b.id = c.min_oid
ORDER BY a.id,
b.id
Basically what it's doing is if the row is not the minimum order id of a particular product, display blank (NULL), otherwise display the information.
SQLFiddle Demo
In this case you can use MySQL variables. I store the previous product id in the variable #prev, and only if it changes we output the product name.
http://www.sqlfiddle.com/#!2/d5fd6/9
SET #prev := NULL;
SELECT
IF( #prev = p.id, NULL, p.id) AS No,
IF( #prev = p.id, NULL, p.name) AS ProductName,
o.qty AS Quantity
,#prev := p.id
FROM products AS p
LEFT JOIN orders AS o
ON p.id = o.pid