SQL : I want to compare 10 consecutive value - mysql

I am trying to solve a problem with SQL.
I have a SQL database which has a table named "data", in this table you have a row named "points". There is like 10000 float values in this row.
I want to make a desktop application that can compare 10 consecutive values ( which i manually enter ) to his nearest 10 consecutive values in the database.
exemple :
i want to compare this list of 10 values ( that i enter ):
10.1 , 25.4, 2, 35, 45, 78.9, 41.1, 44, 1, 65
to the best list of 10 values in my database where the 10 values are the nearest to my 10 entered values ( IMPORTANT : VALUES HAVE TO BE CONSECUTIVE ).
You can see below what i want to do, i want to get the list of the 10 consecutive values that is the nearest to the 10 values i want to compare.
points ( 10000 values... )
points row : 10, 15.5, 14.3, 2, 1, 10.2, 55, 65.3, 41, 10, 25.2, 3, 34, 44, 78.8, 41.2, 41, 2, 66, 44, 25.1, 33.2, 45, 75, 98, 12, 11.2 etc etc
The 10 values in bold are the best nearest consecutive values:
10 is near to 10.1
25.2 is near to 25.4
3 is near to 2
34 is near to 35
44 is near to 45
78.8 is near to 78.9
41.2 is near to 41.1
41 is near to 44
2 is near to 1
66 is near to 65
Is there any way to do this with SQL Command ?
Thanks in advance.

One option uses a row-limiting correlated subquery:
select v.val,
(select val from mytable t order by abs(t.val - v.val) limit 1) as match_val
from (
select 10.1 as val
union all select 25.4
union all ...
) v
Basically the subquery executes for each row in the from clause (which is where you put the list of values): it scans the table, orders rows by the difference with the original value, and brings the value of top row only.

SQL tables represent unordered sets. You need a column to specify the ordering.
You can use lag() or lead() to bring 10 values together. Then you need a definition of closest. One possibility is to take the absolute value of the differences and add them up:
select t.*
from (select t.*,
lead(val, 1) over (order by <ordercol>) as val_2,
lead(val, 2) over (order by <ordercol>) as val_3,
. . .
lead(val, 9) over (order by <ordercol>) as val_10
from t
) t
order by abs(val - $val_1) + abs(val_2 - $val_2) + . . .
limit 1;
The $val_1, $val_2, and so on represent the values that you are passing in.
The rest is just sorting and taking a limit.

Related

MySQL - How to use JSON_EXTRACT to get values between two indices

I am trying to extract values between 2 indices in a JSON array using mysql JSON_EXTRACT.
SELECT JSON_EXTRACT('[10, 20, 30, 40,50, 60]', '$[1]');
This query will smoothly return 20 as result. But if I want to get all the numbers between, say, 1st and 3rd indices, how do I query it?
I was expecting something like:
SELECT JSON_EXTRACT('[10, 20, 30, 40,50, 60]', '$[1]..$[3]'); // Not the proper syntax
which will return 20,30,40. But not working.
How do I achieve this?
SELECT JSON_EXTRACT('[10, 20, 30, 40,50, 60]', CONCAT('$[', idx, ']'))
FROM ( SELECT 1 idx UNION SELECT 2 UNION SELECT 3 ) src;
Of course the indices range can be provided as list/range and converted to rowset in CTE/subquery.

MySQL: Count rows with similar not duplicated content as one

I am working with Codeigniter and its Query Builder class where I have a table with IDs and names.
Those names look like 1234_1a or 2345_2a where 1a can be 1b or 2a,2b,3a... and so on.
Now I want to count all these "1234" and "2345" but write them as one type.
So far I tried with:
$this->db->like('names', '1a', 'before');
$this->db->or_like('names', '1b', 'before');
return $this->db->count_all_results('table');
But the problem:
What if there is 3456_2a but no 3456_1a, than it doesn't work anymore...
id name
2 1212_1a
3 1243_1a
7 3142_1a
24 1243_2a
30 3142_2b
80 2315_2b
136 1243_3b
512 8562_1a
This is how I would like it:
Result:
name count
1212 1
1243 1
3142 1
2315 1
8562 1
If we always want to return a count value of 1, when the count of the number of rows in more than 1 ... then we aren't really returning a count.
And what is the pattern of the names... do they end with a digit and a letter, or is that underscore character important too?
What is to be done with name values such as 12345a or 5678_b2 or 11_22_3b? How are those to be handled?
Seems to me like we want to use a SQL query like this:
SELECT SUBSTRING_INDEX(t.name,'_',1) AS `foo`
, 1 AS `count`
FROM (
SELECT 2 AS `id`, '1212_1a' AS `name`
UNION ALL SELECT 3, '1243_1a'
UNION ALL SELECT 7, '3142_1a'
UNION ALL SELECT 24, '1243_2a'
UNION ALL SELECT 30, '3142_2b'
UNION ALL SELECT 80, '2315_2b'
UNION ALL SELECT 136, '1243_3b'
UNION ALL SELECT 512, '8562_1a'
) t
GROUP BY `foo`
ORDER BY `foo`
The inline view (derived table) is in the query for testing. Replace that with the table reference:
SELECT SUBSTRING_INDEX(t.name,'_',1) AS `foo`
, 1 AS `count`
FROM mytable t
GROUP BY `foo`
ORDER BY `foo`
The expression for foo may need to be adjusted, to get desirable behavior with values that don't follow the regular pattern. Consider name values with no underscore, with more than one underscore, with endings other than a digit. We could also include a WHERE clause to exclude rows that don't follow the pattern,
WHERE t.name REGEXP '_[0-9][a-z]$'
(only name values that end with underscore, digit, lowercase letter).
Without a tested SQL query, I wouldn't know what to implement in CodeIgniter Query Builder.

How do you create a query to find number of entries between a range in Microsoft Access?

I have a table right now that has a list of numbers (some repeating) that goes from 0 to 350.
Is it possible to write a query in Microsoft Access to return how many numbers in the set belong to a range?
For example, if the set of data is 0, 1, 2, 3, 4, 5, 6, 7, I want to create a query to return how many numbers below to the range between 3 and 6 (inclusive). In this example, it would return 4 since the numbers 3, 4, 5 and 6 are in this range.
Thanks.
Have you ever used the 'COUNT' function in a query?
If not, use the query builder to select your number column TWICE from the table.
Add a criteria on your range of 3 to 6.
Set the query to 'Totals' see toolbar), then change your Criteria column to 'WHERE' (in the 'Totals' row),and change the other column to 'COUNT' (in the Totals row)
i.e
SELECT Count(Table1.ID) AS CountOfID
FROM Table1
WHERE (((Table1.ID) Between 1 And 15));

MySQL: Sub-query troubles

So I am attempting my very first sub query and ran into a small problem... Why is the query not taking into account my WHERE clause?
My query:
SELECT *
FROM Product
WHERE stdUnitPrice < 5*
(SELECT MIN(stdUnitPrice)
FROM Product
WHERE discontinued = 'A')
But in the results I am still getting values in the discontinued column that are NOT just 'A'
Here are the results:
# productId, prodName, stdUnitPrice, qtyPerUnit, discontinued
3, Aniseed Syrup, 11.00, 12 - 550 ml bottles, A
13, Konbu, 6.60, 2 kg box, A
19, Teatime Chocolate Biscuits, 10.12, 10 boxes x 12 pieces, A
21, Sir Rodney's Scones, 11.00, 24 pkgs. x 4 pieces, A
23, Tunnbrod, 9.90, 12 - 250 g pkgs., A
**24, Guarana Fantastica, 4.95, 12 - 355 ml cans, D**
33, Geitost, 2.75, 500 g, A
41, Jack's New England Clam Chowder, 10.61, 12 - 12 oz cans, A
45, Rogede sild, 10.45, 1k pkg., A
46, Spegesild, 13.20, 4 - 450 g glasses, A
47, Zaanse koeken, 10.45, 10 - 4 oz boxes, A
52, Filo Mix, 7.70, 16 - 2 kg boxes, A
54, Tourtiere, 8.19, 16 pies, A
74, Longlife Tofu, 11.00, 5 kg pkg., A
75, Rhonbrau Klosterbier, 8.52, 24 - 0.5 l bottles, A
78, Bob's Down Home Juice, 7.90, 6 pack, A
Try this:
select *
from Product
where stdUnitPrice < (5 * (select min(stdUnitPrice) from Product ) )
and discontinued = 'A'
It appears as though MySQL is looking at the where and thinking stdUnitPrice < 5
As well, your where needs to be on the main query.
Try moving your math into the subquery like so:
SELECT *
FROM Product
WHERE stdUnitPrice <
(SELECT 5*MIN(stdUnitPrice)
FROM Product)
AND discontinued = 'A'
So the reasoning for this not working the way you want it to is because you are missing the where clause in your first query. Let me break it down a little for you.
select * from Product where stdUnitPrice < 5* (select min(stdUnitPrice) from Product where discontinued = 'A')
so in this query the sub query gets executed first so lets assume that we set the sub query to a variable:
var subquery = select min(stdUnitPrice) from Product where discontinued = 'A';
Now after that subquery is executed it is then plugged back into the original query like so: (using the new variable name)
select * from Product where stdUnitPrice < 5 * (subquery);
so to get this to include a where discontinued = 'A' you would need to change your query to the following:
SELECT * FROM Product WHERE stdUnitPrice < 5 * (SELECT MIN(stdUnitPrice) FROM Product WHERE discontinued = 'A') AND discontinued = 'A';
I hope this helps.
EDIT: Just to clarify you can't actually use a variable like that im just using that as an example to show how the query will actually be executed.
You are performing an aggregate subset operation that is filtered, however, your main query will return all rows. You are basically asking to return all rows * the minimum value in the table. You need t return the minimum value within all rows that match your selection clause.

ORDER BY FIELD not working - error message

I have this Select:
SELECT pts_name
FROM products_tecspecs
WHERE pts_id IN ( 5275, 21, 5276, 5277,
5278, 49, 5279 )
ORDER BY FIELD (pts_id, 5275, 21, 5276, 5277, 5278, 49, 5279)
I am trying to get the result and order it the way I want. I found this answer but got this error: #1305 - FUNCTION database_name.FIELD does not exist
I am trying to get specifics results with IN (that's working), but sorting the way I want.
Help you be apreciated.
Remove the space between the function and the parenthesis: FIELD (
MySQL parser does not like spaces there. Use:
FIELD(pts_id, ...)
you can also try subquery to order by records in custom order
SELECT pts_name
FROM (SELECT pts_name,
CASE pts_id
WHEN 5275 THEN 1
WHEN 21 THEN 2
WHEN 5276 THEN 3
WHEN 5277 THEN 4
WHEN 5278 THEN 5
WHEN 49 THEN 6
WHEN 5279 THEN 7
END AS sort_order
FROM products_tecspecs
WHERE pts_id IN ( 5275, 21, 5276, 5277, 5278, 49, 5279)
) a
ORDER BY a.sort_order ASC ;