Parse the JSON text from DB column nvarchar - sql-server

I have value in a column which stores the data as an json object .
Below is an example how the value is stored, I know the name of which I have to get the value over here
{"Name":"Today Date","value":"02/23/2017"},{"Name":"Exp Date","value":"02/23/2016"}
I want the value of name "Today Date" over here.
I can't use json parse as we are still using sql server 2014.
Currently with a hint from r41n's answer, I did the below:
select SUBSTRING
( '{"Name":"Today Date","value":"02/23/2017"},{"Name":"Exp Date","value":"02/23/2016"}',
PATINDEX('%{"Name":"Today Date","value":"%', '{"Name":"Today Date","value":"02/23/2017"},{"Name":"Exp Date","value":"02/23/2016"}') + len ('{"Name":"Today Date","value":"'),
10)
If there are any other alternative solutions, please let me know.

PATINDEX + SUBSTRING
It's slow and kinda ugly, but you could go and use PATINDEX like so:
PATINDEX('%{"Name":"Today Date","value":"%', JSONColumn)
This would give you the starting-position in JSONColumn where string starts. You could then go and use SUBSTRING(JSONColumn, 30, 10) to get only the date.
This obviously doesn't work if the date or JSON data is not constant or changes from one instance to another.
I didn't test this, but used it before.

Related

SQL Server: STRING_SPLIT() result in a computed column

I couldn't find good documentation on this, but I have a table that has a long string as one of it's columns. Here's some example data of what it looks like:
Hello:Goodbye:Apple:Orange
Example:Seagull:Cake:Chocolate
I would like to create a new computed column using the STRING_SPLIT() function to return the third value in the string table.
Result #1: "Apple"
Result #2: "Cake"
What is the proper syntax to achieve this?
At this time your answer is not possible.
The output rows might be in any order. The order is not guaranteed to
match the order of the substrings in the input string.
STRING_SPLIT reference
There is no way to guarantee which item was the third item in the list using string_split and the order may change without warning.
If you're willing to build your own, I'd recommend reading up on the work done by
Brent Ozar and Jeff Moden.
You shouldn't be storing data like that in the first place. This points to a potentially serious database design problem. BUT you could convert this string into JSON by replacing : with ",", surround it with [" and "] and retrieve the third array element , eg :
declare #value nvarchar(200)='Example:Seagull:Cake:Chocolate'
select json_value('["' + replace(#value,':','","' )+ '"]','$[2]')
The string manipulations convert the string value to :
["Example","Seagull","Cake","Chocolate"]
After that, JSON_VALUE parses the JSON string and retrieves the 3rd item in the array using a JSON PATH expression.
Needless to say, this will be slow and can't take advantage of indexing. If those values are meant to be read or written individually, they should be stored in separate columns. They'll probably take less space than one long string.
If you have a lot of optional fields but only a subset contain values at any time, you could use sparse columns. This way you could have thousands of rows, only a few of which would contain data at any time

How to take apart information between hyphens in SQL Server

How would I take apart a column that contains string:
92873-987dsfkj80-2002-04-11
20392-208kj48384-2008-01-04
Data would look like this:
Filename Yes/No Key
Abidabo Yes 92873-987dsfkj80-2002-04-11
Bibiboo No 20392-208kj48384-2008-01-04
Want it to look like this:
Filename Yes/No Key
Abidabo Yes 92873-987dsfkj80-20020411
Bibiboo No 20392-208kj48384-20080104
whereby I would like to concat the dates in the end as 20020411 and 20080104. From the right side, the information is the same always. From the left it is not, otherwise I could have concatenated it. It is not an import issue.
As mentioned in the comments already, storing data like this is a bad idea. However, you can obtain the dates from those strings by using a RIGHT function like so:
SELECT RIGHT('20392-208kj48384-2008-01-04', 10)
Output:
2008-01-04
Depending on the SQLSERVER version you are using, you can use STRING_SPLIT which requieres COMPATIBILITY_LEVEL 130. You can also build your own User Defined Function to split the contents of a field and manipulate it as you need, you can find some useful examples of SPLIT functions in this thread:
Split function equivalent in T-SQL?
Assuming I'm correct and the date part is always on the right side of the string, you can simply use RIGHT and CAST to get the date (assuming, again, that the date is represented as yyyy-mm-dd):
SELECT CAST(RIGHT(YourColumn, 10) As Date)
FROM YourTable
However, Panagiotis is correct in his comment - You shouldn't store data like that. Each column in the database should hold only a single point of data, be it string, number or date.
Update following your comment and the updated question:
SELECT LEFT(YourColumn, LEN(YourColumn) - 10) + REPLACE(RIGHT(YourColumn, 10), '-', '')
FROM YourTable
will return the desired results.

Use String parameter for RegEx in query

In my query (the database is a sql server) I use a RegEx for a select command like this:
SELECT * FROM test WHERE id LIKE '1[2,3]'
(This query is tested and returns the data I want)
I want to use a paramter for this RegEx. For that I definded the Paramter in iReport $P{id} as a string and the value is "1[2,3]".
In my query I use now this parameter like this:
SELECT * FROM test WHERE id LIKE $P{id}
As result I get a blank page. I think the problem is that the value of the parameter is defined with " ". But with ' ' I get a compiler error that the paramter isn't a string.
I hope someone can help me.
LIKE applies to text values, not to numeric values. Since id is numeric use something like this:
SELECT * FROM test WHERE id IN (12, 13)
with the parameter
SELECT * FROM test WHERE id IN ($P!{id_list})
and supply a comma separated list of ids for the parameter. The bang (!) makes sure that the parameter will be inserted as-is, without string delimiters.
Btw: LIKE (Transact-SQL) uses wildcards, not regex.
You can still use LIKE since there exists an implicit conversion from numeric types to text in T-SQL, but this will result in a (table or index) scan, where as the IN clause can take advantage of indexes.
The accepted answer works but it is using String replacement, read more about sql-injection, to understand why this is not good practice.
The correct way to execute this IN query in jasper report (using prepared statement) is:
SELECT * FROM test WHERE $X{IN, id, id_list}
For more information as the use of NOTIN, BETWEEN ecc. see JasperReports sample reference for query

SQL Server - how to insert a substring?

I have a string like
`...<..../><... id='someID' .../><...../>....`
(the total length of that string is more than 15k chars, it's an XML form definition)
Inside of that string I have the someID value. I want to put after the element containing that value a new string:
...<..../><... id='someID' .../><my_new_string><...../>....
I tried to split that long string basing on the someID value, but that approach is too slow. How can I achieve that on the other way ?
Or maybe is it possible to select the substring <... id='someID' .../> ?
SQL server can work with XML. You do not need to use substring.
A simular problem was solved on this page: xml.modify
Have you tried using Replace? For example:
REPLACE(yourString, yourPattern, yourPattern + newString);
Using your example, it would look something like:
REPLACE('...<..../><... id='someID' .../><...../>....',
'<... id=''someID'' .../>',
'<... id=''someID'' .../><my_new_string>');
Please notice I escaped the ' characters around "someID".
Best regards.
It isn't clear what data type your string is: xml or (n)varchar? For xml, you can use the various data type methods; for (n)varchar the STUFF() function inserts one string into another string.

T-SQL - text field to nvarchar

I have a 'text' type in a SQL table (BigNote), and a new nvarchar(2000) field (LittleNote).
I need to save the first 2000 characters from the #BigNote into the LittleNote field within a stored procedure. Can someone share some thoughts?
Do I need to check for:
- nulls?
- the BigNote length and only grab the exact amount?
It is working by just assigning LittleNote = #BigNote, but I want to avoid problems when the text is too big etc...
Once we release an update to the application, we will handle this more elegantly, but in the meantime we need to get a non-Text field with this data in the database.
you could use
LittleNote = CONVERT(NVARCHAR(2000), #BigNote)
or with SUBSTRING
LittleNote = SUBSTRING(#BigNote, 1, 2000)

Resources