Reputation: 67
Edit: FYI. So my PrimaryImage is actually an int and is used as a foreign key to my Images table. I just wanted to explain that so it is clear why I set it to on f.PrimaryImage = i.Id
. For some reason all my rows are getting populated with every i.Id, i.EntityId, i.ImageTypeId, & i.ImageUrl instead of just where my f.PrimaryImage = i.Id.
I am writing a SQL stored procedure to SELECT ALL and I want to combine my last 4 columns Id, EntityId, ImageTypeId, ImageUrl
into one new column PrimaryImage
as a single JSON object. I was able to successfully do that with my Skills column but for that I needed it as an array that holds JSON objects so simply using "FOR JSON AUTO"
took care of that. But like I said for PrimaryImage
, I need that as a single JSON object that contains my Id, EntityId, ImageTypeId, & ImageUrl
. I included a picture of my result after executing this proc and right below my table I drew a representation of what I want the column to look like. Just to clarify I have four tables my Friends, FriendSkills, Skills, & Images tables which I've used join statements organize accordingly. Basically my schema needs to look like this:
{
"id": 0000,
"userId": "String"
"bio": "String",
"title": "String",
"summary": "String",
"headline": "String",
"statusId": "String",
"slug": "String",
"skills": [{id: 0, name: "String"},{id: 0, name: "String"}],
"primaryImage": {
"id": 0,
"entityId": 0,
"imageTypeId": 0,
"imageUrl": "String"
}
}
Here is my stored procedure
ALTER PROC [dbo].[Friends_SelectAllV2]
AS
/* --- Test Proc ------
Execute dbo.Friends_SelectAllV2
*/
BEGIN
Select f.Id
,f.UserId
,f.DateAdded
,f.DateModified
,f.Title
,f.Bio
,f.Summary
,f.Headline
,f.Slug
,f.StatusId
,Skills = ( SELECT s.Id,
s.Name
From dbo.Skills as s inner join dbo.FriendSkills fs
on s.Id = fs.SkillId
Where f.Id = fs.FriendId
FOR JSON AUTO
),
PrimaryImage = (SELECT i.Id,
i.EntityId,
i.ImageTypeId,
i.ImageUrl
From dbo.Friends f left join dbo.Images as i
on f.PrimaryImage = i.Id
Where f.PrimaryImage = i.Id
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
)
END
Upvotes: 4
Views: 5241
Reputation: 71578
You don't actually need another subquery if the inner property is a single object, you can use FOR JSON PATH
with explicit path syntax.
Select f.Id
,f.UserId
,f.DateAdded
,f.DateModified
,f.Title
,f.Bio
,f.Summary
,f.Headline
,f.Slug
,f.StatusId
,Skills = ( SELECT s.Id,
s.Name
From dbo.Skills as s inner join dbo.FriendSkills fs
on s.Id = fs.SkillId
Where f.Id = fs.FriendId
FOR JSON AUTO
),
i.Id AS [PrimaryImage.Id],
i.EntityId AS [PrimaryImage.EntityId],
i.ImageTypeId AS [PrimaryImage.ImageTypeId],
i.ImageUrl AS [PrimaryImage.ImageUrl]
From dbo.Friends f
left join dbo.Images as i on f.PrimaryImage = i.Id
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER;
If however there are multiple images, and you need a subquery, the issue here is that you are putting the whole Friends
table in again, instead of correlating the outside table. You would also remove WITHOUT_ARRAY_WRAPPER
.
Select f.Id
,f.UserId
,f.DateAdded
,f.DateModified
,f.Title
,f.Bio
,f.Summary
,f.Headline
,f.Slug
,f.StatusId
,Skills = ( SELECT s.Id,
s.Name
From dbo.Skills as s inner join dbo.FriendSkills fs
on s.Id = fs.SkillId
Where f.Id = fs.FriendId
FOR JSON AUTO
),
PrimaryImage = (SELECT i.Id,
i.EntityId,
i.ImageTypeId,
i.ImageUrl
FROM dbo.Images as i
WHERE f.PrimaryImage = i.Id
FOR JSON PATH
)
From dbo.Friends f
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER;
Upvotes: 3