I have a table parameter having 2 columns id(integer) and param_specs(text).
the actual param_specs column looks like above pic (to simplify it check below:-
)
param_specs
[
{"paramName":"param1",
"type":"string",
"defaultValue":"tomcat7",
"optional":false,
"deploymentParam":false},
{"paramName":"param123PreStopAction",
"type":"path",
"defaultValue":"HELLO",
"optional":false,
"deploymentParam":false}
]
So it is an array of json array and i want to fetch the defaultValue field of paramName param123PreStopAction i.e. HELLO.
****EDIT****
As can be seen in the image this is what my table called parameter looks like having two columns I want to get defaultValue of each row in parameter table where paramName LIKE (%PostStopAction) or (%PreStopAction) check the bold values in image(i.e. the paramName should have either PreStopAction or PostStopAction within the actual paramName value eg 'mytomcat7PostStopAction' and fetch its defaultValue i.e 'post-stop'.)
There can be some rows in the table where there wont be any json having preStop or PostStop paramName like row 3 in the image
can someone help me with the query?
As JGH suggested something as follows:-
SELECT "defaultValue"
FROM parameter a
CROSS JOIN LATERAL
json_to_recordset(a.param_spec::json) AS x("paramName" text,"defaultValue" text)
WHERE "paramName”LIKE “%PreStopAction' OR “paramName” LIKE “%PostStopAction”
One approach is to explode your array in fields and to query them. The trick is to consider only the fields of interest.
Select myOutputField
from json_to_recordset('[the array]') as (myQueryField text, myOutputField text)
where myQueryField = myCondition;
Or, bound to your example:
select "defaultValue" from json_to_recordset('
[
{"paramName":"param1",
"type":"string",
"defaultValue":"tomcat7",
"optional":false,
"deploymentParam":false},
{"paramName":"param123PreStopAction",
"type":"path",
"defaultValue":"HELLO",
"optional":false,
"deploymentParam":false}
]') as x("paramName" text,"defaultValue" text)
where "paramName" = 'param123PreStopAction';
** EDIT **
Your data is not saved in a json column but in a text column. You would have to convert it to json (ideally, the column itself... or at least its content). Also, the json_to_recordset works on single items, not on sets, so you would need to use a LATERAL JOIN to overcome this limitation, as nicely explained here.
SELECT myOutputField
FROM mytable a
CROSS JOIN LATERAL
json_to_recordset(a.jsonintextcolumn::json) as (myQueryField text, myOutputField text)
WHERE myQueryField = myCondition;
Or, bound to your example:
SELECT "defaultValue"
FROM public.testjsontxt a
CROSS JOIN LATERAL
json_to_recordset(a.param_specs::json) as x("paramName" text,"defaultValue" text)
WHERE "paramName" = 'param123PreStopAction';
Related
I have a table column in BigQuery with JSON array format with a row like {"role":"SuperAdmin","_id":"abcd","userId":"efgh"}. This column schema in BigQuery is REPEATED mode. My goal is to extract the userId value for all the rows in that column.
I have tried using JSON functions like json_value and json_extract:
select json_value(column_name, '$.users.userId') as userId, from table_name
but get the following error :
No matching signature for function JSON_VALUE for argument types: ARRAY<STRING>, STRING. Supported signature: JSON_VALUE(STRING, [STRING]) at [2:3]
Please how do I go about it?
Because it is repeated you will need to unnest it first.
Given the following example:
with sample_data as (
select ['{"role":"SuperAdmin","_id":"abcd","userId":"efgh"}','{"role":"SuperAdmin","_id":"abcd","userId":"efgh"}','{"role":"SuperAdmin","_id":"abcd","userId":"efgh"}'] as users
)
select json_value(user, '$.userId') as userId
from sample_data , UNNEST(users) user
The return is:
Trying to get the values and element names extracted from one XML column.
Values are getting just in one row and not able to extract the element name.
The elements in the cell are like this:
6161...
And they are dynamically generated.
Here is the code:
SELECT mainSku, r.value('.[1]','NVARCHAR(MAX)') AS 'value', r.query('.') AS 'secondarySku'
FROM [productsMatrix]
CROSS APPLY details.nodes('/') AS x(r)
WHERE mainSku = 'TP40106'
This is the wrong actual result
This is the result that is pretended
Thanks for reading :)
Your question is far away from being clear, but my magic crystall ball is showing, that you might be looking for this:
SELECT mainSku
,r.value('text()[1]','int') AS [value]
,r.value('local-name(.)') AS [secondarySku]
FROM [productsMatrix]
CROSS APPLY details.nodes('/*') AS x(r)
WHERE mainSku = 'TP40106'
Assumptions:
Your table [productsMatrix] has got an XML column called details. This column contains an XML with no root node, just a list of XML-Elements with names like <AC486>.
The CROSS APPLY on .nodes() will return a list of all first-level-nodes, while the query picks the content (text()-node) and the element's name.
I am currently using PostgreSQL JSON capabilities to create JSON objects out of my query so I can easily use it on my application or pass it to the frontend.
array_to_json(array_agg(tags.*)) does exactly when I need to (creates JSON objects with columns as a keys from the data and convert it into array), however I haven't found any way how to do the same if I need only one or two columns from tags. I played with various JSON and array functions but I've never achieved the same result. Thanks for help
Whole query
SELECT
tags_components.component_id,
array_to_json(array_agg(tags.*)) as tags
FROM tags_components
LEFT JOIN tags ON tags.id = tags_components.tag_id
AND tags_components.component_name = 'company'
GROUP BY tags_components.component_id
Use a derived table, e.g.:
SELECT
tags_components.component_id,
array_to_json(array_agg(tags.*)) as tags
FROM tags_components
LEFT JOIN (
SELECT id, name -- only two columns
FROM tags
) tags
ON tags.id = tags_components.tag_id
AND tags_components.component_name = 'company'
GROUP BY tags_components.component_id
I have a products table with two attribute column, and a json column. I'd like to be able to delimit the json column and insert extra rows retaining the attributes. Sample data looks like:
ID Name Attributes
1 Nikon {"4e7a":["jpg","bmp","nef"],"604e":["en"]}
2 Canon {"4e7a":["jpg","bmp"],"604e":["en","jp","de"]}
3 Olympus {"902c":["yes"], "4e7a":["jpg","bmp"]}
I understand OPENJSON can convert JSON objects into rows, and key values into cells but how do I apply it on a single column that contains JSON data?
My goal is to have an output like:
ID Name key value
1 Nikon 902c NULL
1 Nikon 4e7a ["jpg","bmp","nef"]
1 Nikon 604e ["en"]
2 Canon 902c NULL
2 Canon 4e7a ["jpg","bmp"]
2 Canon 604e ["en","jp","de"]
3 Olympus 902c ["yes"]
3 Olympus 4e7a ["jpg","bmp"]
3 Olympus 604e NULL
Is there a way I can query this products table like? Or is there a way to reproduce my goal data set?
SELECT
ID,
Name,
OPENJSON(Attributes)
FROM products
Thanks!
Here is something that will at least start you in the right direction.
SELECT P.ID, P.[Name], AttsData.[key], AttsData.[Value]
FROM products P CROSS APPLY OPENJSON (P.Attributes) AS AttsData
The one thing that has me stuck a bit right now is the missing values (value is null in result)...
I was thinking of maybe doing some sort of outer/full join back to this, but even that is giving me headaches. Are you certain you need that? Or, could you do an existence check with the output from the SQL above?
I am going to keep at this. If I find a solution that matches your output exactly, I will add to this answer.
Until then... good luck!
You can get the rows with NULL value fields by creating a list of possible keys and using CROSS APPLY to associate each key to each row from the original dataset, and then left-joining in the parsed JSON.
Here's a working example you should be able to execute as-is:
-- Throw together a quick and dirty CTE containing your example data
WITH OriginalValues AS (
SELECT *
FROM (
VALUES ( 1, 'Nikon', '{"4e7a":["jpg","bmp","nef"],"604e":["en"]}' ),
( 2, 'Canon', '{"4e7a":["jpg","bmp"],"604e":["en","jp","de"]}' ),
( 3, 'Olympus', '{"902c":["yes"], "4e7a":["jpg","bmp"]}' )
) AS T ( ID, Name, Attributes )
),
-- Build a separate dataset that includes all possible 'key' values from the JSON.
PossibleKeys AS (
SELECT DISTINCT A.[key]
FROM OriginalValues CROSS APPLY OPENJSON( OriginalValues.Attributes ) AS A
),
-- Get the existing keys and values from the JSON, associated with the record ID
ValuesWithKeys AS (
SELECT OriginalValues.ID, Atts.[key], Atts.Value
FROM OriginalValues CROSS APPLY OPENJSON( OriginalValues.Attributes ) AS Atts
)
-- Join each possible 'key' value with every record in the original dataset, and
-- then left join the parsed JSON values for each ID and key
SELECT OriginalValues.ID, OriginalValues.Name, KeyList.[key], ValuesWithKeys.Value
FROM OriginalValues
CROSS APPLY PossibleKeys AS KeyList
LEFT JOIN ValuesWithKeys
ON OriginalValues.ID = ValuesWithKeys.ID
AND KeyList.[key] = ValuesWithKeys.[key]
ORDER BY ID, [key];
If you need to include some pre-determined key values where some of them might not exist in ANY of the JSON values stored in Attributes, you could construct a CTE (like I did to emulate your original dataset) or a temp table to provide those values instead of doing the DISTINCT selection in the PossibleKeys CTE above. If you already know what your possible key values are without having to query them out of the JSON, that would most likely be a less costly approach.
I have an auditing/logging system that uses raw XML to represent actions taken out by an application. I'd like to improve on this system greatly by using an XML column in a table in the application's SQL Server database.
Each row in the table would contain one log entry and each entry should contain one or more tags that are used to describe the action in a semantic fashion that allows me to search in ways that match the auditing needs of the application, example:
<updateInvoice id="5" userId="7" /><fieldUpdate name="InvoiceDate" /><invoice /><update />
<deleteInvoice id="5" userId="6" /><invoice /><delete />
My intention is to return rowsets from this table by specifying combinations of tags and attributes to include or exclude rows by (e.g. "Include all rows with the tag invoice but exclude rows with the attribute userId='7'", or "Include all rows with the tag invoice but exclude rows with the tag delete)
I wish to do so programatically by using combinations of a simple filter structure to represent combinations of tags and attributes that I want to cause rows to be either included or excluded.
The structure I use looks like this:
enum FilterInclusion { Include, Exclude };
public struct Filter
{
FilterInclusion Inclusion;
string TagName;
string? AttributeName;
object? AttributeValue;
}
My goal is to accept a set of these and generate a query that returns any rows that match any single inclusion filter, without matching any single exclusion filter.
Should I and can I encode this boolean logic into the resulting XPath itself, or am I looking at having multiple SELECT statements in my outputted queries? I'm new to XQuery and any help is appreciated. Thanks!
I'm not sure if that's what you're looking for, but to filter nodes in XML methods you use the brackets [ and ]. For instance to select the elements foo but filter to only those that have the attribute bar you'd use an XPath like /foo[#bar]. If you want those that have the attribute #bar with value 5 you use /foo[#bar=5]. If you want to select the elements foo that have a child element bar you use /foo[bar].
declare #t table (x xml);
insert into #t (x) values
(N'<foo bar="abc"/>');
insert into #t (x) values
(N'<foo bar="5"/>');
insert into #t (x) values
(N'<foo id="1"><bar id="2"/></foo>');
select * from #t;
select c.value(N'#bar', N'varchar(max)')
from #t cross apply x.nodes(N'/foo[#bar]') t(c)
select c.value(N'#bar', N'varchar(max)')
from #t cross apply x.nodes(N'/foo[#bar=5]') t(c)
select c.value(N'#id', N'int')
from #t cross apply x.nodes(N'/foo[bar]') t(c)
I tried to show the examples on the XML snippets in your post, but there those are too structureless to make useful examples.