Postgres knex query joining columns - sql

I have a Postgres DB that stores data in a table that has the following columns "date | uid | id | value | data".
Using knex on a node.js server I currently get from this query:
data = await db(tableName).select(["date", "uid", "id", "value", "value as market_cap", "data"]).whereIn("id", ["index", "market_cap", "market"]);
the following result:
"data": [
{
"date": "2020-11-07T21:43:11.709Z",
"uid": "nmvdqy0kh87sd8a",
"id": "index",
"value": "999.9999999999999",
"market_cap": "999.9999999999999",
"data": null
},
{
"date": "2020-11-07T21:43:11.709Z",
"uid": "nmvdqy0kh87sd8b",
"id": "market_cap",
"value": "10125616413",
"market_cap": "10125616413",
"data": null
},
{
"date": "2020-11-07T21:43:11.709Z",
"uid": "nmvdqy0kh87sd8c",
"id": "market",
"value": null,
"market_cap": null,
"data": {
"1": [],
"2": []
}
},
...
];
The date pairs are all exactly the same. Data stored under id "market_cap" is actually stored as "value" and data stored under id "market" is actually stored as "data".
Now, what I actually need is:
"data": [
{
"date": "2020-11-07T21:43:11.709Z",
"value": "999.9999999999999",
"market_cap": "10125616413",
"data": {
"1": [],
"2": []
}
},
...
];
Is there a way to obtain this data structure directly from the database instead of transforming the data on the server? Bonus points it you provide the knex query / SQL query. Thank you!

You can accomplish this with a self-join on date and selecting on the rows with certain IDs. Left join ensures a result for each date even if they're missing a data type.
select mv."date", mv.value, mc.value as market_cap, md.data
from market_snapshots mv
left join market_snapshots mc on mv."date" = mc."date" and mc.id = 'market_cap'
left join market_snapshots md on mv."date" = md."date" and md.id = 'market'
where mv.id = 'index';
Try it.
In Knex it would be something like...
knex.select(['mv.date', 'mv.value', 'mc.value as market_cap', 'md.data'])
.from({ mv: 'market_snapshots' })
.leftJoin({ mc: 'market_snapshots' }, function() {
this.on('mv.date', '=', 'mc.date').andOn(knex.raw('mc.id = ?', 'market_cap'))
})
.leftJoin({ md: 'market_snapshots' }, function() {
this.on('mv.date', '=', 'md.date').andOn(knex.raw('md.id = ?', 'market'))
})
.where('mv.id', 'index')

Related

How to extract a value in a JSON table on BigQuery?

I have a JSON table which has over 30.000 rows. There are different rows like this:
JSON_columns
------------
{
"level": 20,
"nickname": "ABCDE",
"mission_name": "take_out_the_trash",
"mission_day": "150",
"duration": "0",
"properties": []
}
{
"nickname": "KLMNP",
"mission_name": "recycle",
"mission_day": "180",
"properties": [{
"key": "bottle",
"value": {
"string_value": "blue_bottle"
}
}, {
"key": "bottleRecycle",
"value": {
"string_value": "true"
}
}, {
"key": "price",
"value": {
"float_value": 21.99
}
}, {
"key": "cost",
"value": {
"float_value": 15.39
}
}]
}
I want to take the sum of costs the table. But firtsly, I want to extract the cost from the table.
I tried the code below. It returns null:
SELECT JSON_VALUE('$.properties[3].value.float_value') AS profit
FROM `missions.missions_study`
WHERE mission_name = "recycle"
My question is, how can I extract the cost values right, and sum them?
Common way to extract cost from your json is like below.
WITH sample_table AS (
SELECT '{"level":20,"nickname":"ABCDE","mission_name":"take_out_the_trash","mission_day":"150","duration":"0","properties":[]}' json
UNION ALL
SELECT '{"nickname":"KLMNP","mission_name":"recycle","mission_day":"180","properties":[{"key":"bottle","value":{"string_value":"blue_bottle"}},{"key":"bottleRecycle","value":{"string_value":"true"}},{"key":"price","value":{"float_value":21.99}},{"key":"cost","value":{"float_value":15.39}}]}' json
)
SELECT SUM(cost) AS total FROM (
SELECT CAST(JSON_VALUE(prop, '$.value.float_value') AS FLOAT64) AS cost
FROM sample_table, UNNEST(JSON_QUERY_ARRAY(json, '$.properties')) prop
WHERE JSON_VALUE(json, '$.mission_name') = 'recycle'
AND JSON_VALUE(prop, '$.key') = 'cost'
);

How to query in Array with Typeorm's Repository

This is the current repository code.
After joining the student and director tables in the attendance table, join the location table again in the student table, and join the schedule table in the director table to get the location information and date.
return await this.createQueryBuilder('tbl_attendance')
.leftJoin('tbl_attendance.student', 'student')
.leftJoin('student.location', 'location')
.select([
'student.gcn',
'student.id',
'student.name',
'tbl_attendance.period',
'location.name',
'tbl_attendance.state',
])
.leftJoin('tbl_attendance.director', 'director')
.leftJoin('director.schedule', 'schedule')
.where('location.floor= :floor', { floor: floor })
.andWhere('schedule.date= :date', { date: date })
.andWhere('tbl_attendance.state= :state', { state: state })
.getMany();
}
And this is the currently returned json
[
{
"state": "MOVE",
"period": 7,
"student": {
"id": 1,
"name": "anne",
"gcn": "1301",
"location": {
"name": "semina 2-1"
}
}
},
{
"state": "MOVE",
"period": 8,
"student": {
"id": 1,
"name": "anne",
"gcn": "1301",
"location": {
"name": "semina 2-1"
}
}
}
]
I wish it was returned like this.
[
{
"gcn": 1301,
"student_id": 3,
"student_name": "anne",
"student_attendance": [
{
"period" : 8
"location_name": null || "semina2-1",
"state": "MOVE"
},
{
"period": 9
"location_name": null || "semina2-1",
"state": "MOVE"
},
{
"period": 10
"location_name": null || "semina2-1",
"state":"MOVE"
}
]
}
]
How do I get the student's place id and status for each class separately as an array?
Perhaps you should query the student table and join the related entities onto that one. That way, your result would be an array of students, with each its own array of attendance object.
Now, when it comes to joining with TypeORM, joined tables will always be nested in the resulting object, as an array or an object for one-to-many and many-to-one relationships respectively. There is no straightforward way to control the shape of the resulting data other than mapping it manually.

Problem with using of FOR JSON AUTO in SQL Server

I am using FOR JSON AUTO in SQL server database, to convert my query's result to the JSON format.
in my query, I joined order table to two other tables.
SELECT
orders.[Code], orders.[Total], orders.[Discount],
customer.[Name], customer.[PhoneNumber],
store.[Name], store.[Address]
FROM
Orders orders
INNER JOIN
Customers customer ON (orders.[CustomerID] = customer.[ID])
INNER JOIN
Stores store ON (orders.[StoreID] = store.[ID])
FOR JSON AUTO
Result:
[
{
"Code": "1528",
"Total": 5000,
"Discount": 20,
"customer": [
{
"Name": "Alex",
"PhoneNumber": "(548) 123-5555",
"store": [
{
"Name": "Apple",
"Address": "E. Santa rd"
}
]
}
]
},
{
"Code": "1687",
"Total": 3000,
"Discount": 10,
"customer": [
{
"Name": "John",
"PhoneNumber": "(226) 354-7896",
"store": [
{
"Name": "Sony",
"Address": "W. Atlantic ave"
}
]
}
]
}
]
But it's not correct, because in this scenario customer and store are sibling and they have same parent, and both of them joined with the order table directly, correct JSON must be such as this:
[
{
"Code": "1528",
"Total": 5000,
"Discount": 20,
"customer": [
{
"Name": "Alex",
"PhoneNumber": "(548) 123-5555"
}
],
"store": [
{
"Name": "Apple",
"Address": "E. Santa rd"
}
]
},
{
"Code": "1687",
"Total": 3000,
"Discount": 10,
"customer": [
{
"Name": "John",
"PhoneNumber": "(226) 354-7896"
}
],
"store": [
{
"Name": "Sony",
"Address": "W. Atlantic ave"
}
]
}
]
how can I do that? Are there any option for this in SQL? (I don't want to use inner select.)
If there are one-to-one relationships between Orders and Customer and between Orders and Store then you can make the desired output by using PATH option and dot-separated column names:
SELECT
orders.[Code], orders.[Total], orders.[Discount],
customer.[Name] AS [Customer.Name], customer.[PhoneNumber] AS [Customer.PhoneNumber],
store.[Name] AS [Store.Name], store.[Address] AS [Store.Address]
FROM
Orders orders
INNER JOIN
Customers customer ON (orders.[CustomerID] = customer.[ID])
INNER JOIN
Stores store ON (orders.[StoreID] = store.[ID])
FOR JSON PATH
But if there are one-to-many relationships then you have to use nested queries:
SELECT
orders.[Code], orders.[Total], orders.[Discount],
(SELECT [Name], [PhoneNumber] FROM Customers WHERE Customers.ID=Orders.CustomerID FOR JSON AUTO) AS Customers,
(SELECT [Name], [Address] FROM Stores WHERE Stores.ID=Orders.StoreID FOR JSON AUTO) AS Stores
FROM
Orders orders
FOR JSON AUTO

How to update value in nested json Postgres

I have following JSON stored in "Info" column
{
"customConfig": {
"isCustomGoods": 1
},
"new_addfields": {
"data": [
{
"val": {
"items": [
{
"Code": "calorie",
"Value": "365.76"
},
{
"Code": "protein",
"Value": "29.02"
},
{
"Code": "fat",
"Value": "23.55"
},
{
"Code": "carbohydrate",
"Value": "6.02"
},
{
"Code": "spirit",
"Value": "1.95"
}
],
"storageConditions": "",
"outQuantity": "100"
},
"parameterType": "Nutrition",
"name": "00000000-0000-0000-0000-000000000001",
"label": "1"
},
{
"name": "b4589168-5235-4ec5-bcc7-07d4431d14d6_Для ресторанов",
"val": "true"
}
]
}
}
I want to update value of nested json
{
"name": "b4589168-5235-4ec5-bcc7-07d4431d14d6_Для ресторанов",
"val": "true"
}
and set "val"to "Yes" str so the result should be like
{
"name": "b4589168-5235-4ec5-bcc7-07d4431d14d6_Для ресторанов",
"val": "Yes"
}
How can i do that ? Assuming that i need to update this value in json for many records in database
Considering you have a constant JSON Structure and a primary key in your table. Idea is to get the exact path of element val having value true (which can be at any index in the array) then replace it with desired value. So you can write your query like below:
with cte as (
select
id,
('{new_addfields,data,'||index-1||',val}')::text[] as json_path
from
test,
jsonb_array_elements(info->'new_addfields'->'data')
with ordinality arr(vals,index)
where
arr.vals->>'val' ilike 'true'
)
update test
set info = jsonb_set(info,cte.json_path,'"Yes"',false)
from cte
where test.id=cte.id;
DEMO
We can use jsonb_set() which is available from Postgres 9.5+
From Docs:
jsonb_set(target jsonb, path text[], new_value jsonb [, create_missing boolean])
Query to update the nested object:
UPDATE temp t
SET info = jsonb_set(t.info,'{new_addfields,data,1,val}', jsonb '"Yes"')
where id = 1;
It can also be used in select query:
SELECT
jsonb_set(t.info,'{new_addfields,data,1,val}', jsonb '"Yes"')
FROM temp t
LIMIT 1;

How to filter Cosmos DB data based on value of an element in an array of values Using SQL API

I have a cosmosDB collection with below Data in it.
I have to find out the data only for EVENT named ABC and its value using SQL query.
[
{
"ID": "01XXXXX",
"EVENTS": [
{
"Name": "ABC",
"Value": 0
},
{
"Name": "XYZ",
"Value": 4
},
{
"Name": "PQR",
"Value": 5
}
]
},
{
"ID": "02XXXXX",
"EVENTS": [
{
"Name": "ABC",
"Value": 1
},
{
"Name": "XYZ",
"Value": 2
},
{
"Name": "PQR",
"Value": 3
}
]
}
]
I have tried the below code but it is not working since EVENT is an array.
SELECT * FROM c where c.EVENTS.Name = 'ABC'
Is there any way to find filter out the data only with Event Name as ABC using SQL?
Try using join
SELECT c FROM c
join l in c.EVENTS
where l.Name = 'ABC'