How to transform pl sql Json value into a string - sql

Have a project for work & my SQL skills are improving, but I still struggle with basic stuff every now and then. I need to get 'fundingCode' to show up as a string rather than a number as it is now.
(i.e. currently the outcome is '"fundingCode": 100001' & I need it to show up as '"fundingCode": "100001"
cursor json_index_data (c_org_code VARCHAR2) is
select json_object(
'_dtoName' VALUE 'AeSFndOrganization',
'companyId' VALUE oa.location_desc,
'deptId' VALUE OA.DEPT,
'ocCode' VALUE OA.ORGANIZATION_LEVEL_6,
nvl('seq', 1) VALUE imi.seq,
'fundingCode' VALUE (I.ACCOUNT_INDEX)
FORMAT JSON)
as json_row_value

The way you would typically do a select statement resulting in JSON would be like this:
select json_object(
key '_dtoName' is 'AeSFndOrganization',
key 'companyId' is oa.location_desc,
key 'deptId' is OA.DEPT,
key 'ocCode' is OA.ORGANIZATION_LEVEL_6,
key 'seq' is imi.seq,
key 'fundingCode' is to_char(I.ACCOUNT_INDEX)
) as YOUR_JSON_ALIAS
from YOUR_TABLENAME;
So you define your key on the left and your value (with is) on the right. I don't think that would act any differently in a cursor if you just put cursor json_index_data is in front of it.
If you need to convert a value, use the typical conversion functions like to_char(the_value) or to_number(the_string), etc. That's what I did in the sample query above for:
...
key 'fundingCode' is to_char(I.ACCOUNT_INDEX)
...

So a coworker managed to give me a pretty good explanation. I had previously tried to use concatenation, but I was using bad syntax. Here is how it was finally accomplished.
cursor json_index_data (c_org_code VARCHAR2) is
select json_object(
'multitenantId' VALUE '1',
'_dtoName' VALUE 'AeSFndOrganization',
'companyId' VALUE oa.campus_desc,
'deptId' VALUE OA.DEPT,
'ocCode' VALUE OA.ORGANIZATION_LEVEL_6,
nvl('seq', 1) VALUE imi.seq,
'fundingCode' VALUE '"' || I.ACCOUNT_INDEX || '"'
FORMAT JSON)
as json_row_value

Related

How to cast postgres JSON column to int without key being present in JSON (simple JSON values)?

I am working on data in postgresql as in the following mytable with the fields id (type int) and val (type json):
id
val
1
"null"
2
"0"
3
"2"
The values in the json column val are simple JSON values, i.e. just strings with surrounding quotes and have no key.
I have looked at the SO post How to convert postgres json to integer and attempted something like the solution presented there
SELECT (mytable.val->>'key')::int FROM mytable;
but in my case, I do not have a key to address the field and leaving it empty does not work:
SELECT (mytable.val->>'')::int as val_int FROM mytable;
This returns NULL for all rows.
The best I have come up with is the following (casting to varchar first, trimming the quotes, filtering out the string "null" and then casting to int):
SELECT id, nullif(trim('"' from mytable.val::varchar), 'null')::int as val_int FROM mytable;
which works, but surely cannot be the best way to do it, right?
Here is a db<>fiddle with the example table and the statements above.
Found the way to do it:
You can access the content via the keypath (see e.g. this PostgreSQL JSON cheatsheet):
Using the # operator, you can access the json fields through the keypath. Specifying an empty keypath like this {} allows you to get your content without a key.
Using double angle brackets >> in the accessor will return the content without the quotes, so there is no need for the trim() function.
Overall, the statement
select id
, nullif(val#>>'{}', 'null')::int as val_int
from mytable
;
will return the contents of the former json column as int, respectvely NULL (in postgresql >= 9.4):
id
val_int
1
NULL
2
0
3
2
See updated db<>fiddle here.
--
Note: As pointed out by #Mike in his comment above, if the column format is jsonb, you can also use val->>0 to dereference scalars. However, if the format is json, the ->> operator will yield null as result. See this db<>fiddle.

Translate function not returning relevant string in amazon redshift

I am trying to use a simple Translate function to replace "-" in a 23 digit string. The example of one such string is "1049477-1623095-2412303" The expected outcome of my query should be 104947716230952412303
The list of all "1049477-1623095-2412303" is present in a single column "table1". The name of the column is "data"
My query is
Select TRANSLATE(t.data, '-', '')
from table1 as t
However, it is returning 104947716230952000000 as the output.
At first, I thought it is an overflow error since the resulting integer is 20 digit so I also tried to use following
SELECT CAST(TRANSLATE(t.data,'-','') AS VARCHAR)
from table1 as t
but this is not working as well.
Please suggest a way so that I could have my desirable output
This is too long for a comment.
This code:
select translate('1049477-1623095-2412303', '-', '')
is going to return:
'104947716230952412303'
The return value is a string, not a number.
There is no way that it can return '104947716230952000000'. I could only imagine that happening if somehow the value is being converted to a numeric or bigint type.
Try regexp_replace()
Taking your own example, execute:
select regexp_replace('[string / column_name]','-');
It can be achieve RPAD try below code.
SELECT RPAD(TRANSLATE(CAST(t.data as VARCHAR),'-','') ,20,'00000000000000000000')

from string to map object in Hive

My input is a string that can contain any characters from A to Z (no duplicates, so maximum 26 characters it may have).
For example:-
set Input='ATK';
The characters within the string can appear in any order.
Now I want to create a map object out of this which will have fixed keys from A to Z. The value for a key is 1 if its corresponding character appears in the input string. So in case of this example (ATK) the map object should look like:-
So what is the best way to do this?
So the code should look like:-
set Input='ATK';
select <some logic>;
It should return a map object (Map<string,int>) with 26 key value pairs within it. What is the best way to do it, without creating any user defined functions in Hive. I know there is a function str_to_map that easily comes to mind.But it only works if key value pairs exist in source string and also it will only consider the key value pairs specified in the input.
Maybe not efficient but works:
select str_to_map(concat_ws('&',collect_list(concat_ws(":",a.dict,case when
b.character is null then '0' else '1' end))),'&',':')
from
(
select explode(split("A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z",',')) as dict
) a
left join
(
select explode(split(${hiveconf:Input},'')) as character
) b
on a.dict = b.character
The result:
{"A":"1","B":"0","C":"0","D":"0","E":"0","F":"0","G":"0","H":"0","I":"0","J":"0","K":"1","L":"0","M":"0","N":"0","O":"0","P":"0","Q":"0","R":"0","S":"0","T":"1","U":"0","V":"0","W":"0","X":"0","Y":"0","Z":"0"}

How to generate XML data in Oracle which has Empty string as an attribute

I want to generate an XML element using Oracle's XML documentation generation support features that looks like this
<Example Attr=""></Example>
Attr is an attribute of element Example and has a value of empty string "".
When I tried to generate an XML Element using Oracle's XML functions, I couldn't generate an XML element which has an attribute whose value is an empty string.
select XMLELEMENT("hello", xmlattributes('' as "Max")) from dual
The result of the above query is
<hello></hello>
Note: there is no space between the single quotes for Max attribute.
However my requirement is
<hello Max=""></hello> -- there is no space between the double quotes.
Is there a way to do this?
As you're aware, for XMLAtttribute "if the value_expr is null, then no attribute is created for that value expression".
You can work around this with InsertChildXML but it isn't terribly pretty:
select insertchildxml(xmlelement("hello"), '/hello', '#Max', null) from dual;
INSERTCHILDXML(XMLELEMENT("HELLO"),'/HELLO','#MAX',NULL)
--------------------------------------------------------------------------------
<hello Max=""/>
... and as you can see it collapses an empty node, but that's only a potentially issue if you want this to look exactly as you showed - it's valid XML still. There is an even uglier way around that if you really need to.
That also suggests an alternative to #smnbbrv's replace:
select updatexml(xmlelement("hello", xmlattributes('$$IMPOSSIBLE-VALUE$$' as "Max")),
'/hello[#Max="$$IMPOSSIBLE-VALUE$$"]/#Max', null) from dual;
UPDATEXML(XMLELEMENT("HELLO",XMLATTRIBUTES('$$IMPOSSIBLE-VALUE$$'AS"MAX")),'/HEL
--------------------------------------------------------------------------------
<hello Max=""/>
which might be easier if your max attribute value is coming from data as you can NVL it to the impossible value. I'm not a fan of using magic values though really.
What about setting the property value to some impossible value and then replace it with the value you need (so, empty string in your case)?
select replace(
XMLELEMENT("hello", xmlattributes('$$IMPOSSIBLE-VALUE$$' as "Max")).getStringVal(),
'$$IMPOSSIBLE-VALUE$$'
)
from dual;
I assume you anyway in the end need the string value, so even if this XMLELEMENT is just an example of the problem and you have a biiiig XML generated, you still can generate it first and then, finally, replace all the values with one command as shown above.
I'm using this approach (you write the source attribute instead of the "null"). This way, you don't have to search for some overall impossible value, it's enough to be impossible for that attribute.
select
replace(XMLELEMENT("hello", xmlattributes(nvl(null,' ') as "Max")).getstringval(),
'Max=" "',
'Max=""')
from dual
I used updatexml() similar to A. Poole's example to create an empty string
set serveroutput on
DECLARE
xa xmltype;
xb xmltype;
BEGIN
xa := xmltype('<surfbreaks>'||
'<break lineNum="0" recordtype="empty">d street </break>'||
'<break lineNum="0" recordtype="empty">recordtype="empty" </break>'||
'</surfbreaks>');
dbms_output.put_line ('Before:');
dbms_output.put_line (xa.getclobval);
select UPDATEXML(xa, '//#recordtype', '') into xb from dual;
dbms_output.put_line ('After:');
dbms_output.put_line (xb.getclobval);
END; /

SQL List Function Removing Precision

I am using the LIST function to create a ';' delimited list of values. The type is numeric (19,2). For some reason the precision appears to be ignored when using the list function. When performing a simple select on this column the values look good, ie "12.00". However, if I use a LIST() my results are of format "12.000000"
This is my LIST usage:
LIST(case when tblWOService.PricePerVehicle is null then ' ' else CONVERT(decimal(19,2),tblWOService.PricePerVehicle end,';')
The CONVERT does not change the result. Any ideas?
Thanks!
Have you tried explicitly converting your empty string?
LIST(
case when tblWOService.PricePerVehicle is null then CONVERT(decimal(19,2),' ')
else CONVERT(decimal(19,2),tblWOService.PricePerVehicle) end,';'
)
I've run into a similar datatype issue with CASE statements in T-SQL.

Categories