select rows based on next row in mysql - mysql

I have a table like this :
Type | Time
1 | 234234
2 | 234235
1 | 234238
3 | 234239
4 | 234240
1 | 234242
2 | 234245
I want to count number of all those rows where type=1 and next row's type=2.
For ex : The result here is 2.
I don't know how to put where clause on next row.

You should be able to implement user defined variables to get the total:
select count(*) Total
from
(
select type,
#row:=(case when #prev=1 and type=2 then 'Y' else 'N' end) as Seq,
#prev:=type
from yourtable, (SELECT #row:=null, #prev:=null) r
order by time, type
) src
where Seq = 'Y'
See SQL Fiddle with Demo

Related

Select rows where column > 0 after final row where column == 0

Edit 2021: I want to explain this better.
I have a table named MyTable with two columns; one column named SortColumn type Integer and one column named ExpressionColumn type Boolean.
I want to get all rows, sorted by SortColumn in ascending order, after the last row where ExpressionColumn was True.
The types are not exact.
Eg. Table with rows represented as [SortColumn,ExpressionColumn], [0:True] will get [0:True], [0:True, 1:False] will get [], [0:True, 1:False, 2:True, 3:True] will get [3:True, 4:True].
Leaving the old question below so as not to invalidate given answers. It had too many extra details.
I want to select rows after than last row where column Number is 0.
So with this table,
Id | Number
------------
0 | 5
1 | 30
2 | 10
3 | 25
I want to get rows with Id 0 to 3 inclusive.
With this table,
Id | Number
------------
0 | 5
1 | 30
2 | 10
3 | 25
4 | 0
I want to get no rows at all.
With this table,
Id | Number
------------
0 | 5
1 | 30
2 | 10
3 | 25
4 | 0
5 | 0
6 | 30
I want to get row with Id 6.
SQL details: MySQL 5.6.
Retrieve separate records:
SELECT *
FROM transaction t1
WHERE Name LIKE '%Car Wash%'
AND NOT EXISTS ( SELECT NULL
FROM transaction
WHERE t1.id <= id
AND Name LIKE '%Car Wash%' -- maybe not needed? not specified
AND Price = 0 );
Retrieve their amount only:
SELECT COUNT(*)
FROM transaction t1
WHERE Name LIKE '%Car Wash%'
AND NOT EXISTS ( SELECT NULL
FROM transaction
WHERE t1.id <= id
AND Name LIKE '%Car Wash%'
AND Price = 0 );
fiddle
you can select
select
from my_table
where name like '%car%' and price > 0
and for count
select count(*)
from (
select
from my_table
where name like '%car%' and price > 0
) t
I interpret this question as "how many rows are there for "car wash" after the first row with price > 0". If so:
select count(*)
from (select t.*,
min(case when price = 0 then id end) over () as id_at_0
from transaction t
) t
where name = 'Car Wash' and id > id_at_0
SELECT * FROM MyTable myTable1
AND NOT EXISTS ( SELECT NULL FROM MyTable
WHERE myTable1.SortColumn <= SortColumn
AND ExpressionColumn = True );

How to fetch rows from which sum of a single integer/float column sums upto a certain value

I have a table. It has the following structure
goods_receiving_items
id
item_id
quantity
created_at
I am trying to fetch rows against which have the following conditions
Has one item_id
When the sum of the quantity column equals a certain value
So for example I have the following data
+----+---------+----------+------------+
| id | item_id | quantity | created_at |
+----+---------+----------+------------+
| 1 | 2 | 11 | 2019-10-10 |
| 2 | 3 | 110 | 2019-10-11 |
| 3 | 2 | 20 | 2019-11-09 |
| 4 | 2 | 5 | 2019-11-10 |
| 5 | 2 | 1 | 2019-11-11 |
+----+---------+----------+------------+
I have tried the following query:
SET #sum:= 0;
SELECT item_id, created_at, (#sum:= #sum + quantity) AS SUM, quantity
FROM goods_receiving_items
WHERE item_id = 2 AND #sum<= 6
ORDER BY created_at DESC
If I don't use ORDER BY, then the query will give me ID '1'. But if I use ORDER BY it will return all the rows with item_id = 2.
What should be returned are IDs '5' and '4' exclusively in this order
I can't seem to resolve this and ORDER BY is essential to my task.
Any help would be appreciated
You should use the order by on the resulting set
you could do this using a subquery
SET #sum:= 0;
select t.*
from t (
SELECT item_id
, created_at
, (#sum:= #sum + quantity) as sum
, quantity
FROM goods_receiving_items
WHERE item_id = 2 AND #sum<= 6
) t
ORDER BY created_at DESC
You should try an INNER JOIN with SELECT min(created_at) or SELECT max(created_at)
From MYSQL docs:
...the selection of values from each group cannot be influenced by
adding an ORDER BY clause. Sorting of the result set occurs after
values have been chosen, and ORDER BY does not affect which values the
server chooses.
The answers on the following might help in more detail: MYSQL GROUP BY and ORDER BY not working together as expected
After searching around, I have made up the following query
SELECT
t.id, t.quantity, t.created_at, t.sum
FROM
( SELECT
*,
#bal := #bal + quantity AS sum,
IF(#bal >= $search_number, #doneHere := #doneHere + 1 , #doneHere) AS whereToStop
FROM goods_receiving_items
CROSS JOIN (SELECT #bal := 0.0 , #doneHere := 0) var
WHERE item_id = $item_id
ORDER BY created_at DESC) AS t
WHERE t.whereToStop <= 1
ORDER BY t.created_at ASC
In the above query, $search_number is a variable that holds the value that has to be reached. $item_id is the item we are searching against.
This will return all rows for which the sum of the column quantity makes up the required sum. The sum will be made with rows in descending order by created_at and then will be rearranged in ascending order.
I was using this query to calculate the cost when a certain amount of items are being used in an inventory management system; so this might help someone else do the same. I took most of the query from another question here on StackOverflow

In MYSQL - Select up to a certain value in a column

I searched for a solution since a few weeks, but however could not really solve problem: Is it possible to select only a few rows until or up to a certain value, which could repeating itself further down my table?
I think, an example can be very useful:
Type | OBID | RECID
5 | T-000032 | 5637637
1 | T-123456 | 5637636
1 | T-789123 | 5637635
2 | T-123456 | 5637634
2 | T-789123 | 5637633
1 | T-221133 | 5637628
2 | T-221133 | 5637612
Here a little example:
This section of my table will always start with Type 5 followed by a couple of rows with Type 1. I only need this special "group" of rows with Type 1 since the first row with type 2 appears.
I would not be attracted to any other row with Type 1 - only this ones:
1 | T-123456 | 5637636
1 | T-789123 | 5637635
Quasi only this rows with Type 1 which are between
the first row with Type 5 and
the first row with Type 2.
I hope, you could help me.
Thank you very very much.
Chrissy
This feels like a gaps and islands problem, but in this case you just want a single island. One approach is to use subqueries to find:
The highest RECID value where Type=1. This represents the
inclusive upper bound of the island.
The highest RECID value where Type!=1, and where the RECID
value is also less than the above RECID value. This serves as
the exclusive lower bound of the island.
Here is a working query:
SELECT *
FROM yourTable
WHERE Type = 1 AND RECID > (SELECT MAX(RECID) FROM yourTable
WHERE Type <> 1 AND RECID < (SELECT MAX(RECID) FROM yourTable
WHERE Type = 1)) AND
RECID <= (SELECT MAX(RECID) FROM yourTable WHERE Type = 1)
ORDER BY
RECID DESC;
Demo
You can try below for mysql version less than 8.0
select * from
(SELECT
#row_number:=CASE
WHEN #Type = PType THEN #row_number + 1
ELSE 1
END AS num,
#Type:=Type as PType,
Type,
OBID,RECID
FROM
tablename order by type,RECID desc
)X where num in (1,2)
OR You can use row_number() in case mysql version 8.0+
select * from
(
select *, row_number() over(partition by type order by recid desc) as rn
from tablename
)X where rn in (1,2)

SQL - Only return when no rows hold a value

I am looking for a way to return an ID only if NO rows hold a certain value
For example:
*ID* | *Date*
1 | 01/01/2001
1 | 02/02/2002
1 | 03/03/2003
If I want SQL to return the ID only if no dates are equal to 02/02/2002, how would I script that? I have tried and failed with the below:
select *ID*
from (example)
where date != 02/02/2002
The problem is that this still returns the ID - 1, as the first and last row do not equal 02/02/2002. What I am aiming for is no returned results because at least one row held the matching date.
I would need the script to completely skip the ID when there is a matching date in any row.
For clarity the below should return the ID when using the same 'select' as above because no dates are matching:
*ID* | *Date*
2 | 03/03/2003
2 | 04/04/2004
2 | 05/05/2005
You need Group By and Having clause
select ID
From yourtable
group by ID
Having count (case when date != '02/02/2002' then 1 end) = count(*)
As mentioned by mathguy, this also works
select ID
From yourtable
group by ID
Having count(case when date = '02/02/2002' then 1 end) = 0

Mysql count with case when statement

Consider:
SELECT(count(c.id),
case when(count(c.id) = 0)
then 'loser'
when(count(c.id) BETWEEN 1 AND 4)
then 'almostaloser'
when(count(c.id) >= 5)
then 'notaloser'
end as status,
...
When all is said and done, the query as a whole produces a set of results that look similar to this:
Count | status
--------|-------------
2 | almostaloser //total count is between 2 and 4
--------|-------------
0 | loser // loser because total count = 0
--------|-------------
3 | almostaloser //again, total count between 2 and 4
--------|-------------
What I would like to achieve:
a method to reatain the information from the above table, but add a third column that will give a total count of each status, something like
select count(c.id)
case when(count(c.id) = 0 )
then loser as status AND count how many of the total count does this apply to
results would look similar to:
Count | status |total_of each status |
--------|-------------|---------------------|
2 | almostaloser| 2 |
--------|-------------|---------------------|
0 | loser | 1 |
--------|-------------|---------------------|
3 | almostaloser| 2 |
--------|-------------|----------------------
I've been told this could be achieved using a derived table, but i've not yet been able to get them both, only one or the other.
This can be achieved with this query (you must place your original query as subquery in two places):
SELECT t1.*, t2.total_of_each_status
FROM (
-- put here your query --
) t1
INNER JOIN (
SELECT status, count(*) AS total_of_each_status
FROM (
-- put here your query --
) t2
GROUP BY status
) t2 ON t2.status = t1.status