MySQL count rows with specific value - mysql

I have a table like this:
id status user_id
1 decline 8
2 approved 7
3 approved 7
4 decline 8
5 decline 7
I want result like this:
accept_status decline_status user_id
2 1 7
0 2 8

Schema (MySQL v5.7)
CREATE TABLE TEST (
id int,
status varchar(20),
user_id int
);
INSERT INTO TEST
VALUES(1,'decline',8);
INSERT INTO TEST
VALUES(2,'approved',7);
INSERT INTO TEST
VALUES(3,'approved',7);
INSERT INTO TEST
VALUES(4,'decline',8);
INSERT INTO TEST
VALUES(5,'decline',7);
Query #1
Used two subqueries during SELECT operation
SELECT
(SELECT count(status) FROM TEST b WHERE status='approved' AND b.user_id = a.user_id) as accept_status,
(SELECT count(status) FROM TEST c WHERE status='decline' AND c.user_id = a.user_id) as decline_status,
a.user_id
FROM TEST a
GROUP BY user_id;
OR
Query #2
SELECT
sum(case when status = 'approved' then 1 else 0 end) AS accept_status,
sum(case when status = 'decline' then 1 else 0 end) AS decline_status,
user_id
FROM TEST
GROUP BY user_id
Output
accept_status
decline_status
user_id
2
1
7
0
2
8
View on DB Fiddle

Using SubQuery or Sub Select you can try this query:
select distinct user_id,
(select count(*) from testtable
where status='approved' and user_id=a.user_id) as accept_status,
(select count(*) from testtable
where status='decline' and user_id=a.user_id) as denied_status
from testtable a;

Related

SQL : Summing the values in a column till first non zero values appears in other column?

Suppose, I have a table t1 looking like
id
value1
value2
wk_id
1
2
0
1
1
1
1
2
1
3
0
3
2
2
1
2
2
2
0
3
3
1
0
2
3
2
0
4
3
3
0
5
And I want to sum up the value1 till non-zero value appears on the value2 for first time.
End product must look like this:
id
value1
1
2
2
0
3
6
How to perform this in SQL?
If your MySQL version support window function you can try to use SUM window function with condition aggregate function be a flag to represent your logic (till non-zero value appears on the value2 for first time)
Then do condition aggregate function again.
Query #1
SELECT id,
SUM(CASE WHEN flag = 0 THEN value1 ELSE 0 END) value1
FROM (
SELECT *,
SUM(CASE WHEN value2 = 1 THEN -1 ELSE 0 END) OVER(PARTITION BY ID ORDER BY wk_id) flag
FROM T
) t1
GROUP BY id;
id
value1
1
2
2
0
3
6
View on DB Fiddle
WITH cte AS (
SELECT *,
CASE WHEN SUM(value2) OVER (partition by id ORDER BY wk_id) = 0
THEN SUM(value1) OVER (partition by id ORDER BY wk_id)
ELSE 0
END sum_value1
FROM test
ORDER BY id, wk_id
)
SELECT id, MAX(sum_value1) sum_value1
FROM cte
GROUP BY id;
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=0fcdca008e4a821f952de4d608434bcf
One option is a NOT EXISTS clause, looking for the stop row (the first row with value2 = 1).
select id, sum(value1)
from mytable
where not exists
(
select null
from mytable stoprow
where stoprow.id = mytable.id
and stoprow.wk_id <= mytable.wk_id
and stoprow.value2 = 1
)
group by id
order by id;
Aggregating on a calculated rolling total of value2 can also be done via a self-join.
select id
, sum(if(roll_tot_value2=0,value1,0)) as total
from
(
select t1a.id, t1a.wk_id, t1a.value1
, sum(t1b.value2) as roll_tot_value2
from t1 as t1a
join t1 as t1b
on t1b.id = t1a.id
and t1b.wk_id <= t1a.wk_id
group by t1a.id, t1a.wk_id, t1a.value1
) q
group by id;
id
total
1
2
2
0
3
6
Test on db<>fiddle here
You can use a subquery:
select t.id, coalesce(
(select sum(t2.value1) from t1 t2 where t2.value2 = 0 and t2.id = t.id
and (not exists (select 1 from t1 t3 where t3.value2 = 1 and t3.id = t.id)
or t2.wk_id < (select min(t4.wk_id) from t1 t4 where t4.id = t.id and t4.value2 = 1))), 0)
from t1 t group by t.id

Get records GROUPing BY and discarding duplicates

I have a "transaction_status" table:
id transaction_id status
1 12 0
2 13 0
3 12 -1
4 14 0
5 13 -1
6 15 0
[END OF TABLE]
I need to get the transaction ids which only have a record with status=0.
For example this is what I am looking for from the above table:
id transaction_id status
4 14 0
6 15 0
So far I am trying:
SELECT id, transaction_id, status
FROM transaction_status
WHERE status = 0 OR status = -1
ORDER BY status ASC
GROUP BY txn_id
HAVING status = 0
Made a small change in the having clause.
SELECT id, transaction_id, status
FROM transaction_status
WHERE status = 0 OR status = -1
GROUP BY transaction_id
HAVING min(status) = 0
I also removed order by as it does not make any sense
Use GROUP BY and in having clause check for both min and max status is 0.
Query
select `transaction_id`
from `your_table_name`
group by`transaction_id`
having min(`status`) = 0 and max(`status`) = 0;
I think the easiest way to handle this is to use conditional aggregation by transaction_id and count which IDs have only a status of 0 associated with them. Do this in a subquery, and then join back to your main table to retrieve the full matching records which you want.
SELECT t1.*
FROM transaction_status t1
INNER JOIN
(
SELECT transaction_id
FROM transaction_status
GROUP BY transaction_id
HAVING SUM(CASE WHEN status <> 0 THEN 1 ELSE 0 END) = 0
) t2
ON t1.transaction_id = t2.transaction_id
ORDER BY t1.id DESC

Group By MySQL Query that returns specific results with parameters

Before a user starts a private chat (between 2 members, not a group chat) I want to check and see if there is already a chat consisting of only these two members. In case they've deleted the chat on their end, when they go to message that same user again I want it to merge with the old chat instead of starting a duplicate chat for the same two members.
This is my structure
`chats` table
id created_time
1 [TIMESTAMP]
2 [TIMESTAMP]
`chats.parties` table
id chat_id member_id invited_by
1 1 1 0 // creator of chat
2 1 2 1
3 1 3 1
4 2 1 0
5 2 2 1
Group by chat_id but only return results that contain a row with member_id=1 and member_id=2; no more, no less.
In the case of the tables above, only the chat_id=2 row(s) would be returned because chat_id=1 contains a 3rd member.
Is this possible with raw SQL? I'd prefer to not loop through in php as it would take a while with a lot of chats.
Here are two different ways to get the result you are looking for:
-- using conditional aggregation
select chat_id from chat_parties
group by chat_id
having sum(case when member_id = 1 then 1 else 0 end) > 0
and sum(case when member_id = 2 then 1 else 0 end) > 0
and sum(case when member_id not in (1, 2) then 1 else 0 end) = 0
-- using a correlated subquery
select chat_id from chat_parties c1
where member_id in (1,2)
and not exists (
select 1 from chat_parties where chat_id = c1.chat_id and member_id not in (1,2)
)
group by chat_id having count(distinct member_id) = 2
Change the table names to fit your actual setup.
Using conditional COUNT
SQL Fiddle Demo
SELECT c.`id`
FROM chats c
LEFT JOIN chats_parties cp
ON c.`id`= cp.`chat_id`
GROUP BY c.`id`
HAVING COUNT(case when `member_id` = 1 then 1 END) >= 1
AND COUNT(case when `member_id` = 2 then 1 END) >= 1
AND COUNT(DISTINCT `member_id` ) = 2

MySQL count from different Tables

Table A
Status
1
1
1
2
2
3
Table B
Status
1
1
2
2
2
2
3
3
How to Get following Result Table
Result Table
Status Count
1 5
2 6
3 3
Help me to build SQL Query to get Count in Result Table.
Try this
SELECT Status, COUNT(*) FROM
(SELECT a.Status FROM TableA AS a
UNION ALL
SELECT b.Status FROM TableB AS b) UN
GROUP BY Status
SELECT STATUS, COUNT(*) FROM
(SELECT STATUS FROM TABLE1
UNION ALL
SELECT STATUS FROM TABLE2) un
GROUP BY STATUS
FIDDLE

MySQL: Select Order Only if all its Items are ready status

I will simplify the table like this:
table order:
order_id | name
1 a
2 b
3 c
Table order_item:
item_id | fk_order_id | status
1 1 0
2 1 1
3 2 1
4 2 1
5 3 0
Ready status let say is 1, so only order_id=2 has all its items are on ready status.
How can I query select it?
There are a couple ways of doing this -- here is one using COUNT -- gets COUNT of all and compares to COUNT of Status = 1:
SELECT fk_order_id
FROM (
SELECT fk_order_id,
COUNT(1) totCount,
COUNT(CASE WHEN Status = 1 THEN 1 END) statusCount
FROM Order_Item
GROUP BY fk_order_id
) t
WHERE totCount = statusCount
SQL Fiddle Demo
This could be consolidated into a single query, but I think it reads better using a subquery.
Try this:
SELECT order_id ,name FROM order,order_item
WHERE order.order_id =order_item.fk_order_id
group by order_id ,name having min(status)=1