Select Min value from a group without first row - mysql

Hello I want one query with one objective...
Select the min value from a field for example:
id | row | value
-----------------------
8 | 1 | 0.9
7 | 1 | 0.8
6 | 1 | 0.7
5 | 1 | 0.6
4 | 2 | 0.5
3 | 2 | 0.4
2 | 3 | 0.3
1 | 1 | 0.2
I need to select the min value from this table where row = '1' in this case is id = 1 right? BUT I don't want the id = 1, I want only the min value from the first continuos row, in this case is the id = 5 because row = '1' have the id 8, 7, 6, 5, and the min value is 0.6, the id = 5.
What query I need?

I think you're after this, but it's very hard to tell...
SELECT x.*
FROM my_table x
JOIN my_table y
ON y.id = x.id + 1
AND y.row = x.row
WHERE x.row = 1
ORDER
BY x.value
LIMIT 1;

Try something like:
SELECT min(value), id
WHERE value > (SELECT min(value)
FROM MyTable
WHERE row = 1)
AND row = 1
GROUP BY id;
Inner query will find min value for row as 1 while outer query will find next min value that is greater than min value we got in inner query.

Related

MySQL Update table by matchig values in the same column

I have a table where I store data for different groups and I need to update one group if values in one column are matching.
the table looks like this:
prop_id | group_id | value | visible
1 | 1 | 10 | 1
1 | 2 | 10 | 1
1 | 3 | 15 | 1
2 | 1 | 10 | 1
2 | 2 | 10 | 1
2 | 3 | 10 | 1
So I want to set the visible column to 0 for the group_id=3 if the values in the value column are equal to group_id=1. In this case if value=10 for both group_id=1 and group_id=3 than set visible=0 for group_id=3
expected result after update
prop_id | group_id | value | visible
1 | 1 | 10 | 1
1 | 2 | 10 | 1
1 | 3 | 15 | 1
2 | 1 | 10 | 1
2 | 2 | 10 | 1
2 | 3 | 10 | 0
How is this possible?
Write it as a SELECT first.
Start simple, the rows that we want to update we know are group_id=3 and visible=1, so write a query that gets all of those rows:
SELECT g3.value
, g3.visible
FROM mytable g3
WHERE g3.group_id = 3
AND g3.visible = 1
We know the rows we want to update are in that set, but there are some additional conditions.
So we extend that. According to the spec, we need to find out if there are any matching group_id=1 rows that are visible=1 (matching on value).
We can do that check either with an EXISTS correlated subquery, or we can use a JOIN.
SELECT g3.group_id
, g3.value
, g3.visible
FROM mytable g3
WHERE g3.group_id = 3
AND g3.visible = 1
AND EXISTS ( SELECT 1
FROM mytable g1
WHERE g1.group_id = 1
AND g1.visible = 1
AND g1.value = g3.value
)
-or-
SELECT g3.group_id
, g3.value
, g3.visible
FROM mytable g3
JOIN mytable g1
ON g1.group_id = 1
AND g1.visible = 1
AND g1.value = g3.value
WHERE g3.group_id = 3
AND g3.visible = 1
Verify the query is returning the rows we want to update, under the specific conditions. (It is much easier to verify the results of a SELECT statement, and adjust as necessary, than it is an UPDATE statement.)
Once we have a SELECT query working and verified (returning the rows we want to update) we can convert it into an UPDATE statement. Replace the SELECT ... FROM with UPDATE and add a SET clause that is returning the rows
UPDATE mytable g3
JOIN mytable g1
ON g1.group_id = 1
AND g1.visible = 1
AND g1.value = g3.value
SET g3.visible = 0
WHERE g3.group_id = 3
AND g3.visible = 1
Use Self JOIN then UPDATE
You can try this.
UPDATE T t1
JOIN T t2 on t1.group_id = t2.group_id
and t1.rop_id<>t2.rop_id and t1.value > t2.value
SET t2.visible = 0
sqlfiddle:http://sqlfiddle.com/#!9/6f06de/1

SQL query for rolling changes

I have the following two tables:
1) Table name: period
+----------+
| PeriodID |
+----------+
| 1 |
| 2 |
| 3 |
| 4 |
+----------+
2) Table name: value
+-------------+--------+
| StartPeriod | Amount |
+-------------+--------+
| 1 | 100 |
| 3 | 200 |
+-------------+--------+
The first table represents time periods, like months. The second table represents the amount for each month, but only when it's different from the previous month. The amount starts at 100, stays at 100 for period 2, then jumps up to 200 beginning in period 3, and stays at 200 after that.
I need a query (MySQL) to return the amount for each period, like so:
+----------+--------+
| PeriodID | Amount |
+----------+--------+
| 1 | 100 |
| 2 | 100 |
| 3 | 200 |
| 4 | 200 |
+----------+--------+
So the query would return the Amount for the latest StartPeriod in the value table that's less than or equal to the PeriodID. For example, for PeriodID 2 it returns the Amount for StartPeriod 1 because there is no value for StartPeriod2 and 1 is the largest number less than or equal to 2 that has an Amount in the value table.
(Sorry the tables are so ugly)
Thank you!
You can do it using a correlated sub-query:
SELECT PeriodID,
(SELECT Amount
FROM Value
WHERE StartPeriod <= PeriodID
ORDER BY StartPeriod DESC LIMIT 1) AS Amount
FROM Period AS p
Demo here
Using variables probably performs better compared to the correlated sub-query:
SELECT PeriodID,
#amount := IF(Amount IS NOT NULL, Amount, #amount) AS Amount
FROM (
SELECT PeriodID, Amount
FROM Period AS p
LEFT JOIN Value AS v ON p.PeriodID = v.StartPeriod) AS t
CROSS JOIN (SELECT #amount := -1) AS var
ORDER BY PeriodID
Demo here
A simple subselect that selects the value for the highest startperiod lower or equal to the period-id could achive that:
select
periodid,
(select amount from value where startperiod <= periodid order by startperiod desc limit 1)
from period
order by periodid;
http://sqlfiddle.com/#!9/9f29c/3

Count considering sum of 3 columns

I have 3 column (prod1 , prod2 , prod3 ) with TYPE : DOUBLE
id | prod1 | prod2 | prod3 |
1 | 1.3 | 2.6 | 2.8 |
2 | 0.8 | 3.4 | 0 |
3 | 0 | 0 | 1.3 |
4 | 0 | 0 | 0 |
What I want is COUNT() of 3 columns
SELECT count(prod1,prod2,prod3) AS allc
FROM `testprd`
WHERE id =3
I know above code is wrong
SHOULD GIVE RESULT
allc
-------
1
As prod1 and prod2 have 0 values
Similarly when id = 4 count should be 0 as all column for resp id have zero value ,but when id = 1 then count should be 3
Hence I taught count for each id columns and then sum of all , will result me solution but am not able to reach it.
BELOW IS WHAT I HAVE TRIED
SELECT count(prod1) AS a,
count(prod2) AS b,
count(prod3) AS c
FROM `testprd`
WHERE id =3
Result:
a | b | c
-------------
1 1 1
But should be:
a | b | c
-------------
0 0 1
So sum(a+b+c) = 1
Hence count for id = 3 is 1
What am I doing wrong?
You could get the result you want to have with
SELECT
(prod1 !=0 ) + (prod2 != 0) + (prod3 != 0) AS allc
FROM `testprd`
WHERE id = 3
The aggregate function COUNT counts rows in a table or not null rows in a certain column, but not the values that are not equal zero in a set of columns.
COUNT(expr)
Returns a count of the number of non-NULL values of expr in the rows
retrieved by a SELECT statement. The result is a BIGINT value.
COUNT() returns 0 if there were no matching rows.
Use
SELECT id, if(prod1+prod2+prod3>0,1,0) from testprd;
For all columns separated it should be:
SELECT id, if(prod1>0,1,0), if(prod2>0,1,0), if(prod3>0,1,0) from testprd;
Use a simple query like this
SELECT
IF(prod1 > 0,1,0)+IF(prod2 > 0,1,0)+IF(prod3 > 0,1,0) as Total
FROM test
WHERE id = 3;
SQL Fiddle Demo
OUTPUT
| TOTAL |
|-------|
| 1 |
Just check if that product is different from zero then sum all counts like:
SELECT if(prod1!=0,1,0) +
if(prod1!=0,1,0) +,
if(prod1!=0,1,0) AS ct
FROM `testprd`
WHERE id =3
How about:
SELECT
count(*) AS allc FROM `testprd`
WHERE
id =3 AND
0 < ANY (prod1, prod2, prod3);
COUNT counts the rows slected by your SELECT statement, it does not sum up the column values.
SELECT prod1 + prod2 + prod3 AS mySum
FROM `testprd`
WHERE id =3;
See the MySQL doc concerning Arithmetic Operators and COUNT

What the proper way of using "WHERE" clause when it needs to fetch data by approximate value of some field?

+-------+
| value |
+-------+
| 13.00 |
| 15.00 |
| 17.50 |
| 18.00 |
| 18.10 |
| 18.30 |
| 19.90 |
| 20.00 |
| 20.30 |
| 20.60 |
+-------+
SELECT * FROM `table` WHERE `value` = 19;
I want retrieve rows which contains value from 18.00 to 20.60 (plus or minus 2)
Number 19 I'm geting by POST.
You can use between
SELECT * FROM table
WHERE value between $posted_value - 2 and $posted_value + 2
EDIT
If you want a range of +2 or -2, the most efficient way to do that would be:
SELECT t.*
FROM `table` t
WHERE t.value >= 19 - 2.0
AND t.value <= 19 + 2.0
ORDER BY t.value
original
To get just the value column from the seven rows with values "closest" to 19, calculate the difference between 19 and the value in the value column, take the absolute value of the difference, and then sort by that. Then limit the number of rows returned:
SELECT s.value
FROM (
SELECT s.value
FROM `table` s
ORDER BY ABS(19.0-s.value)
LIMIT 7
) s
ORDER BY s.value
To get the entire row, for the rows with the values "closest" to 19, you could do the same query, but also retrieve a unique identifier from the row, and then perform a join to the original table, for example:
SELECT t.*
FROM (
SELECT r.id
, r.value
, ABS(19.0-r.value) AS `absdiff`
FROM `table` r
ORDER BY ABS(19.0-r.value)
LIMIT 7
) s
JOIN `table` t
ON t.id = s.id

MySQL: How to return only one row based on criteria within a resultset

I have the following table:
id | group | value
1 | 1 | 10
2 | 1 | 20
3 | 1 | 30
4 | 0 | 20
5 | 0 | 20
6 | 0 | 10
I want to return the highest value where the group is 1 (=30) and all of the values where the group is 0, into one resultset.
I have to do this in one statement, and I guess I should use an IF statement within a SELECT statement, but I can't work out how. Can anyone help to point me in the right direction?
(select max(value) from the_table where group = 1)
union
(select value from the_table where group = 0)
If (group +value) is unique, you can also do it without union (as proposed by Ray Toal)
SELECT a.value
FROM table1 a
WHERE a.`group`=0 or (a.`group`=1 AND a.value =
(SELECT MAX(value) FROM table1 b WHERE b.`group`=1))