I have the following tables (many-to-many):
DROP TABLE IF EXISTS [dbo].[ItemOwner], [dbo].[Items], [dbo].[Owners]
GO
CREATE TABLE [dbo].[Items]
(
[Id] [int] IDENTITY(1,1) PRIMARY KEY CLUSTERED,
[Name] [varchar](max) NOT NULL
);
CREATE TABLE [dbo].[Owners]
(
[Id] [int] IDENTITY(1,1) PRIMARY KEY CLUSTERED,
[Name] [varchar](max) NOT NULL
);
CREATE TABLE [dbo].[ItemOwner]
(
[ItemId] [int] NOT NULL REFERENCES [dbo].[Items]([Id]),
[Ownerd] [int] NOT NULL REFERENCES [dbo].[Owners]([Id]),
UNIQUE([ItemId], [Ownerd])
);
INSERT INTO [dbo].[Items] ([Name])
VALUES ('item 1'), ('item 2'), ('item 3');;
INSERT INTO [dbo].[Owners] ([Name])
VALUES ('owner 1'), ('owner 2');
INSERT INTO [dbo].[ItemOwner]
VALUES (1, 1), (1, 2), -- the item is owned by two owners
(2, 1), (2, 2), -- the item is owned by two owners
(3, 1); -- the item is owned by one owner
So if I do:
SELECT DISTINCT
STRING_AGG([Ownerd], ', ')
FROM
[dbo].[ItemOwner]
GROUP BY
[ItemId]
I get all permutations of owners. I want these permutations at the top level objects and aggregate the items to it.
How can I get a JSON in SQL Server which looks like this:
[
{
"owners": [
{
"id": 1,
"name": "owner 1"
},
{
"id": 2,
"name": "owner 2"
}
],
"own": [
{
"id": 1,
"name": "item 1"
},
{
"id": 2,
"name": "item 2"
}
]
},
{
"owners": [
{
"id": 1,
"name": "owner 1"
}
],
"own": [
{
"id": 3,
"name": "3"
}
]
}
]
I tried a lot of things – I have no clue how to combine a GROUP BY
with an proper aggregate function. SQL Server 2019 (so no JSON_ARRAYAGG?)
2
Answers
You can use
FOR JSON PATH
like:Here are the Microsoft docs
What you are looking for is a way to get distinct groups of identical owner/item sets. To do this, you need to group up not just the distinct
OwnerId
by theItemId
, you also need to group that by the newDistinctOwners
list and get the grouped upDistinctItems
.Then you can use
OPENJSON
to crack that back open and join back to the parent tables.Unfortunately, SQL Server does not support
JSON_AGG
yet, otherwise this would have been simpler. Instead we need to useSTRING_AGG
and concat the[]
to it.db<>fiddle