counting using join information - mysql

I have two tables.
One table records orderstock which has FK_stock and FK_orderNo
I want to count the number of orders each item of stock has. The following code works correctly to do this:
(1)
SELECT orderstock.FK_orderNo, Count(orderstock.FK_stock) AS CountOfFK_stock
FROM stock INNER JOIN orderstock ON stock.StockID = orderstock.FK_stock
GROUP BY orderdemo.FK_orderNo
However, I wish to add to this such that only stock items which are non perishable (stock.perishable=0) are listed. So something like
SELECT orderstock.FK_orderNo, Count(orderstock.FK_stock) AS CountOfFK_stock
FROM stock INNER JOIN orderstock ON stock.stockID = orderstock.FK_stock
WHERE stock.perishable=0
GROUP BY orderstock.FK_orderNo
How do I access information relating to the FK_stock to make this work? When I attempt to combine information from the stock table to this end, each item of stock is counted separately.
Results from (1)
FK_OrderNo CountOfFK_Stock
9 10
104 8
105 3
106 10
107 8
108 10
109 11
110 9
Desired results (something like):
FK_OrderNo CountOfFK_Stock
9 7
104 8
105 3
106 4
107 7
108 2
109 11
110 6

I guess you are looking for conditional count
Move the where clause filter to Count Aggregate and make the count aggregate to count the record only when stock.perishable = 0.
SELECT orderdemo.fk_orderno,
Count(CASE
WHEN stock.perishable = 0 THEN 1
END) AS nonperishable_count
FROM stock
INNER JOIN orderdemo
ON stock.studentid = orderdemo.fk_stock
GROUP BY orderdemo.fk_orderno
Count Aggregate can be replaced by SUM aggregate as well. Something like this
Sum(CASE
WHEN stock.perishable = 0 THEN 1
ELSE 0
END) AS nonperishable_count

Related

mysql query to find rows having only single specific sub-category against any category (in group by data)

I have MySQL table with name users. SQL returns following result
select user_id, vegetarian, count(*) from users group by user_id, vegetarian;
Current SQL Output
user_id vegetarian count(*)
2 1 15
3 0 131
3 1 6
4 1 6
5 0 113
5 1 7
6 1 6
7 0 107
7 1 11
Required Output
My required output is:
user_id vegetarian count(*)
2 1 15
4 1 6
6 1 6
Kindly help me for SQL query to get my required output.
Kind Regards
SELECT user_id, 1 vegetarian, COUNT(*)
FROM users
GROUP BY user_id
HAVING NOT SUM(NOT vegetarian);
NOT vegetarian converts 0 to 1 and backward. Hence SUM() calculates the amount of rows which are not vegetarians. And HAVING NOT SUM() removes the rows where this sum is above zero.

how to comparison LAG function in mysql

I got complicated problem in mysql.
I have some table on mydatabase.
sample docs(this is only simple sample, actual data are so many table that I have to join)
table "merchant"
id name
1 arief
2 john
3 chena
table "transaction"
id product_id price merchant_id date
1 1 20000 2 2020-02-01
2 5 25000 1 2020-02-01
3 2 10000 3 2020-02-02
4 2 10000 2 2020-02-02
5 3 5000 2 2020-02-02
5 2 10000 2 2020-02-03
6 3 5000 3 2020-02-04
I want to know the information of merchants transaction daily "before" and "after" to comparison
like this below
name_merchant sumtrx_20-02-01 sumtrx_20-02-02 sumtrx_20-02-03 sumtrx_20-02-04
arief 1 0 0 0
john 1 2 1 0
chena 0 1 0 1
I tried with this query
select m.name, count(trx.id, trx.date = '2020-02-01') as sumtrx_20-02-01, count(trx.id, trx.date = '2020-02-02') as sumtrx_20-02-02, count(trx.id, trx.date = '2020-02-03') as sumtrx_20-02-03, count(trx.id, trx.date = '2020-02-04') as sumtrx_20-02-04 from merchant as m join transaction as trx on m.id = trx.merchant_id
group by m.name
but that query didn't work
You can use sum() instead of count().
SELECT m.name,
sum(trx.date = '2020-02-01') `sumtrx_20-02-01`,
...
sum(trx.date = '2020-02-04') `sumtrx_20-02-04`
FROM merchant m
INNER JOIN transaction trx
ON m.id = trx.merchant_id
GROUP BY m.name;
And you also need to enclose identifiers, here the column aliases, in backticks if you use special characters like - in them. Or avoid using special characters in them all together.

MySQL count without grouping

I am running the following query to understand to get users' first attempt to answer a question listed next to their second attempt.
SELECT
s.id AS attempt_id_first, m.id AS attempt_id_second, s.user_id
FROM
attempt s
INNER JOIN attempt m on s.user_id = m.user_id
WHERE
s.id<m.id
I end up with this:
attempt_first attempt_second user_id
7 17 1
9 10 2
9 15 2
10 15 2
4 6 9
24 25 15
29 34 19
29 36 19
34 36 19
I would like to have a new column that counts the number of attempts by users so that:
7 17 1 1
9 10 2 3
9 15 2 3
10 15 2 3
4 6 9 1
24 25 15 1
29 34 19 3
29 36 19 3
34 36 19 3
I am sure this is trivial, but I cannot get it to work. Help anyone?
I think this is it: Just display the results, and throw in an extra count subquery:
select
userid,
id,
(select
count('x')
from
attempt x
where
x.userid = a.userid) as attempcount
from
attempt a
If you like to keep the first and second attempt in separate columns, you can of course embed the subselect in your original query.
It seems wrong, though. Firstly, you need to have at least two attemps, otherwise none will show. You can solve that by changing inner join to left join and move the condition in the where clause to that join. Secondly, the 'second attempt' is not the second attempt per say. Actually, for each of the attempts you get all next attempts. Look at the example of user 2. You accidentally get three rows (where there are three attemps), but you get attempt 9 and 10, as well as attempt 9 and 15 as well as 10 and 15. 9, 15 is incorrect, since 15 isn't the attempt that followed 9. The more attempts a user has, the more of these false results you will get.
If you want one attempt listed next to the next one, with the count, I would suggest:
SELECT s.user_id, s.id AS attempt_id_first,
(select s2.id
from attempt s2
where s2.user_id = s.user_id and
s2.id > s.id
order by s2.id
limit 1
) as attempt_id_second,
(select count(*)
from attempt s3
where s3.user_id = s.user_id
) as totalAttempts
FROM attempt s ;
This only lists each attempt once with the next one. The count is included as the last column.

simple sql select over 3 tables

I'm stuck with Mysql... I'm sure this question have been asked hundreds of times but without any keyword. I've 2 tables and a view:
tbl_user_measure
measure_cat userid amount
------------------------------
7 1 78
5 1 96
4 1 78
tbl_itemcat_measure
measure_cat item_cat
----------------------
7 1
5 1
4 1
vw_allitems
measure_cat min max item_cat itemid
---------------------------------------------------
7 76 81 1 1
5 97 100 1 1
4 79 81 1 1
7 76 81 1 11
5 95 97.5 1 11
4 76 79 1 11
4 33 12 2 5
What I'm looking for is the item(s) whose min and max values match in all measure_cat's of the specific item_cat the users values (max > tbl_user_measure.amount > min).
My approach was
SELECT distinct
v.itemid,
v.measure_cat_id,
v.min,
v.max
FROM
vw_allitems v, tbl_user_measure um, tbl_user u
where
um.tbl_measure_category_id = v.measure_cat_id and
(um.amount >= v.min and um.amount <= v.max) and
v.productid = 1
This resultes in:
itemid measure_cat_id min max
---------------------------------------------------
1 7 76 81
7 7 76 81
10 7 76 81
11 7 76 81
11 4 76 79
11 5 95 9
What I need is just the itemid '11' because its values fit in all categories.
Looks like you're almost there. Your query returns all matching rows; change it so that it returns the itemid and the count, grouped by itemid. All that's left is just to return those items where the count is equal to the number of rows that user has in the first table.
UPDATE: This should do what you need:
SELECT x.itemid, x.measure_cat, x.min, x.max
FROM
(SELECT vw.itemid i, u.userid u, count(*) mc
FROM vw_allitems vw
JOIN tbl_user_measure u ON vw.measure_cat=u.measure_cat
WHERE u.amount>=vw.min and u.amount<=vw.max
GROUP BY vw.itemid, u.userid) match_counts
JOIN
(SELECT userid u, count(*) uc
FROM tbl_user_measure
GROUP BY userid) user_counts
ON match_counts.u = user_counts.u
AND match_counts.mc=user_counts.uc
JOIN
vw_allitems x
ON match_counts.i = x.itemid
WHERE match_counts.u=1
Quick walkthrough. The first subquery takes every combination of user and item, and counts the number of matches. The second subquery counts how many entries that user has in tbl_user_measure. The join selects just those users and items where the match count equals the total count for that user (i.e. all the user's entries match), then finally we join it to the original data to return the original rows from vw_allitems and select just the user we are interested in.
Try this query:
SELECT v.itemid,
v.measure_cat_id,
v.min,
v.max
FROM vw_allitems as v,
INNER JOIN tbl_user_measure as um
ON um.measure_cat = v.measure_cat and um.amount >= v.min and um.amount <= v.max
INNER JOIN tbl_itemcat_measure as im
ON im.item_cat=um.item_cat

MySQL Date range incorrect result obtained - Query ignores the specified range

I have a query that involves searching database over a range of 30 days. Queries, both with correct output and wrong output are below:
CORRECT RESULTS:
SELECT
affiliates.member_id,
IFNULL( COUNT(orders.deal_id) , 0 ) AS deals_count,
IFNULL( SUM(orders.quantity) , 0 ) AS deals_quanity
FROM affiliates
LEFT JOIN deals ON affiliates.member_id = deals.member_id
LEFT JOIN orders ON deals.deal_id = orders.deal_id
LEFT JOIN customers_orders_link ON orders.order_id = customers_orders_link.order_id
AND DATE(customers_orders_link.datetime) BETWEEN '2011-06-01' AND '2011-07-01'
AND customers_orders_link.order_status = 'Delivered'
GROUP BY affiliates.member_id;
EXPECTED & RECEIVED: (Correct)
MemberID COUNT SUM
1 11 16
2 0 0
WRONG RESULTS:
//Notice the change in the date range
SELECT
affiliates.member_id,
IFNULL( COUNT(orders.deal_id) , 0 ) AS deals_count,
IFNULL( SUM(orders.quantity) , 0 ) AS deals_quanity
FROM affiliates
LEFT JOIN deals ON affiliates.member_id = deals.member_id
LEFT JOIN orders ON deals.deal_id = orders.deal_id
LEFT JOIN customers_orders_link ON orders.order_id = customers_orders_link.order_id
AND DATE(customers_orders_link.datetime) BETWEEN '2011-10-01' AND '2011-10-31'
AND customers_orders_link.order_status = 'Delivered'
GROUP BY affiliates.member_id
EXPECTED:
MemberID COUNT SUM
1 0 0
2 0 0
BUT I RECEIVE: (INCORRECT OUTPUT)
MemberID COUNT SUM
1 11 16
2 0 0
The first query is producing correct results whereas the second query is producing incorrect results. Even if I use a date in the past as the range, I still receive the same Incorrect Output. Its as if the query is completely ignoring the date range specification. So this case of ignoring the date range specification seems to be the problem.
How can I make the query "see" and "obey" the date range specification and actually receive the Expected Output for the 2nd query listed above?
EDIT 1:
//Table: Orders
order_id deal_id quantity price
1 1 2 40.00
1 2 1 15.00
2 1 1 20.00
3 9 1 5.00
4 1 2 40.00
4 9 2 10.00
5 1 1 20.00
5 9 1 5.00
6 1 2 40.00
6 9 2 10.00
7 1 1 20.00
8 11 1 1.00
//Table: customers_orders_link
order_id customer_id order_status datetime
1 4 Cancelled 2011-06-05 20:26:45
2 4 Delivered 2011-06-05 20:38:28
3 4 Pending Payment 2011-06-05 20:56:50
4 4 Pending Payment 2011-06-09 17:03:08
5 4 Pending Payment 2011-06-09 17:12:23
6 4 Pending Payment 2011-06-09 17:19:57
7 4 Pending Payment 2011-06-09 17:40:59
8 4 Pending Payment 2011-06-10 03:55:17
I solved it myself using a totally different method.
I don't know what your data looks like, but I suspect your LEFT JOIN customers_orders_link is to blame. If you only want to tally COUNT() and SUM() when the conditions of that table are met, it should be a standard JOIN in place of a LEFT JOIN.