extract text from string data using SQL (with handing null values) - tsql

I have issue with extracting text from string data using T-SQL. I have following data and text that I would like to extract (value between second and third underscore:
sss_ss_d_a -> d
aaa_dd_b -> b
aaa_aa -> NULL
I know that there is a lot of similar topics, but I have problem especially with handling NULLs and situation when there are no delimiter after desired value
Thank you very much for your help, regards

Try it like this:
Some sample data in a declared table
DECLARE #tbl TABLE(YourString VARCHAR(100));
INSERT INTO #tbl VALUES('sss_ss_d_a'),('aaa_dd_b'),('aaa_aa');
--The query
SELECT t.YourString
,CAST(CONCAT('<x>',REPLACE(t.YourString,'_','</x><x>'),'</x>') AS XML).value('/x[3]/text()[1]','nvarchar(max)')
FROM #tbl t;
The idea in short:
We replace the underscores with XML tags thus transforming the string to castable XML.
We use XQuery within .value to pick the third element.
Starting with v2016 the recommended approach uses JSON instead
(hint: we use "2" instead of "3" as JSON is zero-based).
,JSON_VALUE(CONCAT('["',REPLACE(t.YourString,'_','","'),'"]'),'$[2]')
The idea is roughly the same.
General hint: Both approaches might need escaping forbidden characters, such as < or & in XML or " in JSON. But this is easy...

Related

PostgreSQL open JSONB column with slashes

How is it possible to open the JSONB column where JSONB string with slashes?
"{\"id\":\"c39fe0f5f9b7c89b005bf3491f2a2ce1\",\"token\":\"c39fe0f5f9b7c89b005bf3491f2a2ce1\",\"line_items\":[{\"id\":32968150843480,\"properties\":{},\"quantity\":2,\"variant_id\":32968150843480,\"key\":\"32968150843480:4a6f6b7d19c7aef119af2cd909f429f1\",\"discounted_price\":\"40.00\",\"discounts\":[],\"gift_card\":false,\"grams\":0,\"line_price\":\"80.00\",\"original_line_price\":\"80.00\",\"original_price\":\"40.00\",\"price\":\"40.00\",\"product_id\":4638774493272,\"sku\":\"36457537-mud-yellow-28\",\"taxable\":false,\"title\":\"Knee Length Summer Shorts - Camel / 28\",\"total_discount\":\"0.00\",\"vendor\":\"Other\",\"discounted_price_set\":{\"shop_money\":{\"amount\":\"40.0\",\"currency_code\":\"USD\"},\"presentment_money\":{\"amount\":\"40.0\",\"currency_code\":\"USD\"}},\"line_price_set\":{\"shop_money\":{\"amount\":\"80.0\",\"currency_code\":\"USD\"},\"presentment_money\":{\"amount\":\"80.0\",\"currency_code\":\"USD\"}},\"original_line_price_set\":{\"shop_money\":{\"amount\":\"80.0\",\"currency_code\":\"USD\"},\"presentment_money\":{\"amount\":\"80.0\",\"currency_code\":\"USD\"}},\"price_set\":{\"shop_money\":{\"amount\":\"40.0\",\"currency_code\":\"USD\"},\"presentment_money\":{\"amount\":\"40.0\",\"currency_code\":\"USD\"}},\"total_discount_set\":{\"shop_money\":{\"amount\":\"0.0\",\"currency_code\":\"USD\"},\"presentment_money\":{\"amount\":\"0.0\",\"currency_code\":\"USD\"}}}],\"note\":null,\"updated_at\":\"2022-03-15T13:24:02.787Z\",\"created_at\":\"2022-03-15T13:23:31.912Z\",\"controller\":\"custom_webhooks\",\"action\":\"store_data\",\"custom_webhook\":{\"id\":\"c39fe0f5f9b7c89b005bf3491f2a2ce1\",\"token\":\"c39fe0f5f9b7c89b005bf3491f2a2ce1\",\"line_items\":[{\"id\":32968150843480,\"properties\":{},\"quantity\":2,\"variant_id\":32968150843480,\"key\":\"32968150843480:4a6f6b7d19c7aef119af2cd909f429f1\",\"discounted_price\":\"40.00\",\"discounts\":[],\"gift_card\":false,\"grams\":0,\"line_price\":\"80.00\",\"original_line_price\":\"80.00\",\"original_price\":\"40.00\",\"price\":\"40.00\",\"product_id\":4638774493272,\"sku\":\"36457537-mud-yellow-28\",\"taxable\":false,\"title\":\"Knee Length Summer Shorts - Camel / 28\",\"total_discount\":\"0.00\",\"vendor\":\"Other\",\"discounted_price_set\":{\"shop_money\":{\"amount\":\"40.0\",\"currency_code\":\"USD\"},\"presentment_money\":{\"amount\":\"40.0\",\"currency_code\":\"USD\"}},\"line_price_set\":{\"shop_money\":{\"amount\":\"80.0\",\"currency_code\":\"USD\"},\"presentment_money\":{\"amount\":\"80.0\",\"currency_code\":\"USD\"}},\"original_line_price_set\":{\"shop_money\":{\"amount\":\"80.0\",\"currency_code\":\"USD\"},\"presentment_money\":{\"amount\":\"80.0\",\"currency_code\":\"USD\"}},\"price_set\":{\"shop_money\":{\"amount\":\"40.0\",\"currency_code\":\"USD\"},\"presentment_money\":{\"amount\":\"40.0\",\"currency_code\":\"USD\"}},\"total_discount_set\":{\"shop_money\":{\"amount\":\"0.0\",\"currency_code\":\"USD\"},\"presentment_money\":{\"amount\":\"0.0\",\"currency_code\":\"USD\"}}}],\"note\":null,\"updated_at\":\"2022-03-15T13:24:02.787Z\",\"created_at\":\"2022-03-15T13:23:31.912Z\"}}"
this real JSONB column
I can not find any example of how to deal with this type of JSONB
Whatever is inserting your data is screwing it up. It is taking the string representation of a JSON object and stuffing that into a JSON string scalar. You need to fix that or it will just keep happening.
To fix what is already there, you need to extract the real PostgreSQL string out of the JSON string, then cast that to JSONB. Extracting a JSON string can be done unintuitively with #>>'{}', or even less intuitively with ->>0.
select (data#>>'{}')::jsonb from table_name.
Of course you should fix it permanently, not just do it on the fly all the time, which is both slow and confusing.
update table_name set data=(data#>>'{}')::jsonb;
Of course fixing the tool which screws this up in the first place, and fixing the historical data, need to be done in a coordinated fashion or you will have a glorious mess on your hands.
I think you have wrong formatted string in jsonb field. You can try fix it in next way:
select trim(both '"' from replace(data::varchar, '\"', '"'))::jsonb data from tbl;
PostgreSQL JSONB online

split the string column which has a delimiter(',')-sql

Hi I am trying to split the string column which has a delimiter(',')
drop table #address
CREATE TABLE #Address(stir VARCHAR(max));
GO
INSERT INTO #Address(stir)
values('aa,"","7453adeg3","tom","jon","1900-01-01","14155","","2"')
,('ca,"23","42316eg3","pom","","1800-01-01","9999","","1"')
,('daa,"","1324567a","","catty","","756432","213",""')
GO
Expected output:
I am using PARSENAME but it is returning null values? guide me on my expected out put
thanks in advance
The best solution here would be to just create a flat CSV file based on your current insert data, and then use SQL Server's bulk import tool to load it into a table. The following CSV data should be workable here:
aa,"","7453adeg3","tom","jon","1900-01-01","14155","","2"
ca,"23","42316eg3","pom","","1800-01-01","9999","","1"
daa,"","1324567a","","catty","","756432","213",""
Just make sure that you specify double quote as the field escape character.

PostgreSql Queries treats Int as string datatypes

I store the following rows in my table ('DataScreen') under a JSONB column ('Results')
{"Id":11,"Product":"Google Chrome","Handle":3091,"Description":"Google Chrome"}
{"Id":111,"Product":"Microsoft Sql","Handle":3092,"Description":"Microsoft Sql"}
{"Id":22,"Product":"Microsoft OneNote","Handle":3093,"Description":"Microsoft OneNote"}
{"Id":222,"Product":"Microsoft OneDrive","Handle":3094,"Description":"Microsoft OneDrive"}
Here, In this JSON objects "Id" amd "Handle" are integer properties and other being string properties.
When I query my table like below
Select Results->>'Id' From DataScreen
order by Results->>'Id' ASC
I get the improper results because PostgreSql treats everything as a text column and hence does the ordering according to the text, and not as integer.
Hence it gives the result as
11,111,22,222
instead of
11,22,111,222.
I don't want to use explicit casting to retrieve like below
Select Results->>'Id' From DataScreen order by CAST(Results->>'Id' AS INT) ASC
because I will not be sure of the datatype of the column due to the fact that JSON structure will be dynamic and the keys and values may change next time. and Hence could happen the same with another JSON that has Integer and string keys.
I want something so that Integers in Json structure of JSONB column are treated as integers only and not as texts (string).
How do I write my query so that Id And Handle are retrieved as Integer Values and not as strings , without explicit casting?
I think your assumtions about the id field don't make sense. You said,
(a) Either id contains integers only or
(b) it contains strings and integers.
I'd say,
If (a) then numerical ordering is correct.
If (b) then lexical ordering is correct.
But if (a) for some time and then (b) then the correct order changes, too. And that doesn't make sense. Imagine:
For the current database you expect the order 11,22,111,222. Then you add a row
{"Id":"aa","Product":"Microsoft OneDrive","Handle":3095,"Description":"Microsoft OneDrive"}
and suddenly the correct order of the other rows changes to 11,111,22,222,aa. That sudden change is what bothers me.
So I would either expect a lexical ordering ab intio, or restrict my id field to integers and use explicit casting.
Every other option I can think of is just not practical. You could, for example, create a custom < and > implementation for your id field which results in 11,111,22,222,aa. ("Order all integers by numerical value and all strings by lexical order and put all integers before the strings").
But that is a lot of work (it involves a custom data type, a custom cast function and a custom operator function) and yields some counterintuitive results, e.g. 11,111,22,222,0a,1a,2a,aa (note the position of 0a and so on. They come after 222).
Hope, that helps ;)
If Id always integer you can cast it in select part and just use ORDER BY 1:
select (Results->>'Id')::int From DataScreen order by 1 ASC

replacing characters in a CLOB column (db2)

I have a CLOB(2000000) field in a db2 (v10) database, and I would like to run a simple UPDATE query on it to replace each occurances of "foo" to "baaz".
Since the contents of the field is more then 32k, I get the following error:
"{some char data from field}" is too long.. SQLCODE=-433, SQLSTATE=22001
How can I replace the values?
UPDATE:
The query was the following (changed UPDATE into SELECT for easier testing):
SELECT REPLACE(my_clob_column, 'foo', 'baaz') FROM my_table WHERE id = 10726
UPDATE 2
As mustaccio pointed out, REPLACE does not work on CLOB fields (or at least not without doing a cast to VARCHAR on the data entered - which in my case is not possible since the size of the data is more than 32k) - the question is about finding an alternative way to acchive the REPLACE functionallity for CLOB fields.
Thanks,
krisy
Finally, since I have found no way to this by an SQL query, I ended up exporting the table, editing its lob content in Notepad++, and importing the table back again.
Not sure if this applies to your case: There are 2 different REPLACE functions offered by DB2, SYSIBM.REPLACE and SYSFUN.REPLACE. The version of REPLACE in SYSFUN accepts CLOBs and supports values up to 1 MByte. In case your values are longer than you would need to write your own (SQL-based?) function.
BTW: You can check function resolution by executing "values(current path)"

What's the most efficient way of querying the database based on a list of values?

I have a list of record Id's that I want to retrieve from Sql Server. I'm trying to figure out what the most performant way doing this would be. For example in code I have this:
var recordsToFind = new List<long>{ 12345, 12346, 45756, 42423 ... }
I want to create a stored proc that does this:
Select * From Puzzles where ID = {any of the integers passed in}
I know there are several options like, table value parameters, converting the list into a comma seperated string and using CharIndex, created a temp table and splitting the string etc...
What would be the best approach keeping in mind this will be used A LOT!
Thanks!
Several must read articles about this can be found here: http://www.sommarskog.se/arrays-in-sql.html Performance considerations are addressed in those articles.
Do you have the ability to change the code and the stored procedure or are you bound to some limit? If you have the ability to change both, I've seen this done before:
//Convert array/list to a comma delimited string using your own function (We'll call string strFilter)
//Pass strFilter into stored procedure (varchar(1000) maybe, we'll call parameter #SQLFILTER)
DECLARE #SQL AS VARCHAR(2000) --Or VARCHAR(MAX)
SET #SQL = "SELECT * FROM PUZZLES WHERE ID IN (" + #SQLFILTER + ")"
EXEC (#SQL)
I apologize if my syntax is off. My job unfortunately uses Oracle and I haven't used SQL Server a lot in 8 months. Hope this helps.
Micah,
is it out of the question to just do the simple sql 'in()' function?? (with obviously your array being used as a parameter, rather then the hardcoded values)
select * From Puzzles where ID in (12345, 12346, 45756, 42423)
maybe i've misunderstood the question mind you :)
[edit] - i notice that this is being used in .net. would it be possible to use linq against the database at all?? if so, then a few well crafted linq (over EF or subsonic for example) methods may do the trick. for example:
var idlist = new int[] { 12345, 12346, 45756, 42423 };
var puzzleids = Puzzles.Where(x =>
idlist.Contains(x.ID));