I have a ton of positions saved in a database in the following format
Examples:
[32.306,[7195.4,9414.24,0.005]]
[219.184,[7197.41,9416.66,-0.003]]
[161.215,[1170.26,4852.79,3.815e-04]]
[37.338,[479.163,3757.15,-0.005]]
[11.719,[12436.5,4780.36,-9.46e-04]]
The coordinates are in the format [DIRECTION,[X,Y,Z]]
I would like to replace all of the Z coordinates with 0. Been struggling with finding the correct way of doing this in an SQL query.
Query:
SQLFIDDLEExample
CONCAT(SUBSTRING_INDEX(col,',',3), ',0]]') col
Result:
| COL |
|-------------------------------|
| [32.306,[7195.4,9414.24,0]] |
| [219.184,[7197.41,9416.66,0]] |
| [161.215,[1170.26,4852.79,0]] |
| [37.338,[479.163,3757.15,0]] |
| [11.719,[12436.5,4780.36,0]] |
I would chop up the your string field using SUBSTRING and cast the values to floats and store them in 4 different fields (direction, x, y and z).
Then you can easily update the Z value (and any other value)
When you need the more complex string representation, just concatenate the 4 fields by casting it back to varchar.
Related
I have this type of string
'160f7a4a-766a-4c23-a155-8bd3f7389f77\', \'63233bfc-b663-4c73-890b-00a48d79c4dc'
In one column and I want like
'160f7a4a-766a-4c23-a155-8bd3f7389f77','63233bfc-b663-4c73-890b-00a48d79c4dc'
This type of result in MySQL
i have to perform query like
SELECT * FROM kapp_staging.kols where `kol_id` in (select REPLACE(json_id,'\'',"'") FROM kapp_staging.news_items
where `id` = '991'))
in where in clause i have subquery and in subquery
i geting
'160f7a4a-766a-4c23-a155-8bd3f7389f77\', \'63233bfc-b663-4c73-890b-00a48d79c4dc'
this type of value
so i need to remove \ from value so my where in query work fine.
i have data like:
Kols table
| id | kol_id | name | data |
|----|---------------------------------------- |---------| ------|
| 1 |160f7a4a-766a-4c23-a155-8bd3f7389f77 | balwant | data |
| 2 |63233bfc-b663-4c73-890b-00a48d79c4dc | vikram | data |
news items
| id | json_id | data |
|----|-----------------------------------------------------------------------------------------|---------|
| 991 | {'\160f7a4a-766a-4c23-a155-8bd3f7389f77\','\160f7a4a-766a-4c23-a155-8bd3f7389f77\'} | data |
I tried many ways but didn't get this response.
Thanks in Advance : )
The backslashes aren't in the data, they're just used to escape the quotes when inserting into the table. So you don't need to remove them.
However, you can't use IN to match values in a comma-delimited list, you need to use FIND_IN_SET(); see Search with comma-separated value mysql
You also need to remove the quotes and curly braces before you can use FIND_IN_SET().
SELECT DISTINCT k.*
FROM kols AS k
JOIN news_items AS n
ON FIND_IN_SET(k.kol_id,
REPLACE(REPLACE(REPLACE(json_id, '{', ''), '}', ''), "'", ''))
DEMO
Things would be much easier if you normalized your data and put the list of IDs into a separate table with one row per ID.
The MySQL database I am working with has a column with comma separated values similar to -
mysql> select * from performance;
+----+------------------+
| id | maximums |
+----+------------------+
| 1 | 10000RPM, 60KM/h |
| 2 | 5000RPM, 30KM/h |
| 3 | 25mph, 3000RPM |
| 4 | 200KM/h, 2000RPM |
+----+------------------+
4 rows in set (0.00 sec)
I am trying to cast the numbers found in to their own INT columns.
mysql> select maximums,
CASE WHEN maximums like "%mph%" THEN CAST(SUBSTRING_INDEX(maximums, 'mph', 1) AS UNSIGNED) END AS mph_int,
CASE WHEN maximums like "%KM/h%" THEN CAST(SUBSTRING_INDEX(maximums, 'KM/h', 1) AS UNSIGNED) END AS kmh_int,
CASE WHEN maximums like "%RPM%" THEN CAST(SUBSTRING_INDEX(maximums, 'RPM', 1) AS UNSIGNED) END AS rpm_int
from performance;
+------------------+---------+---------+---------+
| maximums | mph_int | kmh_int | rpm_int |
+------------------+---------+---------+---------+
| 10000RPM, 60KM/h | NULL | 10000 | 10000 |
| 5000RPM, 30KM/h | NULL | 5000 | 5000 |
| 25mph, 3000RPM | 25 | NULL | 25 |
| 200KM/h, 2000RPM | NULL | 200 | 200 |
+------------------+---------+---------+---------+
4 rows in set, 4 warnings (0.00 sec)
I expect the output to show me the values as INTs in new columns, however am unsure how to achieve this.
Let's give this a whirl, using the good ol'-fashioned blunt instrument approach. I am guessing that you only need this to work once, to convert an old, poorly-designed schema into something more workable. Given that, I have made no effort at elegance or performance.
(If you are not using this to fix your data schema, you should, because the pain you are experiencing now is only the beginning.)
First, we need to split the maximums value into two pieces and process them separately. The first half is:
SUBSTRING_INDEX(`maximum`, ',', 1)
The second half is similar, but there is a stray space:
TRIM(SUBSTRING_INDEX(`maximum`, ',', -1))
From here on, let's just always trim, in case there is variation in the data. Now we need to see if the first section has 'mph' in it, and if so capture the value as you did in your question (this is essentially like your example but operating on only the first part of the maximum value):
IF(TRIM(SUBSTRING_INDEX(`maximum`, ',', 1)) LIKE '%mph', SUBSTRING_INDEX(TRIM(SUBSTRING_INDEX(`maximum`, ',', 1)), 'mph', 1), NULL)
Let's name that chunk of code "mph test on first half". The mph test on the second half is almost identical, just using -1 as the index. Finally, we need to put the non-null value (if either) into the column using COALESCE. Once we create all six variations of the test, we end up with the following:
SELECT
...
COALESCE([mph test on first half], [mph test on second half]) AS mph_int,
COALESCE([kph test on first half], [kph test on second half]) AS kph_int,
COALESCE([rpm test on first half], [rpm test on second half]) AS rpm_int
WHERE
...
Chances are you don't actually need to formally cast the string of digits into an integer; if you are inserting into a table with columns of those types, MySQL will cast the value for you.
I'm storing a object / data structure like this inside a MySql (actually a MariaDb) database:
{
idx: 7,
a: "content A",
b: "content B",
c: ["entry c1", "entry c2", "entry c3"]
}
And to store it I'm using 2 tables, very similar to the method described in this answer: https://stackoverflow.com/a/17371729/3958875
i.e.
Table 1:
+-----+---+---+
| idx | a | b |
+-----+---+---+
Table 2:
+------------+-------+
| owning_obj | entry |
+------------+-------+
And then made a view that joins them together, so I get this:
+-----+------------+------------+-----------+
| idx | a | b | c |
+-----+------------+------------+-----------+
| 7 | content A1 | content B1 | entry c11 |
| 7 | content A1 | content B1 | entry c21 |
| 7 | content A1 | content B1 | entry c31 |
| 8 | content A2 | content B2 | entry c12 |
| 8 | content A2 | content B2 | entry c22 |
| 8 | content A2 | content B2 | entry c32 |
+-----+------------+------------+-----------+
My question is what is the best way I can get it back to my object form? (e.g. I want an array of the object type specified above of all entries with idx between 5 and 20)
There are 2 ways I can think of, but both seem to be not very efficient.
Firstly we can just send this whole table back to the server, and it can make a hashmap with the keys being the primary key or some other unique index, and collect up the different c columns, and rebuild it that way, but that means it has to send a lot of duplicate data, and take a bit more memory and processing time to rebuild on the server. This method also won't be very pleasant to scale if we have multiple arrays, or have arrays within arrays.
Second method would be to do multiple queries, filter Table 1 and get back the list of idx's you want, and then for each idx, send a query for Table 2 where owning_obj = current idx. This would mean sending a whole lot more queries.
Neither of these options seems very good, so I'm wondering if there is a better way. Currently I'm thinking it can be something that utilizes JSON_OBJECT(), but I'm not sure how.
This seems like a common situation, but I can't seem to find the exact wording to search for to get the answer.
PS: The server interfacing with MySql/MariaDb is written in Rust, don't think this is relevant in this question though
You can use GROUP_CONCAT to combine all the c values into a comma-separated string.
SELECT t1.idx, t1.a, t1.b, GROUP_CONCAT(entry) AS c
FROM table1 AS t1
LEFT JOIN table2 AS t2 ON t1.idx = t2.owning_obj
GROUP BY t1.idx
Then explode the string in PHP:
$result_array = [];
while ($row = $result->fetch_assoc()) {
$row['c'] = explode(',', $row['c']);
$result_array[] = $row;
}
However, if the entries can be long, make sure you increase group_concat_max_len.
If you're using MySQL 8.0 you can also use JSON_ARRAYAGG(). This will create a JSON array of the entry values, which you can convert to a PHP array using json_decode(). This is a little safer, since GROUP_CONCAT() will mess up if any of the values contain comma. You can change the separator, but you need a separator that will never be in any values. Unfortunately, this isn't in MariaDB.
In a MySQL-table I have a VARCHAR-column with different values, which may represent String-, Integer-, Float-, Whatever-Values. These Values are written as a language-specific String into the Database, this means a float-value of 123.45 may be written as a String like "123,45" in german language (using VB.Net...)
As I need average values of float-values wich are in the same group:
How can I cast such a string to a FLOAT within MySQL?
Simply AVG(CONVERT(value, DECIMAL)) won't work (returns 99.00000), conversion to FLOAT is not possible.
Charset is utf8, Collation is utf8_general_ci.
Sample table:
id | value | group
1 | 122,45 | 1
2 | 66,34 | 1
3 | blabla | 2
4 | 109,21 | 1
5 | bababa | 2
Goal: somethig like SELECT AVG(CONVERT(value, DECIMAL)) FROM table WHERE (group=1) should result in 99.333333, not 99.
Any Ideas?
Christoph
PS.: I did not make that database-layout...
You could try
SELECT AVG(CONVERT(
REPLACE(REPLACE(value, '.', ''), ',', '.'),
DECIMAL(10,2)))
FROM `table`
WHERE `group`=1
The string function format(x,d,locale) should do exactly what you want. See https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_format
In a MySQL-table I have a VARCHAR-column with different values, which may represent String-, Integer-, Float-, Whatever-Values. These Values are written as a language-specific String into the Database, this means a float-value of 123.45 may be written as a String like "123,45" in german language (using VB.Net...)
As I need average values of float-values wich are in the same group:
How can I cast such a string to a FLOAT within MySQL?
Simply AVG(CONVERT(value, DECIMAL)) won't work (returns 99.00000), conversion to FLOAT is not possible.
Charset is utf8, Collation is utf8_general_ci.
Sample table:
id | value | group
1 | 122,45 | 1
2 | 66,34 | 1
3 | blabla | 2
4 | 109,21 | 1
5 | bababa | 2
Goal: somethig like SELECT AVG(CONVERT(value, DECIMAL)) FROM table WHERE (group=1) should result in 99.333333, not 99.
Any Ideas?
Christoph
PS.: I did not make that database-layout...
You could try
SELECT AVG(CONVERT(
REPLACE(REPLACE(value, '.', ''), ',', '.'),
DECIMAL(10,2)))
FROM `table`
WHERE `group`=1
The string function format(x,d,locale) should do exactly what you want. See https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_format