Select a row based on conditions for next row - mysql

Here is a part of my MySQL Table:
| id | opentrap | openrect | lampgroen | lamprood | closeout | openout | limitswitchclose | limitswitchopen | traploop | photocells | rectloop | DateTime | milliseconds |
| 92 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 2018-11-09 13:56:41 | 654 |
| 93 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 2018-11-09 13:56:42 | 262 |
| 94 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 2018-11-09 13:56:42 | 561 |
| 95 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 2018-11-09 13:56:45 | 83 |
| 96 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 2018-11-09 13:56:46 | 189 |
| 97 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 2018-11-09 13:56:47 | 402 |
| 98 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 2018-11-09 13:56:48 | 611 |
| 99 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 2018-11-09 13:56:48 | 916 |
I want to select a row based on alot of conditions and based if the next row has
traploop = 1 or rectloop = 1
The query I want to use looks like this (but I can't figure out how to write a condition for the next row):
SELECT *
FROM table
WHERE closeout = 0
AND openout = 0
AND lampgroen = 1
AND lamprood = 1
AND limitswitchopen = 1
AND NEXTROW: traploop = 1
OR rectloop = 1;
This should give me:
| 95 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 2018-11-09 13:56:45 | 83 |

Here is one approach, using correlated subqueries:
SELECT *
FROM yourTable t1
WHERE closeout = 0 AND openout = 0 AND lampgroen = 1 AND lamprood = 1 AND
limitswitchopen = 1 AND
((SELECT t2.traploop FROM yourTable t2
WHERE t2.id > t1.id ORDER BY t2.id LIMIT 1) = 1 OR
(SELECT t2.rectloop FROM yourTable t2
WHERE t2.id > t1.id ORDER BY t2.id LIMIT 1) = 1);
Demo
This approach is robust to the possibility that the id values may not be continuous. The only requirement for the "next" row is that it have the next highest id value from the current row.

This is what you need:
SELECT t0.*
FROM
table t0
INNER JOIN
table t1
ON t0.id + 1 = t1.id
WHERE
t0.closeout = 0 AND
t0.openout = 0 AND
t0.lampgroen = 1 AND
t0.lamprood = 1 AND
t0.limitswitchopen = 1 AND
(t1.traploop = 1 OR t1.rectloop = 1);

You can get the "next" row using join -- assuming that "next" is based on id and that has no gaps:
select . . .
from t join
tnext
on tnext.id = t.id + 1
where . . .;
You can then apply the conditions to either t or tnext.
In MySQL 8+, lead() would be a better alternative.

You can try with Correlated Subquery with Exists()
SELECT t1.*
FROM table AS t1
WHERE t1.closeout = 0 AND
t1.openout = 0 AND
t1.lampgroen = 1 AND
t1.lamprood = 1 AND
t1.limitswitchopen = 1 AND
EXISTS (SELECT 1
FROM table AS t2
WHERE t2.id = t1.id + 1 AND
(t2.traploop = 1 OR t2.rectloop = 1)
)
PS: This assumes that there are no gaps in id column

A simple query that uses correlated sub queries but works if ids have gaps is this:
SELECT *
FROM t AS curr
WHERE closeout = 0 AND openout = 0 AND lampgroen = 1 AND lamprood = 1 AND limitswitchopen = 1
AND 1 = (
SELECT CASE WHEN traploop = 1 OR rectloop = 1 THEN 1 END
FROM t AS next
WHERE id > curr.id
ORDER BY id
LIMIT 1
)
Demo on DB Fiddle

Related

MySQL : How to get latest row on optional where clause using group by?

We have one table- Product_table:
product_id | company_id | Status | must_show
1 | 23 | 1 | 1
2 | 23 | 1 | 1
3 | 23 | 1 | 0
4 | 23 | 1 | 0
5 | 23 | 0 | 0
6 | 24 | 1 | 0
7 | 24 | 1 | 0
8 | 24 | 1 | 0
9 | 24 | 1 | 0
10 | 24 | 0 | 0
We need to find the max product_id of company where status is 1. For that we are using below query:
select * from Product_table as pt
JOIN (select MAX(product_id) as extid from Product_table) t1 ON t1.extid =
pt.product_id where company_id in (23,24) and status = 1 group by company_id;
Result:
product_id| company_id| Status | must_show
4 | 23 | 1 | 0
9 | 24 | 0 | 0
This query is fine but we have an issue here.
If value for must_show is 1 then we need show max_product id for company with must_show=1 and status=1.
If value for must_show is 0 then we need show max_product id for company with status=1.
Expected Result:
product_id| company_id| Status | must_show
2 | 23 | 1 | 1
9 | 24 | 1 | 0
Please give me the path to find a solution. Thanks!
Please try below query:
select max(t.product_id) product_id, t.company_id, t.status, t.must_show from
( select p1.product_id, p1.company_id, p1.status, p1.must_show
from product_table p1
where status = 1
and must_show = (
select max(must_show) from product_table p2 where p2.company_id = p1.company_id)
) as t group by t.company_id;
Output:
+------------+------------+--------+-----------+
| product_id | company_id | status | must_show |
+------------+------------+--------+-----------+
| 2 | 23 | 1 | 1 |
| 9 | 24 | 1 | 0 |
+------------+------------+--------+-----------+
company_id in (23,24)- I think you don't need this condition as there are only these two company_id present in your table as per your question data.

Create 2 columns based on value in existing column

I have the following table. I would like to add 2 new columns with a select query that will show the total based on the flag type.
Table:
tt | company | count | flag
--------------------------------------------
123 | adeco | 5 | 1
123 | mic | 4 | 2
333 | manpower | 88 | 2
444 | linar | 2 | 2
555 | dlank | 3 | 1
Desired:
tt | company | total | flag | total_flag1 | total_flag2
-------------------------------------------------------------------
123 | adeco | 5 | 1 | 5 | 0
123 | mic | 4 | 2 | 0 | 4
333 | manpower | 88 | 2 | 0 | 88
444 | linar | 2 | 2 | 0 | 2
555 | dlank | 3 | 1 | 3 | 0
By your desired result, you should use case when or if syntax to to this:
select
yourtable.*,
case when flag = 1 then `count` else 0 end as total_flag1,
case when flag = 2 then `count` else 0 end as total_flag2
from yourtable
Or
select
yourtable.*,
if(flag = 1, `count`, 0) as total_flag1,
if(flag = 2, `count`, 0) as total_flag2
from yourtable
I think you can do what you want using correlated subqueries or join:
select t.*, tsum.total_flag1, tsum.total_flag2
from t join
(select t.tt,
sum(case when flag = 1 then total else 0 end) as total_flag1,
sum(case when flag = 2 then total else 0 end) as total_flag2
from t
group by t.tt
) tsum
on t.tt = tsum.tt;

Perform full outer join in mysql

I already know i can do outer join in MySQL using union.
I also check this one.
Full Outer Join in MySQL
But i want to do something like this and I don't know how can I achieve this using union.
I have db table user_count as follow.
+-------------+-----------+---------+-------+
| meb_id | left_id |right_id |active |
+-------------+-----------+---------+-------+
| 1001 | (NULL) | (NULL) | 1 |
| 1002 | 1001 | 0 | 0 |
| 1003 | 0 | 1001 | 0 |
| 1004 | 1001 | 0 | 0 |
| 1004 | 1002 | 0 | 0 |
+-------------+-----------+---------+-------+
I have queries as follow.
SELECT left_id, COUNT(left_id) AS left_count FROM `user_count` GROUP BY left_id
SELECT right_id, COUNT(right_id) AS right_count FROM `user_count` GROUP BY right_id;
SELECT left_id AS meb_id, COUNT(left_id) AS active_left_count FROM `user_count` WHERE active = 1 GROUP BY left_id;
SELECT right_id AS meb_id, COUNT(right_id) AS active_right_count FROM `user_count` WHERE active = 1 GROUP BY right_id;
I want to preform outer join or union so my result will be like this
+-------------+-----------+------------+------------+--------------+
| meb_id |left_count |right_count |active_left |active_right |
+-------------+-----------+------------+------------+--------------+
| (NULL) | 0 | 0 | 0 | 0 |
| 0 | 1 | 3 | 0 | 0 |
| 1001 | 2 | 1 | 0 | 0 |
| 1002 | 1 | 0 | 0 | 0 |
| 1003 | 0 | 0 | 0 | 0 |
+-------------+-----------+------------+------------+--------------+
How can i do this. Any help greatly appreciated.
Try this:
select
a.meb_id
,sum(case when a.meb_id = b.left_id then 1 else 0 end) left_count
,sum(case when a.meb_id = b.right_id then 1 else 0 end) right_count
,sum(case when a.meb_id = b.left_id and active = 1 then 1 else 0 end) active_left
,sum(case when a.meb_id = b.right_id and active = 1 then 1 else 0 end) active_right
from (
select meb_id from user_count union
select left_id from user_count union
select right_id from user_count
) a
cross join user_count b
group by a.meb_id
order by a.meb_id
Demo
sqlfiddle

MySQL - Count rows in main table with some condition and equals specific values

I have two table and first named table1:
ID | Name | Type | isActive | isDeleted |
-----------------------------------------------
1 | item 1 | 4 | 1 | 0 |
2 | item 2 | 2 | 1 | 0 |
3 | item 3 | 1 | 1 | 1 |
4 | item 4 | 1 | 1 | 0 |
5 | item 5 | 1 | 1 | 0 |
6 | item 6 | 3 | 1 | 0 |
7 | item 7 | 1 | 1 | 0 |
8 | item 8 | 2 | 1 | 0 |
9 | item 9 | 1 | 1 | 0 |
10 | item 10 | 1 | 1 | 0 |
AND second named table1_meta:
ID | table1_id | options | value
------------------------------------
1 | 1 | dont_ask | 1
2 | 2 | dont_ask | 1
3 | 5 | dont_ask | 1
4 | 6 | dont_ask | 1
5 | 8 | alwasys_ask| 1
6 | 9 | alwasys_ask| 1
7 | 1 | is_flagged | 1
8 | 2 | is_flagged | 0
9 | 3 | is_flagged | 0
10 | 4 | is_flagged | 0
11 | 5 | is_flagged | 0
12 | 6 | is_flagged | 1
13 | 7 | is_flagged | 0
14 | 8 | is_flagged | 0
15 | 9 | is_flagged | 0
16 | 10 | is_flagged | 0
I'm trying to count rows in table1 where certain specific criteria is met, some of these conditionals.
The WHERE condition must contain these criteria:
table1.type = 1 and table1.isActive = 1 and table1.isDeleted = 0 and table1_meta.options = 'is_flagged' and table1_meta.value = 0
and this:
table1_meta.options = 'dont_ask' and table1_meta.value = 1
and this:
table1_meta.options = 'always_ask' and table1_meta.value = 1
so, how can I do that?
SQLFiddle link: http://sqlfiddle.com/#!2/2eb27b
Thanks.
I assume you are trying to count rows in the first table. Here is one way using subqueries:
select count(*)
from table1 t1
where t1.type = 1 and t1.isActive = 1 and t1.IsDeleted = 0 and
exists (select 1
from table1_meta tm
where t1.id = tm.table1_id and tm.options = 'is_flagged' and tm.value = 0
) and
not exists (select 1
from table1_meta tm
where t1.id = tm.table1_id and
tm.options = 'dont_ask' and tm.value = 1
) and
exists (select 1
from table1_meta tm
where t1.id = tm.table1_id and
tm.options = 'always_ask' and tm.value = 1
);
This has a separate subquery for each condition on the meta table.
I think I found the answer of my question.
the query is:
SELECT Count(*) AS total FROM
(SELECT Count(*)
FROM table1 t1,
table1_meta t1meta
WHERE t1.type = 1
AND t1.isactive = 1
AND t1.isdeleted = 0
AND t1meta.options = 'is_flagged'
AND t1meta.value = 0
AND t1.id NOT IN (SELECT table1_id
FROM table1_meta tm
WHERE tm.options = 'dont_ask'
AND tm.value = 1)
UNION
SELECT Count(*)
FROM table1_meta tm,
table1 t1
WHERE t1.id = tm.table1_id
AND tm.options = 'always_ask'
AND tm.value = 1) x
Thanks anyway, Gordon.

mysql join incorrect results

Each childrow has a parentid and position. For childrows with the same position there is one row where start='1'.
What i'm trying to do is return the pending rows with their start row.
The results that should be shown are; start(owen) pending(dave,paul). This is because they have the same position. Here is the SQL fiddle http://sqlfiddle.com/#!2/e6e54/1
id | name | parentid| position| start | pending |
1 | mike | 0 | 0 | 0 | 0 |
2 | dave | 1 | 1 | 0 | 1 |
3 | paul | 1 | 1 | 0 | 1 |
4 | john | 1 | 2 | 1 | 0 |
5 | bret | 1 | 2 | 0 | 0 |
6 | owen | 1 | 1 | 1 | 0 |
7 | rick | 1 | 3 | 1 | 0 |
8 | jaye | 1 | 3 | 0 | 0 |
$getquery = mysql_query("select child.*
from `mytable` child inner join `mytable` parent
on parent.id=child.parentid
inner join `mytable` child2 on child.parentid=child2.parentid
and child2.pending='1'
where child.start='1' ORDER BY child.id DESC");
while($row=mysql_fetch_assoc($getquery)) {
$name = $row['name'];
echo "<p>Name: $name </p>";
}
select * from `mytable` order by position, pending
You can add a where position=1 clause if that's the only position of interest.