replace() concat() and substr() add character at specific location in string cannot get the position right - mysql

End result: all 3 fields should be merged (solved OK), and the character "T" should be added as the 5th character in the merged string (no other characters should be removed or altered in sequence). (see all specifics below).
What am I doing wrong?
Data is in the following format:
data1: AL
data2: 33 0230S 0440E
data3: SW
Here is my current sql:
replace(concat(b.data1,
substr(b.data2, 4, 1),
'T',
substr(b.data2, 1),
b.data3), ' ', '')
AS MergedData
The final output should look like:
AL33T0230S0440ESW
I've been able to get the "T" placed at random locations, but cannot get it consistently added as the 5th character from the start of the string.

Use:
replace only on data2 (because that's the only field that needs it), then
concat() to join it all up, and finally
the insert() function to insert the T
(Don't use substr at all)
insert(concat(data1, replace(data2, ' ', ''), data3), 5, 0, 'T')
Here's a test:
set #data1 := 'AL', #data2 := '33 0230S 0440E', #data3 := 'SW';
select
insert(concat(#data1, replace(#data2, ' ', ''), #data3), 5, 0, 'T')
as MergedData;
Output:
+-------------------+
| MergedData |
+-------------------+
| AL33T0230S0440ESW |
+-------------------+

Random locations seems odd, this seems to work though;
replace(concat(b.data1,
substr(b.data2, 1, 2),
'T',
substr(b.data2, 4),
b.data3), ' ', '')
Demo here.

Find the position of the first space in data2, replace it with T, remove the rest of the spaces in the resulting string, then concatenate it with the two other values:
CONCAT(
b.data1,
REPLACE(INSERT(b.data2, LOCATE(' ', b.data2), 1, 'T'), ' ', ''),
b.data3
) AS MergedData

Related

Exact strings in a column in SQL

I am trying to use mysql to solve the question below.
Any idea how should I make it work? Thank you.
Tried to use the code below but extracted duplicate strings in two columns and it's hard-code so it's not working..
SELECT itemid, SUBSTRING_INDEX(SUBSTRING_INDEX(item_variation, ',', 1), ',', -1) 'type one',
SUBSTRING_INDEX(SUBSTRING_INDEX(item_variation, ',', 2), ',', -1) 'type two',
SUBSTRING_INDEX(SUBSTRING_INDEX(item_variation, ',', 3), ',', -1) 'type three',
SUBSTRING_INDEX(SUBSTRING_INDEX(item_variation, ',', 4), ',', -1) 'type four'
FROM data
Question:
To extract items with more than 3 types
|itemid|shopid|item_name|item_type|price|stock|creation_date|
|1|10000|clothes|{}|5|100|27/1/2018|
|2|10000|dress|{Pink: 20, Black: 20, Grey: 20}|20|100|20/2/2018|
|3|10001|t-shirt|{S: 2, M: 2, L: 2, XL: 2}|2|50|1/1/2018|
|4|10002|socks|{us5.5: 1, us9: 1, us4.5: 1, us10: 1, us7: 1, us6: 1, us5: 1}|1|1000|4/1/2018|
|5|10002|Gloves|{S: 2, M: 2}|2|500|6/1/2018|
Expected result
|itemid |item_name |item_type|
|3 |t-shirt |{S: 2, M: 2, L: 2, XL: 2}|
|4 |socks |{us5.5: 1, us9: 1, us4.5: 1, us10: 1, us7: 1, us6: 1, us5: 1}|
This ought to do:
select itemid, item_name, item_type
from t
where length(item_type) - length(replace(item_type, ',', '')) >= 3;
You need a special case to tell 0 and 1 apart. It would not work if item_type contains ',' in either key or value of the json-like field (missing quoted around strings to be json).
You just need to count number of comma(,)>=3. Try below code:
SELECT
Itemid,Item_Name,Item_type
FROM myjson
where ROUND (
(
LENGTH(item_type)
- LENGTH( REPLACE ( item_type, ",", "") )
) / LENGTH(",")
)>=3

BLEU - Error N-gram overlaps of lower order

I ran the code below
a = ['dog', 'in', 'plants', 'crouches', 'to', 'look', 'at', 'camera']
b = ['a', 'brown', 'dog', 'in', 'the', 'grass', ' ', ' ']
from nltk.translate.bleu_score import corpus_bleu
bleu1 = corpus_bleu(a, b, weights=(1.0, 0, 0, 0))
print(bleu1)
This is the error
The hypothesis contains 0 counts of 3-gram overlaps. Therefore the
BLEU score evaluates to 0, independently of how many N-gram overlaps
of lower order it contains. Consider using lower n-gram order or use
SmoothingFunction() warnings.warn(_msg)
Can someone tell me what is the problem here? I can not find the solution on google. Thank you.
Best,
DD
I found the solution. Basically, I need a list inside a list for list 'a'. So code below will work without error.
a = [['dog', 'in', 'plants', 'crouches', 'to', 'look', 'at', 'camera']]
b = ['a', 'brown', 'dog', 'in', 'the', 'grass', ' ', ' ']
from nltk.translate.bleu_score import corpus_bleu
bleu1 = corpus_bleu(a, b, weights=(1.0, 0, 0, 0))
print(bleu1)

MySQL JSON: finding value of sibling element in sub-array

I have the following (pseudo)JSON in a type JSON (LONGTEXT) column in my MariaDB 10.2
{"order":
{"otherstuff":...},
{"dates":
[
{
"typeId":2,
"date":"2019-05-21 09:00:00"
},
{
"typeId":4,
"date":"2019-05-21 10:00:00"
}
]
}
}
What I need is the order's date while I know which type I need (4).
An order can have a number of dates identified by their typeId. typeId 4 is not always in second position.
SELECT JSON_UNQUOTE(JSON_SEARCH(`json`, 'one', 4, NULL, '$.dates[*].typeId'))
// gives me: $.dates[1].typeId
My first thought now was to REPLACE typeId with date, but that complains about mixed collations.
How would I (more elegantly) reference the 'date' value here?
Also, the query is supposed to be the expression of a GENERATED column in my table. Since date id4 is not necessarily there for every order, I tried this:
SELECT IF(4 IN (JSON_EXTRACT(json, '$.dates[*].typeId')), 'yes', 'no')
// above condition evaluates to [2, 4]
I have trimmed away '[' and ']' but then it only gives me a 'yes' if 4 is first in the array (is it an array?).
So (without brackets):
[4, 7] -> yes
[2, 4] -> no
I'm assuming this doesn't get recognized as an array of values but a string. Then why does it give me 'yes' if my needle is in first position?
Instead of yes and no I obviously want to use the date and NULL.
The MySQL JSON functions are quite new to me. So maybe someone could point me in the right direction?
Try:
Option 1:
SELECT
JSON_UNQUOTE(
JSON_EXTRACT(
`json`,
REPLACE(
JSON_UNQUOTE(
JSON_SEARCH(
`json`,
'one',
4,
NULL,
'$.order.dates[*].typeId'
)
),
'typeId',
'date'
)
)
) `date`;
Option 2:
SELECT
IF(
JSON_CONTAINS(
JSON_EXTRACT(
`json`,
'$.order.dates[*].typeId'
),
4
),
'yes',
'no'
) `exists`;
See dbfiddle.

Sum the digits of a number in mysql

I have a query that returns an integer number from a mathematical calculation. I need to sum all the digits in that integer number.
Something like this:
select sumdigits(number) from dual
-- if number =123, output: 1+2+3 = 6
-- if number =100, output: 1+0+0 = 1
I wanted to test this using Fiddle or Rextester, but neither is working right now. So, your upvotes/downvotes will serve as the test:
SELECT CAST(SUBSTRING(number, 1, 1) AS UNSIGNED) + -- first digit
CAST(SUBSTRING(number, 2, 1) AS UNSIGNED) + -- second digit
CAST(SUBSTRING(number, 3, 1) AS UNSIGNED) AS the_sum -- third digit
FROM yourTable
This assumes a number with a max width of 3 digits, which is also zero padded (as you mentioned we can assume).
If you really need to do this in production, you should probably create a user defined function to handle such manipulations, edge cases, etc.
Update:
Going with the comment by #ThorstenKettner we could generalize this answer to a number field of any length by just adding more terms for each digit position. For example, if we wanted to cover numbers which could be up to four digits wide we could just add this term:
+ CAST(SUBSTRING(number, 4, 1) AS UNSIGNED)
which would either add a number if present, or would add zero if not present.
I'm ashamed to even suggest this but...
SELECT
foo,
CHAR_LENGTH(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(foo, '-', ''),
'0', ''),
'1', '1'),
'2', '22'),
'3', '333'),
'4', '4444'),
'5', '55555'),
'6', '666666'),
'7', '7777777'),
'8', '88888888'),
'9', '999999999')
) AS digit_sum
FROM (
SELECT 123 AS foo
UNION ALL SELECT 100
UNION ALL SELECT 413432143
UNION ALL SELECT -6301
UNION ALL SELECT 1234567890
) x
+------------+-----------+
| foo | digit_sum |
+------------+-----------+
| 123 | 6 |
| 100 | 1 |
| 413432143 | 25 |
| -6301 | 10 |
| 1234567890 | 45 |
+------------+-----------+
5 rows in set (0.00 sec)
It probably makes more sense rewritten as function, together with some error checking to return NULL on floats or something similar.

Mask values on mysql database

I have a column with values like this:
01709100011
I need to transform it to:
017.091.0001-1
The values have always the same characters number.
Both columns are varchar
Thanks in advance for any help.
SELECT CONCAT(SUBSTRING(test, 1,3),'.',SUBSTRING(test,4,3),'.',SUBSTRING(test,7,4),'-',SUBSTRING(test,11,1)) FROM test;
In the above example I used the table test and values in column test.
SELECT CONCAT_WS( "-", CONCAT_WS( ".", SUBSTRING( foo, 0, 3 ), SUBSTRING( foo, 3, 3 ), SUBSTRING( 6, 4 )), SUBSTRING( foo, 10 , 1 )) FROM bar WHERE 1=1;