I have a products table which contains a JSON column product_logs. Inside of this, it contains something similar to:
{
"c8eebc99-d936-3245-bc8d-17694f4ecb58": {
"created_at": "2022-05-08T15:33:33.591166Z",
"event": "product-created",
"user": null
},
"ce7b171b-b479-332f-bf9e-54b948581179": {
"created_at": "2022-05-08T15:33:33.591174Z",
"event": "near-sell-by",
"user": null
}
}
I only want to return rows of products that have a near-sell-by event in the product_logs so I try to do this:
SELECT
products.*
FROM products,
JSON_TABLE(product_logs, '$[*]', COLUMNS (
created_at DATETIME PATH '$.created_at',
event VARCHAR(MAX) PATH '$.event'
) logs
WHERE
logs.event = 'near-sell-by'
However, I seem to be getting the following error:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '(product_logs, '$[*]', COLUMNS (
created_at DATETIME PATH '$.cr...' at line 4
Any help to where I'm going wrong would be greatly appreciated
You seem to have copied, from another database, there is no varchar8max) in mysql, to syntax is a bit complicated, and you need to undestand json pretty well.
a gui like workbench, at least can help you identify the error, but it will not help you
CREATE TABLE products (product_logs varchar(1209))
INSERT INTO products VALUES ('{
"c8eebc99-d936-3245-bc8d-17694f4ecb58": {
"created_at": "2022-05-08T15:33:33.591166Z",
"event": "product-created",
"user": null
},
"ce7b171b-b479-332f-bf9e-54b948581179": {
"created_at": "2022-05-08T15:33:33.591174Z",
"event": "near-sell-by",
"user": null
}
}
')
SELECT
products.*,logs.created_at,logs.event
FROM products,
JSON_TABLE(products.product_logs, '$.*'
COLUMNS (
created_at DATETIME PATH '$.created_at',
event Text PATH '$.event'
)) logs
WHERE
logs.event = 'near-sell-by'
product_logs | created_at | event
:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------ | :-----------
{<br> "c8eebc99-d936-3245-bc8d-17694f4ecb58": {<br> "created_at": "2022-05-08T15:33:33.591166Z",<br> "event": "product-created",<br> "user": null<br> },<br> "ce7b171b-b479-332f-bf9e-54b948581179": {<br> "created_at": "2022-05-08T15:33:33.591174Z",<br> "event": "near-sell-by",<br> "user": null<br> }<br>}<br> | 2022-05-08 15:33:34 | near-sell-by
db<>fiddle here
Related
I have a table which has a JSON column called people like this:
Id
people
1
[{ "id": 6 }, { "id": 5 }, { "id": 3 }]
2
[{ "id": 2 }, { "id": 3 }, { "id": 1 }]
...and I need to update the people column and put a 0 in the path $[*].id where id = 3, so after executing the query, the table should end like this:
Id
people
1
[{ "id": 6 }, { "id": 5 }, { "id": 0 }]
2
[{ "id": 2 }, { "id": 0 }, { "id": 1 }]
There may be more than one match per row.
Honestly, I didnĀ“t tried any query since I cannot figure out how can I loop inside a field, but my idea was something like this:
UPDATE mytable
SET people = JSON_SET(people, '$[*].id', 0)
WHERE /* ...something should go here */
This is my version
SELECT VERSION()
+-----------------+
| version() |
+-----------------+
| 10.4.22-MariaDB |
+-----------------+
If the id values in people are unique, you can use a combination of JSON_SEARCH and JSON_REPLACE to change the values:
UPDATE mytable
SET people = JSON_REPLACE(people, JSON_UNQUOTE(JSON_SEARCH(people, 'one', 3)), 0)
WHERE JSON_SEARCH(people, 'one', 3) IS NOT NULL
Note that the WHERE clause is necessary to prevent the query replacing values with NULL when the value is not found due to JSON_SEARCH returning NULL (which then causes JSON_REPLACE to return NULL as well).
If the id values are not unique, you will have to rely on string replacement, preferably using REGEXP_REPLACE to deal with possible differences in spacing in the values (and also avoiding replacing 3 in (for example) 23 or 34:
UPDATE mytable
SET people = REGEXP_REPLACE(people, '("id"\\s*:\\s*)2\\b', '\\14')
Demo on dbfiddle
As stated in the official documentation, MySQL stores JSON-format strings in a string column, for this reason you can either use the JSON_SET function or any string function.
For your specific task, applying the REPLACE string function may suit your case:
UPDATE
mytable
SET
people = REPLACE(people, CONCAT('"id": ', 3, ' '), CONCAT('"id": ',0, ' '))
WHERE
....;
I am still learning Snowflake, any help would be really appreciated
I have a table(tbl1) that has a variant column(column_json) which looks like below:
{
"catalog": [
{
"img_href": "https://schumacher-webassets.s3.amazonaws.com/Web%20Catalog-600/179361.jpg",
"name": "ADITI HAND BLOCKED PRINT",
"price": 16
},
{
"img_href": "https://schumacher-webassets.s3.amazonaws.com/Web%20Catalog-600/179330.jpg",
"name": "TORBAY HAND BLOCKED PRINT",
"price": 17
},
{
"img_href": "https://schumacher-webassets.s3.amazonaws.com/Web%20Catalog-600/179362.jpg",
"name": "ADITI HAND BLOCKED PRINT",
"price": 18
}
],
"datetime": 161878993658
"catalog_id": 1
}
I am trying to add a new key-value pair to objects in catalog array. Hence, I am using an update query to update.
Here's my update query:
UPDATE tbl1
SET column_json:catalog[0] = object_insert(column_json:catalog[0], 'item_href', 'https://fschumacher.com/178791')
WHERE column_json:catalog_id = '1'
However I am facing below error
SQL compilation error: syntax error line 2 at position 20 unexpected ':'.
UPDATE only supports column operations so your approach won't work.
Rebuilding the catalog, as below, will work (but it does make me pause and wonder if there's a better way.)
UPDATE tbl1
SET column_json = new_catalog
FROM (select object_construct('catalog_id', catalog_id, 'datetime', any_value(datetime), 'catalog', array_agg(new_col)) new_catalog from (select column_json:datetime datetime, column_json:catalog_id catalog_id, iff(c.index = 0 and column_json:catalog_id = '1', object_insert(column_json:catalog[0], 'item_href', 'https://fschumacher.com/178791', true), c.value) new_col from tbl1, lateral flatten(column_json:catalog) c) group by catalog_id)
WHERE column_json:catalog_id = '1';
--This results in the following:
--select column_json:catalog[0].item_href from tbl1;
--"https://fschumacher.com/178791"
I am trying to build a query which combines rows of one table into a JSON array, I then want that array to be part of the return.
I know how to do a simple query like
SELECT *
FROM public.template
WHERE id=1
And I have worked out how to produce the JSON array that I want
SELECT array_to_json(array_agg(to_json(fields)))
FROM (
SELECT id, name, format, data
FROM public.field
WHERE template_id = 1
) fields
However, I cannot work out how to combine the two, so that the result is a number of fields from public.template with the output of the second query being one of the returned fields.
I am using PostGreSQL 9.6.6
Edit, as requested more information, a definition of field and template tables and a sample of each queries output.
Currently, I have a JSONB row on the template table which I am using to store an array of fields, but I want to move fields to their own table so that I can more easily enforce a schema on them.
Template table contains:
id
name
data
organisation_id
But I would like to remove data and replace it with the field table which contains:
id
name
format
data
template_id
At the moment the output of the first query is:
{
"id": 1,
"name": "Test Template",
"data": [
{
"id": "1",
"data": null,
"name": "Assigned User",
"format": "String"
},
{
"id": "2",
"data": null,
"name": "Office",
"format": "String"
},
{
"id": "3",
"data": null,
"name": "Department",
"format": "String"
}
],
"id_organisation": 1
}
This output is what I would like to recreate using one query and both tables. The second query outputs this, but I do not know how to merge it into a single query:
[{
"id": 1,
"name": "Assigned User",
"format": "String",
"data": null
},{
"id": 2,
"name": "Office",
"format": "String",
"data": null
},{
"id": 3,
"name": "Department",
"format": "String",
"data": null
}]
The feature you're looking for is json concatenation. You can do that by using the operator ||. It's available since PostgreSQL 9.5
SELECT to_jsonb(template.*) || jsonb_build_object('data', (SELECT to_jsonb(field) WHERE template_id = templates.id)) FROM template
Sorry for poorly phrasing what I was trying to achieve, after hours of Googling I have worked it out and it was a lot more simple than I thought in my ignorance.
SELECT id, name, data
FROM public.template, (
SELECT array_to_json(array_agg(to_json(fields)))
FROM (
SELECT id, name, format, data
FROM public.field
WHERE template_id = 1
) fields
) as data
WHERE id = 1
I wanted the result of the subquery to be a column in the ouput rather than compiling the entire output table as a JSON.
Assume I am using PG 9.3 and I have a post table with a json column 'meta_data':
Example content of the json column 'meta_data'
{
"content": "this is a post body",
"comments": [
{
"user_id": 1,
"content": "hello"
},
{
"user_id": 2,
"content": "foo"
},
{
"user_id": 3,
"content": "bar"
}
]
}
How can I find all the posts where the user_id = 1 from the comments array from the meta_data column?
I'm almost positive I'm implementing this incorrectly but try this
select *
from posts
where id in (
select id from (
select id,
json_array_elements(meta_data->'comments')->'user_id' as user_id
from posts
) x
where cast(user_id as varchar) = '1'
);
There's probably an array operator like #> that will remove the need for the nested select statements but I can't seem to get it to work right now.
Let me know if this is going down the correct track, I'm sure we could figure it out if required.
UPDATE:
I've turned my xml into a query table in coldfusion, so this may help to solve this.
So my data is:
[id] | [code] | [desc] | [supplier] | [name] | [price]
------------------------------------------------------
1 | ABCDEF | "Tst0" | "XYZ" | "Test" | 123.00
2 | ABCDXY | "Tst1" | "XYZ" | "Test" | 130.00
3 | DCBAZY | "Tst2" | "XYZ" | "Tst2" | 150.00
Now what I need is what the linq to xml query outputs below. Output should be something like (i'll write it in JSON so it's easier for me to type) this:
[{
"code": "ABCD",
"name": "Test",
"products":
{
"id": 1,
"code": "ABCDEF",
"desc": "Tst0",
"price": 123.00
},
{
"id": 2,
"code": "ABCDXY",
"desc": "Tst1",
"price": 130.00
}
},
{
"code": "DCBA",
"name": "Tst2",
"products":
{
"id": 3,
"code": "DCBAZY",
"desc": "Tst2",
"price": 150.00
}
}]
As you can see, Group by the first 4 characters of 'CODE' and 'Supplier' code.
Thanks
How would i convert the following LINQ to XML query to SQL?
from q in query
group q by new { Code = q.code.Substring(0, 4), Supplier = q.supplier } into g
select new
{
code = g.Key.Code,
fullcode = g.FirstOrDefault().code,
supplier = g.Key.Supplier,
name = g.FirstOrDefault().name,
products = g.Select(x => new Product { id = x.id, c = x.code, desc = string.IsNullOrEmpty(x.desc) ? "Description" : x.desc, price = x.price })
}
Best i could come up with:
SELECT c, supplier, n
FROM products
GROUP BY C, supplier, n
Not sure how to get the subquery in there or get the substring of code.
ps: this is for coldfusion, so I guess their version of sql might be different to ms sql..
The easiest way is to attache a profiler to you database and see what query is generate by the linq-to-SQL engine.