Previous entry before first zero SQL - mysql

given the following table:
id (desc) | amount
------------------
9 | 3
8 | 2
7 | 1 <- RETURN THIS ROW
6 | 0
5 | 1
4 | 0
3 | 2
2 | 1
1 | 0
I need to return only one row - that one with the id 7
Rules:
- the most recent entry have an amount bigger than 0
- should return the row after the first amount 0 occurence
That way if I have:
id (desc) | amount
------------------
4 | 0
3 | 0
2 | 1
1 | 0
It will not show any row.

You can use window functions:
select t.*
from (select t.*,
max(case when amount = 0 then id end) over () as last_0_id
from t
) t
where id > last_0_id
order by id asc
limit 1;
Or, without window functions:
select t.*
from t join
(select max(t2.id) as id
from t t2
where t2.amount = 0
) t2
on t.id > t2.id
order by id asc
limit 1;
Here is a db<>fiddle
This is probably faster than using lead(), actually.

Related

How can I create a column with incremented values from a column with cumulated values in MySQL?

Table1 contains a column with cumulated values (all positive integers):
id ValuesCum
1 5
2 8
3 20
I would like to write a statement that returns an extra column with the incremented values for each row. The output should read something like:
id ValuesCum ValuesInc
1 5 (5)
2 8 3
3 20 12
Does anyone have a solution for this?
If you are running MySQL 8.0, you can use window function lag() for this:
select
t.*,
ValuesCum - lag(ValuesCum, 1, 0) over(order by id) ValuesInc
from mytable t
In earlier versions, an alternative is a correlated subquery:
select
t.*,
ValuesCum - (
select coalesce(max(t1.ValuesCum), 0)
from mytable t1
where t1.id < t.id
) ValuesInc
from mytable t
You can use a correlated subquery to get the value of ValuesCum of the previous id:
select t.*,
t.ValuesCum -
coalesce((select ValuesCum from tablename where id < t.id order by id desc limit 1), 0) ValuesInc
from tablename t
See the demo.
Results:
| id | ValuesCum | ValuesInc |
| --- | --------- | --------- |
| 1 | 5 | 5 |
| 2 | 8 | 3 |
| 3 | 20 | 12 |

Loop through MySQL table in order. If value is 0 store cell value next to it. If not 0 update to stored value

I've tried a few PROCEDURES and LOOPS, but i'm having trouble getting my results.
I have a table of 19,000 records that looks like this:
id | seq | custom_id
1 | 0 | 123
2 | 0 | 124
3 | 1 | NULL
4 | 0 | 125
5 | 1 | NULL
6 | 2 | NULL
7 | 3 | NULL
My goal is:
id | seq | custom_id
1 | 0 | 123
2 | 0 | 124
3 | 1 | 124-1
4 | 0 | 125
5 | 1 | 125-1
6 | 2 | 125-2
7 | 3 | 125-3
So if seq is 0 it will have a custom ID. if seq is not 0 I would like to get the custom id and concat -seq to the end.
In a Correlated Subquery, we can get the previous (and closest) custom_id value where the seq is 0.
Now, we simply need to use Concat() function to concatenate the previous custom_id value with the current row's seq value, to get the new custom_id.
Try the following query to Select the data (DB Fiddle DEMO):
SELECT
t1.id,
t1.seq,
CASE WHEN t1.seq = 0 THEN t1.custom_id
ELSE CONCAT((SELECT t2.custom_id
FROM your_table AS t2
WHERE t2.id < t1.id AND
t2.seq = 0
ORDER BY t2.id DESC LIMIT 1), '-', t1.seq)
END AS custom_id
FROM your_table AS t1
However, based on your comments, it seems that you are interested in Updating the custom_id column at once. In MySQL, using subquery on the same table (which is being updated as well), is possible via Derived Tables approach.
We determine the modified custom_id for id where seq <> 0 in a sub-select result set (Derived table), and then Join it back to the main table for update.
Try the following for Updating the data (DB Fiddle DEMO):
UPDATE
your_table AS tab
JOIN
(
SELECT
t1.id,
CONCAT((SELECT t2.custom_id
FROM your_table AS t2
WHERE t2.id < t1.id AND
t2.seq = 0
ORDER BY t2.id DESC LIMIT 1),
'-', t1.seq) AS custom_id
FROM your_table AS t1
WHERE t1.seq <> 0
) AS dtab ON dtab.id = tab.id
SET tab.custom_id = dtab.custom_id
WHERE tab.seq <> 0;

MySQL : collect the sum of the associated values

I have three tables in database:
Table: article
id | code | name | quantity | stock_date
--------------------------------------------------
1 1dfod Article name 10 2016-04-01
Table: selling
id | client_id | selling_type_id | selling_date | selling_status
----------------------------------------------------------------
1 1 1 2016-04-02 1
2 1 1 2016-04-03 1
3 1 1 2016-04-04 1
Table: selling_detail
id | selling_id | article_id | quantity
-------------------------------------
1 1 1 2
2 1 1 3
3 1 1 1
4 2 1 3
5 3 1 1
at the end I would have a stock record for this article like this:
date | in_stock (item in stock) | out_stock (sum of item sold)
----------------------------------------------------------------------
2016-04-01 10 0
2016-04-02 0 6
2016-04-03 0 3
2016-04-04 0 1
All mysql queries to my knowledge do not give me this result.
Here is my code:
SELECT SUM(sd.quantity) out_stock, s.search_date, ifnull(ss.quantity, 0) in_stock
FROM selling_detail sd JOIN selling s ON (sd.selling_id = s.id)
LEFT JOIN shop_stock ss ON (ss.search_date = s.search_date) WHERE (sd.shop_stock_id = 1)
GROUP BY s.search_date;
SELECT date,SUM(in_stock) in_stock,SUM(out_stock) out_stock FROM
(
SELECT stock_date date,quantity in_stock,0 out_stock FROM article
UNION
SELECT selling_date,0,quantity FROM selling JOIN selling_detail ON selling_detail.selling_id = selling.id
) x
GROUP BY date;
As you are trying to combine similar data from two very different tables, you'll probably be staring down the barrel of a UNION ALL.
Something along these lines should get you started:
SELECT *
FROM (
SELECT a.stock_date `date`,
SUM(a.quantity) `in_stock (item in stock)`,
0 `out_stock (sum of item sold)`
FROM article a
WHERE a.id = :article_id
GROUP BY `date`
UNION ALL
SELECT s.selling_date,
0,
SUM(sd.quantity)
FROM selling s
JOIN selling_detail sd
ON sd.selling_id = s.id
AND sd.article_id = :article_id
/* WHERE s.selling_type = ??
AND s.selling_status = ?? /* If necessary */
GROUP BY `date`
) sr
ORDER BY `date`

MySQL count per item

I'm currently trying to make a mysql query that will count the number of zeros and ones per item, in the following way:
Table:
ID | PollID | Value
------------------------------------
1 | 1 | 1
2 | 1 | 1
3 | 2 | 0
4 | 2 | 1
5 | 1 | 0
And the result I want is:
Poll | one | zero
----------------------------------
1 | 2 | 1
2 | 1 | 1
Thanks for the help!
This is the shortest possible answer in MySQL because it supports boolean arithmetic.
SELECT PollID,
SUM(value = 1) AS `One`,
SUM(value = 0) AS `Zero`
FROM tableName
GROUP BY PollID
SQLFiddle Demo
select z.pollid,z.ones,s.zeros
from (select a.pollid,count(a.value) as ones from test a
where a.value=1
group by a.pollid) z
left join
(select b.pollid,count(b.value) as zeros from test b
where b.value=0 group by b.pollid) s
on z.pollid=s.pollid;
try this
select table.pollid,
Switch(table.value Like 1, 1)AS one,
Switch(table.value Like 0, 1)AS zero
from table
group by pollid

MySQL query on rows, only return row if row item does not exist in other rows

ID stone_free original_stone_id
------- | ---------- | -------------------
1 | 0 | 1
2 | 1 | 2
3 | 1 | 1
I would like to return rows from the table only if stone_free equals 0 and there is no corresponding original_stone_id in other rows for each row. So for example in the above example row 1 has stone_free as 0 and there is a corresponding original_stone_id in row 3, therefore the query shouldn't return any rows.
In the example below row 1 has stone_free as 0 but there is no corresponding original_stone_id in the other row, therefore the query should return row 1.
ID stone_free original_stone_id
------- | ---------- | -------------------
1 | 0 | 1
2 | 1 | 2
A simple LEFT JOIN should do it;
SELECT a.*
FROM Stones a
LEFT JOIN Stones b ON a.ID<>b.ID AND a.original_stone_id = b.original_stone_id
WHERE b.ID IS NULL AND a.stone_free=0
Demo here.
I'm not sure if it'll work on MySQL but give a shot to it
select *
from tbl
where stone_free = 0 and
(
select count(tab.original_stone_id)
from tbl tab
where tab.original_stone_id = tbl.original_stone_id
) = 1
Select * from tablename t1
Where stone_free = 0
And Not Exists (Select Id from tablename t2 where t2.original_stone_id = t1.original_stone_id And t2.Id <> t1.Id)