With the following SQL:
SELECT
CAST(JSON_VALUE(d.Data,'lax $.realSKosten') AS DECIMAL(18,5)) as ks,
CONVERT(float ,JSON_VALUE(d.Data,'lax $.realAKosten')) as ka
FROM UserEntityData as d
I get this result:
[{"ks":1.23000,"ka":1.230000000000000e+000},
{"ks":2.34500,"ka":2.345000000000000e+000}]
With huge resultsets, a big part of the result consists of zeros. Therefore it would be much better, if the resultset would look like this:
[{"ks":1.23,"ka":1.23},
{"ks":2.345,"ka":2.345}]
As shown, with "AS DECIMAL(18,5)" I can shorten it. But the number of decimals is fixed.
Is there a performant way to tell the SQL-Server to remove all zeros at the end, if there are any? Of course without converting it to varchar and doing any text-manipulation.
Not if you want the value to be treated as a numerical value, no. If you're happy with the values being quoted, however, you could use TRIM.
SELECT TRIM('0' FROM CONVERT(varchar(20),ks)) AS ks,
TRIM('0' FROM CONVERT(varchar(20),ka)) AS ka
FROM (VALUES(1.23000,1.23000),
(2.34500,2.34500))V(ks,ka)
FOR JSON AUTO;
Which results in:
[
{
"ks": "1.23",
"ka": "1.23"
},
{
"ks": "2.345",
"ka": "2.345"
}
]
Related
I am trying to build a array from this string and need help with pattern on regexp_extract_all.
Here is my input string contains keyword value pairs
BEGIN
DECLARE p_JSON STRING DEFAULT """
{
"instances": [{
"LT_20MN_SalesContrctCnt": 388.0,
"Pyramid_Index": '',
"MARKET": "'Growth Markets','Europe'",
"SERVICE_DIM": "'S&C','F&M'",
"SG_MD": "'All Service Group'"
}]}
""";
SELECT split(x,":")[OFFSET(0)] as keyword, split(x,":")[OFFSET(1)] keyword_value
FROM unnest(split(REGEXP_REPLACE(JSON_EXTRACT(p_JSON, '$.instances'),r'([\'\"\[\]{}])', ''))) as x
END;
The above SQL is failing at SPLIT due to , with in the data.
All I am trying to do here is build a two columns Keyword and value.
The idea here is if I can extract each row using REGEXP_EXTRACT_ALL with out the last "," then I should be able to split into keyword and keyword_value columns. Btw the names or number of keywords/values are not fixed.
Intended output from REGEXP_EXTRACT_ALL:
"LT_20MN_SalesContrctCnt": 388.0
"Pyramid_Index": ''
"MARKET": "'Growth Markets','Europe'"
"SERVICE_DIM": "'S&C','F&M'"
"SG_MD": "'All Service Group'"
Appreciate if you can suggest a better way to handle this.
Thanks in advance.
Using your sample data, I just added an extra REGEXP_REPLACE to replace ," to #" so we can avoid splitting using ,. See approach below:
SELECT
SPLIT(arr,":")[OFFSET(0)] as keyword,
SPLIT(arr,":")[OFFSET(1)] as keyword_value,
FROM sample_data,
UNNEST(SPLIT(REGEXP_REPLACE(REGEXP_REPLACE(JSON_EXTRACT(p_JSON, '$.instances'),r'[\[\]{}]',''),r',"','#"'),'#')) arr
Output:
I had a hard time finding the values on a basis, as all the examples cite the same way of finding information in simple jsons.
But a friend from work gave me a solution and I came to share.
the initial question was: How to make a select in a nested json ???
A json like this:
{
"vehicle":[
{
"vehicle_type":"Truck",
"car_make":"Lotus",
"car_model":"Esprit",
"quantity":7,
"seats":7,
"price_hour":16,
"price_day":147,
"color":[
"Purple",
"Pink",
"Blue",
"White"
]
}
]
}
To view the structure, you can use the https://jsoneditoronline.org/
The answer I bring uses select with regex:
select * from example
where example.jsonTest->>'vehicle' ~ 'color"\s*:\s*"?.*?Blue.*"?';
and
select * from example
where example.jsonTest->>'vehicle' ~ 'vehicle_type"\s*:\s*"?.*?SUV.*"?';
To be clear I left a working example in https://rextester.com/BQZP48785
** sorry for my bad english
In order to determine the vehicle with color blue, and vehicle type with SUV, jsonb_array_elements() function might be used to unnest the main array, and then putting (j.elm->>'vehicle_type') = 'SUV' into the WHERE clause would be enough for the second, while (j.elm->>'color')::jsonb ? 'Blue' should be used containing jsonb conversion with ? operator for the first one, since (j.elm->>'color') extracts an array, while (j.elm->>'vehicle_type') does simple string pieces.
Therefore a regular expression is not needed such as below queries :
SELECT e.*
FROM example e
CROSS JOIN jsonb_array_elements(jsonTest->'vehicle') j(elm)
WHERE (j.elm->>'color')::jsonb ? 'Blue'
and
SELECT e.*
FROM example e
CROSS JOIN jsonb_array_elements(jsonTest->'vehicle') j(elm)
WHERE (j.elm->>'vehicle_type') = 'SUV'
Demo
I have data from a query that looks like this:
SELECT
model_features
FROM some_db
which returns:
{
"food1": 0.65892159938812,
"food2": 0.90786880254745,
"food3": 0.88357985019684,
"food4": 0.99999821186066,
"food5": 0.99237471818924,
"food6": 0.62127977609634
}
{
"food4": 0.9999965429306,
"text1": 0.82206630706787
}
...
etc.
What I am eventually trying to do is simply get a count of each of the "food1", "food2" features,
but to do so (i think) I need to trim out the unnecessary numeric data. I'm at a loss as to how to do this, as everytime I try to simply unnest
SELECT
t.concepts
FROM some_db
CROSS JOIN UNNEST(model_features) AS t(concepts)
I get this error:
Column alias list has 1 entries but 't' has 2 columns available
Anyone mind pointing me in the right direction?
Solved this for myself: the issue was I needed to avoid dropping the second column of information in order for the query to execute. This may not be the canonical best way to approach, but it worked:
SELECT
t.concepts,
t.probabilities
FROM some_db
CROSS JOIN UNNEST(model_features) AS t(concepts,probabilities)
I have json stored in one of the columns in SQL Server and I need to modify it to remove the square brackets from it. The format is as below. Can't seem to find a good way of doing it.
[ { "Message":"Info: this is some message here.", "Active":true } ]
One way is to do it using below query, but this query is very very slow and I need to run on a very large set of data.
select a.value
from dbo.testjson e
cross apply OPENJSON(e.jsontext) as a
where isjson(e.jsontext) = 1
The only other way I can think of is just doing string manipulation but it can be error prone. Could someone help with this?
Ok, figured it out:
select
json_query(
'[{"Message":"Info: this is some message here.","Active":true}]',
'$[0]'
)
This will return the inner message.
You should add the property name, in this case Message, in order to get only that part. Keep in mind that it's case sensitive. Something like;
select json_value('[{"Message":"Info: this is some message here.","Active":true}]', '$[0].Message')
I have some hard time figuring it out how to custom sort data below the way I want to. Meaning it should be in order like this:
201-1-1
201-1-2
201-1-3
.......
201-2-1
and so on if you know what I mean.
Instead I'm getting this sort executing below code:
select *
from test.dbo.accounts
order by account_name asc
Output:
201-10-1
201-10-2
201-1-1
201-11-1
201-11-2
201-11-3
201-11-4
201-11-6
201-1-2
201-12-1
201-12-2
201-12-3
201-12-4
201-12-6
201-1-3
201-13-1
201-13-2
201-13-3
201-13-4
201-13-6
201-1-4
201-14-1
201-14-2
201-14-4
201-14-6
201-15-1
201-15-2
201-15-3
201-15-4
201-15-6
201-1-6
201-16-1
201-16-2
201-16-3
201-16-4
201-16-6
201-16-7
201-1-7
201-17-1
201-17-2
201-17-4
201-17-6
201-18-1
201-18-2
201-18-3
201-18-4
201-18-6
201-19-1
Thanks
For your sample data, this following trick will work:
order by len(account_name), account_name
This only works because the only variable length component is the second component and because the hyphen is "smaller" than digits.
You should normalize the accounts names so all the components are the same length, by left padding the numbers with zeros.
Ugh. String manipulation in SQL can be extremely cumbersome. There might be a better way to do this, but this does seem to work.
select accoutn_name
from test.dbo.accounts
order by left(account_name,charindex('-',account_name,1)-1)
,replace(right(left(account_name,CHARINDEX('-',account_name,1)+2),2),'-', '')
,REPLACE(right(account_name,2),'-','')
BTW, this is a very expensive process to run. If it's productionalized, you'll want to come up with a better solution.