Json in Postgresql - json

I'm learning Postgresql and Json.
I have for example database like that:
CREATE TABLE employees (
employee_id serial primary key,
department_id integer references departments(department_id),
name text,
start_date date,
fingers integer,
geom geometry(point, 4326)
);
CREATE TABLE departments (
department_id bigint primary key,
name text
);
INSERT INTO departments
(department_id, name)
VALUES
(1, 'spatial'),
(2, 'cloud');
INSERT INTO employees
(department_id, name, start_date, fingers, geom)
VALUES
(1, 'Paul', '2018/09/02', 10, 'POINT(-123.32977 48.40732)'),
(1, 'Martin', '2019/09/02', 9, 'POINT(-123.32977 48.40732)'),
(2, 'Craig', '2019/11/01', 10, 'POINT(-122.33207 47.60621)'),
(2, 'Dan', '2020/10/01', 8, 'POINT(-122.33207 47.60621)');
How could i do so i could get the data like this:
[
{
"department_name": "cloud",
"employees": [
{
"name": "Craig",
"start_date": "2019-11-01"
},
{
"name": "Dan",
"start_date": "2020-10-01"
}
]
},
{
"department_name": "spatial",
"employees": [
{
"name": "Paul",
"start_date": "2018-09-02"
},
{
"name": "Martin",
"start_date": "2019-09-02"
}
]
}
]

follow this link: https://dba.stackexchange.com/questions/69655/select-columns-inside-json-agg/200240#200240
CREATE TEMP TABLE x (
name text,
start_date date
);
WITH cte AS (
SELECT
d.name AS department_name,
json_agg((e.name, e.start_date)::x) AS employees
FROM
departments d
JOIN employees e ON d.department_id = e.department_id
GROUP BY
1
)
SELECT
json_agg((row_to_json(cte.*)))
FROM
cte;

Related

SQL including count and multiple where clauses

I have 2 tables.
Table text_to_annotate:
CREATE TABLE text_to_annotate (
ID varchar(3),
text varchar(100));
INSERT INTO text_to_annotate (ID, text)
VALUES
(1, test1),
(2, test2),
(3, test3);
Table annotation_data:
CREATE TABLE annotation_data (
text_ID varchar(3),
annotation_ID varchar(3)
IP varchar(15));
INSERT INTO annotation_data (text_ID, annotation_ID, IP)
VALUES
(1, 0, IP_1),
(2, 1, IP_1),
(3, 2, IP_1),
(1, 1, IP_2),
(2, 2, IP_2),
(3, 3, IP_2),
(3, 0, IP_3),
(3, 0, IP_4),
(3, 2, IP_5);
I want to display an unseen text to an annotator which hasn't been annotated more than 5 times. For example, a new annotator with IP = IP_6 cannot annotate text_ID = 3, only text_ID = 1 and text_ID = 2. An annotator can only annotate unique text_IDs once.
Here's my code, but something isn't quite correct:
SELECT text_to_annotate.ID, text_to_annotate.text
FROM text_to_annotate
WHERE text_to_annotate.ID NOT IN (
SELECT text_ID, count(*)
FROM annotation_data
WHERE IP = '{$ip}'
AND GROUP BY text_ID
HAVING count(*) > 1;
)
ORDER BY RAND()
Here's my answer:
SELECT text_to_annotate.ID, text_to_annotate.text
FROM text_to_annotate
WHERE text_to_annotate.ID NOT IN (
SELECT text_ID, count(*)
FROM annotation_data
WHERE IP = '{$ip}'
)
AND text_to_annotate.ID IN (
SELECT text_ID FROM impact_annotation
GROUP BY text_ID
HAVING COUNT(*) < 5
)
ORDER BY RAND()

How to remove multiple values of different dictionaries stored in arrays with JSON_REMOVE?

I have the following json doc in MYSQL JSON field called test:
[
{"a": "1", "b": "2"},
{"a": "1", "b": "-2"},
{"a": "2", "b": "3"},
{"a": "2", "b": "-3"},
{"a": "3", "b": "4"}
]
CREATE TABLE `test` (`test` JSON);
INSERT INTO `test` VALUES
(JSON_ARRAY(JSON_OBJECT('a', '1', 'b', '2'),
JSON_OBJECT('a', '1', 'b', '-2'),
JSON_OBJECT('a', '2', 'b', '3'),
JSON_OBJECT('a', '2', 'b', '-3'),
JSON_OBJECT('a', '3', 'b', '4'))),
(JSON_ARRAY()),
(JSON_ARRAY());
SELECT JSON_UNQUOTE(JSON_SEARCH(`test`, 'all', 1, null, '$[*].a')) `data`
FROM `test`;
+----------------------+
| data |
+----------------------+
| ["$[0].a", "$[1].a"] |
| NULL |
| NULL |
+----------------------+
And I want to remove all dictionaries that have key/value "a": "1".
So I tried this:
UPDATE `test`
SET `test` = JSON_REMOVE(`test`, JSON_UNQUOTE(JSON_SEARCH(`test`,
'all',
1,
null,
'$[*].a')));
The expected result that I wanted is, but of course it doesn't work:
// This is an expected result after update
SELECT JSON_UNQUOTE(JSON_SEARCH(`test`, 'all', 1, null, '$[*].a')) `data`, `test` FROM `test`;
+----------------------+------------------------------------------------------------------------------------------------------------------+
| data | test |
+----------------------+------------------------------------------------------------------------------------------------------------------+
| NULL | [{"a": "2", "b": "3"}, {"a": "2", "b": "-3"}, {"a": "3", "b": "4"}] |
| NULL | [] |
| NULL | [] |
+----------------------+------------------------------------------------------------------------------------------------------------------+
Note that the mysql version is 8.0
Thank you
You can use Recursive CTE along with JSON_EXTRACT() function in order to dynamically generate the indexes, of which don't match a = 1, of objects within the array such as
WITH RECURSIVE cte AS
(
SELECT 0 i
UNION ALL
SELECT i + 1 i
FROM cte
WHERE i + 1 < ( SELECT JSON_LENGTH(jsdata) FROM `test` )
)
SELECT JSON_ARRAYAGG(JSON_EXTRACT(jsdata, CONCAT('$[',i,']'))) AS Result
FROM `test`,
cte
WHERE JSON_EXTRACT(jsdata, CONCAT('$[',i,'].a')) != "1"
provided that the version of the DB is 8+
Demo
WITH
-- enumerate rows - unique value per row is needed for reconstruction
cte1 AS (
SELECT *, ROW_NUMBER() OVER () rn
FROM test
),
-- decompose JSON array to separate objects properties,
-- select only those which does not contain unneeded value
cte2 AS (
SELECT cte1.*, jsontable.a, jsontable.b
FROM cte1
CROSS JOIN JSON_TABLE(cte1.test,
'$[*]' COLUMNS ( a VARCHAR(255) PATH '$.a',
b VARCHAR(255) PATH '$.b')) jsontable
WHERE jsontable.a <> 1
),
-- reconstruct the array w/o unneeded objects back
cte3 AS (
SELECT test, rn, JSON_ARRAYAGG(JSON_OBJECT('a', a, 'b', b)) new_test
FROM cte2
GROUP BY test, rn
)
-- update sourdce table
UPDATE test
JOIN cte3 ON test.test = cte3.test
SET test.test = cte3.new_test;
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=05e4db09be79152c37b9b482b8bff170
If the table in practice contains primary key or at least unique index then you can simplify the query (cte1 not needed, final join can be performed by this PK/unique).

Turn Rows into Multiple elements in JSON

I have 1 order number which contains 4 skus, each sku is linked to 3 categories:
I need to write a SQL statement to convert this into JSON format which involves subquery and multiple elements in an array. Basically I need it to look like this:
{
"order_number": "WEB000000000",
"order_items": [
{
"sku": 111111111,
"categories": ["Checked Shirts", "Mens", "Shirts"]
},
{
"sku": 333333333,
"categories": ["Accessories & Shoes", "Mens Accessories", "Socks"]
},
{
"sku": 666666666,
"categories": ["Checked Shirts", "Mens", "Shirts"]
},
{
"sku": 999999999,
"categories": ["Nightwear", "Slippers", "Womens"]
}
]
}
Here's what I have so far but I just can't get it quite right:
DROP TABLE IF EXISTS ##Data;
CREATE TABLE ##Data
(
order_number varchar(100),
sku bigint,
categories varchar(100)
);
INSERT INTO ##Data
select 'WEB000000000', 111111111, 'Mens'
union all select 'WEB000000000', 111111111, 'Shirts'
union all select 'WEB000000000', 111111111, 'Checked Shirts'
union all select 'WEB000000000', 333333333, 'Accessories & Shoes'
union all select 'WEB000000000', 333333333, 'Mens Accessories'
union all select 'WEB000000000', 333333333, 'Socks'
union all select 'WEB000000000', 666666666, 'Mens'
union all select 'WEB000000000', 666666666, 'Shirts'
union all select 'WEB000000000', 666666666, 'Checked Shirts'
union all select 'WEB000000000', 999999999, 'Womens'
union all select 'WEB000000000', 999999999, 'Nightwear'
union all select 'WEB000000000', 999999999, 'Slippers'
SELECT * FROM ##Data;
select OUTER1.[order_number] as [order_number],
(select OSL.[order_number],
(select [sku],
(select [categories]
from ##Data skus
where order_item.[order_number] = skus.[order_number]
and order_item.[sku] = skus.[sku]
GROUP BY [categories]
FOR JSON PATH) as categories
from ##Data order_item
where order_item.[order_number] = OSL.[order_number]
GROUP BY [order_number], [sku]
FOR JSON PATH) as order_items
from ##Data OSL
where OSL.[order_number]=OUTER1.[order_number]
group by OSL.[order_number]
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER) AS JSON
from ##Data OUTER1
group by OUTER1.[order_number]
drop table ##Data

Add count to N1QL query result in Couchbase

I have a N1QL query:
SELECT p.`ID`, p.`Name` FROM `Preferences` p WHERE `type` = "myType"
The result is a list of objects[{"ID": "123", "Name": "John"}, ...]
I want to get a result JSON such as:
{
"count": 5,
"result": [{"ID": "123", "Name": "John"}, ...]
}
How could I do this using N1QL?
SELECT
COUNT(t.ID) AS count,
ARRAY_AGG(t) AS results
FROM
(
SELECT
p.`ID`, p.`Name`
FROM
`Preferences` p
WHERE `type` = "myType"
) AS t

stuck with appending name to the sub elements in json

I have 3 tables with the following schema.
a.c1 int (pk),
a.c2 varchar(50),
a.c3 varchar(50),
b.c1 int(pk),
b.c2 int(fk) -> a.c1,
b.c3 varchar(50),
b.c4 varchar(50),
c.c1 int(pk),
c.c2 int(fk) -> b.c1,
c.c3 int(fk) -> a.c1,
c.c4 varchar(50),
c.c5 varchar(50)
I'm expecting the result to be
{
"json_doc": {
"a.c1": "val",
"a.c2": "val",
"a.c3": "val",
"b": [{
"b_c1_value": {
"b.c1": "val",
"b.c2": "val",
"b.c3": "val",
"b.c4": "val",
"c": [{
"c_c1_value": {
"c.c1": "val",
"c.c2": "val",
"c.c3": "val",
"c.c4": "val",
"c.c5": "val"
}
}]
}
}]
}
}
Can someone please help me with the right sql. I'm very very new to Postgres.
I have gotten this far:
select row_to_json(t)
from (
select
*,
(
select array_to_json(array_agg(row_to_json(d)))
from (
select
*,
(
select array_to_json(array_agg(row_to_json(dc)))
from (
select *
from c
where c.c2 = b.c1
) dc
) as c
from b
where c2 = a.c1
) d
) as b
from a
WHERE a.deployid = 19
) t;
I need key names for the arrays to be populated. I'm stuck with this. Any help is deeply appreciated!