Related
These are my tables:
CREATE TABLE product (
product_id serial PRIMARY KEY,
name VARCHAR ( 50 ),
size VARCHAR ( 50 ),
)
CREATE TABLE country (
country_id serial PRIMARY KEY,
name VARCHAR ( 50 ),
product_id INT
)
CREATE TABLE color (
color_id serial PRIMARY KEY,
name VARCHAR ( 50 ),
product_id INT
)
I want my query to return the list of product in this way.
Query result needs to have to objects: meta and result
The result needs to be paginated with 10 objects. And meta should include the total count of filtered products, count of attributes of products.
When country is filtered, I want to see other country choices' names and counts as well, not only the country filtered (same for the color).
If the color is filtered, I don't want to see the countries that are not available with this color for the products we have (and vice versa):
{
"meta": {
"count" : 200,
"next_page": true,
"colors": [
{"id": 1, "name": "red", "count": 5},
{"id": 2, "name": "white", "count": 10}
],
"countries": [
{"id": 1, "name": "Germany", "count": 120},
{"id": 2, "name": "Albania", "count": 201}
],
"sizes": [
{"id": 1, "name": "Big", "count": 45},
{"id": 2, "name": "Small", "count": 63}
]
},
"result": [
{
"product_name" : "Milk",
"color": "White",
"country": "Germany"
},
{
"product_name" : "Milk2",
"color": "White",
"country": "Germany"
},
{
"product_name" : "Milk3",
"color": "White",
"country": "Germany"
}
]
}
This is what I've done:
WITH results as (
SELECT
product.id,
product.name,
product.size,
color.name,
country.name
FROM product
LEFT JOIN color ON color.product_id = product.id
LEFT JOIN country ON country.product_id = product.id
WHERE color.name = ANY('{White}')
)
SELECT
(
SELECT
jsonb_build_object(
'count', count.full_count,
'next_page', count.full_count - (1 * 10) > 0
)
FROM (SELECT count(id) AS full_count FROM results) AS count
) AS meta,
(
SELECT jsonb_agg(result_rows)
FROM
(SELECT * FROM results
LIMIT 10
OFFSET (1-1) * 10) AS result_rows
) AS result
I've tried lot's of thing and did not get the result of getting name and counts of country and colors. So I didn't include that part of query. BTW, the the slight change in query returning result is acceptable.
Any help is highly appreciated. I'm using the latest version of PostgreSQL. You can see this type of query used in Ebay (search results page) where page filter properties change while you select different filters to correspond the available choices and counts depending your current filters.
First of all, your data model looks like strange (or wrong). I would suggest you the following data model instead, so that you can store several products with the same size and/or the same color and/or the same country. The only limitation here is that one product may only have one size, one color, and one country. You will have to create new tables if you want to manage one to many relationships.
CREATE TABLE size (
size_id serial PRIMARY KEY,
name VARCHAR ( 50 )
) ;
CREATE TABLE country (
country_id serial PRIMARY KEY,
name VARCHAR ( 50 )
) ;
CREATE TABLE color (
color_id serial PRIMARY KEY,
name VARCHAR ( 50 )
) ;
CREATE TABLE product (
product_id serial PRIMARY KEY,
name VARCHAR ( 50 ),
size_id INT CONSTRAINT rf_size REFERENCES size (size_id) MATCH SIMPLE,
color_id INT CONSTRAINT rf_color REFERENCES color (color_id) MATCH SIMPLE,
country_id INT CONSTRAINT rf_country REFERENCES country (country_id) MATCH SIMPLE
) ;
Then you can get your expected with the following query :
WITH global_list AS (
SELECT p.size_id, p.color_id, p.country_id
, s.name AS size_name, clr.name AS color_name, cty.name AS country_name
, count(*) AS product_count
FROM product AS p
INNER JOIN country AS cty
ON cty.country_id = p.country_id
INNER JOIN color AS clr
ON clr.color_id = p.color_id
INNER JOIN size AS s
ON s.size_id = p.size_id
GROUP BY p.size_id, size_name, p.color_id, color_name, p.country_id, country_name
), result_list AS (
SELECT jsonb_build_object('product_name',p.name,'color',clr.name,'country',cty.name, 'size', s.name) AS result
, count(*) OVER () AS total_count
FROM product AS p
INNER JOIN country AS cty
ON cty.country_id = p.country_id
INNER JOIN color AS clr
ON clr.color_id = p.color_id
INNER JOIN size AS s
ON s.size_id = p.size_id
WHERE cty.name = COALESCE('Albania', cty.name) -- enter here the country filter criteria if any, like 'Germany', or NULL if no country criteria
AND clr.name = COALESCE(NULL, clr.name) -- enter here the color filter criteria if any, like 'White', or NULL if no color criteria
AND s.name = COALESCE(NULL, s.name) -- enter here the size filter criteria if any, like 'Medium', or NULL if no size criteria
), country_list AS (
SELECT jsonb_build_object('id', gl.country_id, 'name', gl.country_name, 'count', sum(gl.product_count)) AS country
FROM global_list AS gl
WHERE gl.color_name = COALESCE(NULL, gl.color_name) -- same color criteria than above
AND gl.size_name = COALESCE(NULL, gl.size_name) -- same size criteria than above
GROUP BY gl.country_id, gl.country_name
), color_list AS (
SELECT jsonb_build_object('id', gl.color_id, 'name', gl.color_name, 'count', sum(gl.product_count)) AS color
FROM global_list AS gl
WHERE gl.country_name = COALESCE('Albania', gl.country_name) -- same country criteria than above
AND gl.size_name = COALESCE(NULL, gl.size_name) -- same size criteria than above
GROUP BY gl.color_id, gl.color_name
), size_list AS (
SELECT jsonb_build_object('id', gl.size_id, 'name', gl.size_name, 'count', sum(gl.product_count)) AS size
FROM global_list AS gl
WHERE gl.country_name = COALESCE('Albania', gl.country_name) -- same country criteria than above
AND gl.color_name = COALESCE(NULL, gl.color_name) -- same color criteria than above
GROUP BY gl.size_id, gl.size_name
)
SELECT (SELECT jsonb_build_object('result', jsonb_agg(result)) FROM result_list LIMIT 10 OFFSET 0)
|| jsonb_build_object('meta'
, jsonb_build_object( 'count', (SELECT total_count FROM result_list LIMIT 1)
, 'next_page', (SELECT total_count > 10 FROM result_list LIMIT 1)
, 'countries', (SELECT jsonb_agg(country) FROM country_list)
, 'colors', (SELECT jsonb_agg(color) FROM color_list)
, 'sizes', (SELECT jsonb_agg(size) FROM size_list)
)
)
ps : the first query Global_list could be implemented as a view
The result looks like :
{
"meta": {
"count": 2,
"sizes": [
{
"id": 1,
"name": "Small",
"count": 1
},
{
"id": 2,
"name": "Medium",
"count": 1
}
],
"colors": [
{
"id": 1,
"name": "White",
"count": 1
},
{
"id": 3,
"name": "Blue",
"count": 1
}
],
"countries": [
{
"id": 1,
"name": "Germany",
"count": 1
},
{
"id": 3,
"name": "Albania",
"count": 2
}
],
"next_page": false
},
"result": [
{
"size": "Medium",
"color": "White",
"country": "Albania",
"product_name": "Milk2"
},
{
"size": "Small",
"color": "Blue",
"country": "Albania",
"product_name": "Milk3"
}
]
}
All details in dbfiddle
currently I use this code.
SELECT jsonb_agg(user_data) AS contact_info
FROM (
SELECT jsonb_build_object('user_id', u._id,
'name', u.name,
'mobile', u.mobile,
'profile', CASE WHEN u.profile IS NOT NULL THEN CONCAT ('${process.env.S3_URL}', '', u.profile) ELSE NULL END,
'address_list', jsonb_agg(jsonb_build_object('_id', ua._id,
'address', address,
'lat', lat,
'long', long)
ORDER BY user_id ASC)) AS user_data
FROM users u
LEFT JOIN users_address ua ON ua.user_id = u._id
WHERE ua.user_id = ${contact_id}
AND ua.is_deleted = 0
GROUP BY u._id,
u.name,
u.mobile,
u.profile
) t
Here i use two table > 1. users 2.users_address. contact_id is nothing but a user id which store in users table. and in users_address i also stored a user_id for referrece so i can easily join that both table using user_id.
current output:
"data": {
"name": "abhi",
"mobile": "3256417890",
"profile": "asda",
"user_id": 1,
"address_list": [
{
"_id": 3,
"lat": 23.0031403,
"long": 72.5337234,
"address": "India"
},
{
"_id": 5,
"lat": 23.0031403,
"long": 72.5337234,
"address": "India"
},
{
"_id": 7,
"lat": 23.0031403,
"long": 72.5337234,
"address": "India"
}
]
}
this output is right but whenever i enter contact_id which having null data in users_address table then it throw error.
if no data found then my expected output is :
"data": {
"name": "abhi",
"mobile": "3256417890",
"profile": "asda",
"user_id": 1,
"address_list": []
}
please someone help me to figure out this error. Thank you in adavance.
If you want to do a left join on users_address, you should put all related conditions on the users_address table within the LEFT JOINÂ conditions, instead of in a WHERE:
LEFT JOIN users_address ua ON ua.user_id = u._id
WHERE ua.user_id = ${contact_id}
AND ua.is_deleted = 0
Should be
LEFT JOIN users_address ua ON (ua.user_id = u._id
AND ua.user_id = ${contact_id}
AND ua.is_deleted = 0)
The difference is that the WHERE will apply the conditions on the null cells returned by the LEFT JOIN, so it will remove them.
Also, you don't need the clause
WHERE ua.user_id = ${contact_id}
This is covered by your LEFT JOIN clause already (and it is dangerous to pass raw variables to your SQL string)
How do write a sql query to get at least 2 items for distinct UUIDs
user-table
id name
xxx a
xyx b
zzz e
visitedlocation-table
id startDate userID location
1. 1/2/21 xxx USA
2. 1/3/21 xxx UK
3. 1/2/21 xyx AR
4. 1/3/21 xyx USA
5. 1/5/21 zzz USA
6. 1/6/21 xxx IN
I want to get a list of users with their last two visited locations
Desired output
[
{
id: "xxx",
name: "a",
lastVisits: [
{
id: "6",
startDate: "1/6/21",
location: "IN"
},
{
id: "2",
startDate: "1/3/21",
location: "UK"
}
]
},
{
id: "xyx",
name: "b",
lastVisits: [
{
id: "4",
startDate: "1/3/21",
location: "USA"
},
{
id: "3",
startDate: "1/2/21",
location: "AR"
}
]
},
{
id: "zzz",
name: "b",
lastVisits: [
{
id: "5",
startDate: "1/5/21",
location: "USA"
}
]
}
]
I am using Type Orm and the user entity has a one to many relations with the "visited location" table
repository
.createQueryBuilder('user)
.leftJoinAndSelect(
'user.visitedLocation',
'visitedLocation',
'visitedLocation.userId = user.id'
)
.getRawMany();
I tried using this query but it returns all the visited locations. But I want only the last 2 visited locations.
If it's hard do in query builder please suggest SQL query for this
You can try dense_rank() to rank your rows and only get the last two rows
SELECT userID,startDate,location
FROM
(
SELECT a.id as userID, b.startDate, b.location,
--this will group your rows by user_id and then rank them based on startDate
DENSE_RANK() OVER(PARTITION BY b.userID ORDER BY b.startDate DESC) as
row_rank
FROM user-table a
INNER JOIN visitedlocation-table b
ON (a.id = b.userID)
)T WHERE row_rank <=2 -- fetch only the first two rows
you can take inspiration from the above logic. I'll be posting the JSON based output solution too
Edit
WITH user_visits AS
(
SELECT userID,name,id,startDate,location
FROM
(
SELECT a.id as userID,a.name,b.id, b.startDate, b.location,
--this will group your rows by user_id and then rank them based on startDate
DENSE_RANK() OVER(PARTITION BY b.userID ORDER BY b.startDate DESC) as
row_rank
FROM user_table a
INNER JOIN visitedlocation_table b
ON (a.id = b.userID)
)T WHERE row_rank <=2 -- fetch only the first two rows
)
SELECT jsonb_pretty(array_to_json(array_agg(row_to_json(t)))::jsonb)
FROM(
SELECT userid as id, name,
(
SELECT array_to_json(array_agg(row_to_json(d)))
FROM(
SELECT id,startdate,location
FROM user_visits b
WHERE b.userid = u.userid
)d
) as lastVisits
FROM user_visits u
GROUP BY userid,name
ORDER BY userid
)t;
output of above query
[
{
"id": "xxx",
"name": "a",
"lastvisits": [
{
"id": 6,
"location": "IN",
"startdate": "2021-06-01"
},
{
"id": 2,
"location": "UK",
"startdate": "2021-03-01"
}
]
},
{
"id": "xyz",
"name": "b",
"lastvisits": [
{
"id": 4,
"location": "USA",
"startdate": "2021-03-01"
},
{
"id": 3,
"location": "AR",
"startdate": "2021-02-01"
}
]
},
{
"id": "zzz",
"name": "e",
"lastvisits": [
{
"id": 5,
"location": "USA",
"startdate": "2021-05-01"
}
]
}
]
I am trying to compare the set of two JSON values for every transaction and extract specific values from the below.. I want to extract the following values cCode,dCode,hcps and mod..Can you please guide me on the snowflake SQL syntax for the same.. The first JSON is done by coder and the second json by auditor
1st json
[
{
"cCode": "7832",
"Date": "08/26/2020",
"ID": "511",
"description": "holos",
"dgoses": [
{
"description": "disease",
"dCode": "Y564",
"CodeAllId": "8921",
"messages": [
""
],
"sequenceNumber": 1
},
{
"description": "acute pain",
"dCode": "U3321",
"CodeAllId": "33213",
"messages": [
""
],
"sequenceNumber": 2
},
{
"description": "height",
"dCode": "U1111",
"CodeAllId": "33278",
"messages": [
""
],
"sequenceNumber": 3
},
{
"description": "PIDEMIA ",
"dCode": "H8811",
"CodeAllId": "90000",
"messages": [
""
],
"sequenceNumber": 4
}
],
"familyPlan": "",
"hcpc": 5,
"id": "",
"isEPS": false,
"mod": "67",
"originalUnitAmount": "8888",
"type": "CHARGE",
"unitAmount": "9000",
"vId": "90001"
},
{
"cCode": "900114",
"Date": "08/26/2020",
"ID": "523",
"description": "heart valve",
"dgoses": [
{
"description": "Fever",
"dCode": "J8923",
"CodeAllId": "892138",
"messages": [
""
],
"sequenceNumber": 1
}
],
"familyPlan": "",
"hcpc": 1,
"id": "",
"mod": "26",
"originalUnitAmount": "19039",
"type": "CHARGE",
"unitAmount": "1039",
"vId": "5113"
}
]
2nd JSON
[
{
""cCode"": ""78832"",
""Date"": ""08/26/2020"",
""ID"": ""511"",
""description"": ""holos"",
""dgoses"": [
{
""description"": ""disease"",
""dCode"": ""Y564"",
""CodeAllId"": ""8921"",
""messages"": [
""""
],
""sequenceNumber"": 1
},
{
""description"": ""acute pain"",
""dCode"": ""U3321"",
""CodeAllId"": ""33213"",
""messages"": [
""""
],
""sequenceNumber"": 2
},
{
""description"": ""height"",
""dCode"": ""U41111"",
""CodeAllId"": ""33278"",
""messages"": [
""""
],
""sequenceNumber"": 3
},
{
""description"": ""PIDEMIA "",
""dCode"": ""H8811"",
""CodeAllId"": ""90000"",
""messages"": [
""""
],
""sequenceNumber"": 4
}
],
""familyPlan"": """",
""hcpc"": 8,
""id"": """",
""isEPS"": false,
""mod"": ""67"",
""originalUnitAmount"": ""8888"",
""type"": ""CHARGE"",
""unitAmount"": ""9000"",
""vId"": ""90001""
},
{
""cCode"": ""900114"",
""Date"": ""08/26/2020"",
""ID"": ""523"",
""description"": ""heart valve"",
""dgoses"": [
{
""description"": ""Fever"",
""dCode"": ""J8923"",
""CodeAllId"": ""892138"",
""messages"": [
""""
],
""sequenceNumber"": 1
}
],
""familyPlan"": """",
""hcpc"": 1,
""id"": """",
""mod"": ""126"",
""originalUnitAmount"": ""19039"",
""type"": ""CHARGE"",
""unitAmount"": ""1039"",
""vId"": ""5113""
}
]
And I am looking for a result as the below:
Billid ctextid cCode-Coder cCode-Auditor deletedccode added-ccode dCode-Coder
dCode-Auditor deleted-dcode added-dcode hcpc-coder hcpc-auditor deletedhcpc addedhcpc mod-coder mod-auditor deletedmod addedmod
7111 89321 7832,900114 78832,900114 7832 78832 Y564,U3321,U1111,H8811,J8923 Y564,U3321,U41111,H8811,J8923 U1111 U41111 5,1 8,1 5 8 67,26 67,126 26 126
Can anyone please help me here
sql Tried
with cte4 as
(
select info:dCode as dtcode
from cte3, lateral flatten( input => saveinfo:dgoses )
)
select dCode from cte4, lateral flatten( input => dtcode )
This gives an error straightaway for using :
I have tried the code with the SQL server version but I need to know how to map the JSON functions to the Snowflake SQL version..Can you please help here..
with I as
(
select ,
dense_rank() over (order by Billid, Ctextid) as tid,
dense_rank() over (partition by Billid, Ctextid order by Created) as n
from ##input1
),
D as
(
select I., mk.[key] as mk, m., dk.[key] as dk, d.
from I
cross apply openjson(info) mk
cross apply openjson(mk.value) with
(
cCode nvarchar(max) '$.cCode',
dgoses nvarchar(max) '$.dgoses' as json
) m
cross apply openjson(dgoses) dk
cross apply openjson(dk.value) with
(
dCode nvarchar(max) '$.dCode'
) d
),
C as
(
select * from D where n = 1
),
A as
(
select * from D where n = 2
)
select
Billid,
codedby,
Ctextid,
(
select string_agg(cCode, ',') within group (order by mk)
from
(
select distinct cCode, mk
from C
where tid = t.tid
) d
) as cCodeCoder,
(
select string_agg(cCode, ',') within group (order by mk)
from
(
select distinct cCode, mk
from A
where tid = t.tid
) d
) as cCodeAuditor,
(
select string_agg(cCode, ',')
from
(
select cCode
from C
where tid = t.tid
except
select cCode
from A
where tid = t.tid
) d
) as deletedcCode,
(
select string_agg(cCode, ',')
from
(
select cCode
from A
where tid = t.tid
except
select cCode
from C
where tid = t.tid
) d
) as addedcCode,
(
select string_agg(dCode, ',') within group (order by mk, dk)
from
(
select distinct dCode, mk, dk
from C
where tid = t.tid
) d
) as dCodeCoder,
(
select string_agg(dCode, ',') within group (order by mk, dk)
from
(
select distinct dCode, mk, dk
from A
where tid = t.tid
) d
) as dCodeAuditor,
(
select string_agg(dCode, ',')
from
(
select dCode
from C
where tid = t.tid
except
select dCode
from A
where tid = t.tid
) d
) as deleteddCode,
(
select string_agg(dCode, ',')
from
(
select dCode
from A
where tid = t.tid
except
select dCode
from C
where tid = t.tid
) d
) as addeddCode
from I as t
where n = 1
Thanks,
Arun
I'm not entirely sure how you need the data, but you're trying to get "cCode, dCode, hcps and mod" (assuming hcps is actually hcpc). The problem is cCode, hcpc, and mod are all on the same level of the JSON. dCode is not. It's nested one layer down from the other properties and is a one to many relationship. This could be flattened out to two tables with a 1:MANY relationship, or it could be flattened out in a single table repeating the cCode, hcpc, and mod values. This example shows the second option:
-- I created a table named FOO and added your JSON as a variant
create temp table foo(v variant);
with
JSON(C_CODE, DGOSES, HCPC, "MOD") as
(
select "VALUE":cCode::int as C_CODE
,"VALUE":dgoses as DGOSES
,"VALUE":hcpc::int as HCPS
,"VALUE":mod::int as "MOD"
from foo, lateral flatten(v)
)
select C_CODE, HCPC, "MOD", "VALUE":dCode::string as D_CODE
from JSON, lateral flatten(DGOSES);
This creates a table like this:
C_CODE HCPC MOD D_CODE
7832 5 67 Y564
7832 5 67 U3321
7832 5 67 U1111
7832 5 67 HBB11
900114 1 26 J8923
Following is the query:
SELECT [C].[Id],
[C].[Name],
[Module].[Id],
[Module].[Name]
FROM [dbo].[Category] [C]
INNER JOIN [CategoryModule] [CM]
ON [C].[Id] = [CM].[CategoryId]
CROSS APPLY (SELECT [M].[Id], [M].[Name] FROM [Module] [M]
WHERE [M].[Id] = [CM].[ModuleId]) [Module]
WHERE [C].[Id]IN (1,2)
FOR JSON AUTO
Output:
[
{"Id":1,"Name":"Book","Module":[{"Id":1,"Name":"Unit"}]},
{"Id":2,"Name":"Business","Module":[{"Id":1,"Name":"Unit"}]},
{"Id":1,"Name":"Book","Module":[{"Id":2,"Name":"App"}]}
]
Need:
[
{"Id":1,"Name":"Book","Module":[{"Id":1,"Name":"Unit"},{"Id":2,"Name":"App"}]},
{"Id":2,"Name":"Business","Module":[{"Id":1,"Name":"Unit"}]}
]
It generate separate object for same master table entry.
Hi i think it's possible use FOR JSON AUTO, OPENJSON and JSON_MODIFY
I had the same problem but i finally find a solution
In your case try this
SELECT
JSON_MODIFY (
(SELECT value FROM OPENJSON((SELECT * FROM Category WHERE Id = C.Id FOR JSON AUTO),'$')),
'$.Module',
(SELECT M.Id, M.Name FROM CategoryModule CM INNER JOIN Module M ON CM.ModuleId= M.Id WHERE CM.CategoryId= C.Id FOR JSON AUTO)
) AS Category
FROM Category C
FOR JSON AUTO
The Ouput is
[{
"Category": {
"Id": 1,
"Name": "Book",
"Module": [{
"Id": 1,
"Name": "Unit"
}, {
"Id": 2,
"Name": "App"
}]
}
}, {
"Category": {
"Id": 2,
"Name": "Business",
"Module": [{
"Id": 1,
"Name": "Unit"
}]
}
}]