Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I do a "FOR JSON" with 2 joins

I can't get this to work properly. I have 4 tables: Products, Suppliers, X_Product_Suppliers and Comments. I want to query them all and put them into JSON using the following query:

WITH Products (Id, Name, Price) As (
    SELECT 1, 'First Product', 10
), Suppliers (Id, Name) As (
    SELECT 1, 'Factory1' UNION ALL
    SELECT 2, 'Factory2'
), Comments (Id, [Text], ProductId) As (
    SELECT 1, 'Good Product', 1 UNION ALL
    SELECT 2, 'Fantastic!'  , 1
), X_Product_Supplier (ProductId, SupplierId) As (
    SELECT 1, 1 UNION ALL
    SELECT 1, 2
)
SELECT Products.*, Suppliers.*, Comments.* FROM Products
LEFT OUTER JOIN X_Product_Supplier ON X_Product_Supplier.ProductId = Products.Id
LEFT OUTER JOIN Suppliers ON X_Product_Supplier.SupplierId = Suppliers.Id
LEFT OUTER JOIN Comments ON Comments.ProductId = Products.Id
FOR JSON AUTO

For some reason sql-server will nest the comments under the supplier instead of under the product:

   {  
      "Id":1,
      "Name":"First Product",
      "Price":"10",
      "Suppliers":[  
         {  
            "Id":1,
            "Name":"Factory1",
            "Comments":[  //THIS SHOULD BE UNDER PRODUCT, NOT SUPPLIER
               {  
                  "Id":1,
                  "Text":"Good Product",
                  "ProductId":1
               },
               {  
                  "Id":2,
                  "Text":"Fantastic!",
                  "ProductId":1
               }
            ]
         },
         {  
            "Id":2,
            "Name":"Factory2",
            "Comments":[  //THIS IS NOW DUPLICATE
               {  
                  "Id":1,
                  "Text":"Good Product",
                  "ProductId":1
               },
               {  
                  "Id":2,
                  "Text":"Fantastic!",
                  "ProductId":1
               }
            ]
         }
      ]
   }

What I actually want is this:

   {  
      "Id":1,
      "Name":"First Product",
      "Price":"10",
      "Suppliers":[  
         {  
            "Id":1,
            "Name":"Factory1"
         },
         {  
            "Id":2,
            "Name":"Factory2"
         }
      ],
      "Comments":[  
               {  
                  "Id":1,
                  "Text":"Good Product",
                  "ProductId":1
               },
               {  
                  "Id":2,
                  "Text":"Fantastic!",
                  "ProductId":1
               }
            ]
   }

How do I do this?

like image 226
Yolofy Avatar asked Mar 29 '17 13:03

Yolofy


People also ask

Can we use two joins in single query?

Multiple joins can be described as a query containing joins of the same or different types used more than once, thus giving them the ability to combine multiple tables.

Which method do we use for joining two tables?

A JOIN clause is used to combine rows from two or more tables, based on a related column between them. Notice that the "CustomerID" column in the "Orders" table refers to the "CustomerID" in the "Customers" table. The relationship between the two tables above is the "CustomerID" column.

How do I JOIN two datasets in SQL?

The simplest way to combine two tables together is using the keywords UNION or UNION ALL. These two methods pile one lot of selected data on top of the other. The difference between the two keywords is that UNION only takes distinct values, but UNION ALL keeps all of the values selected.

How many joins in a query?

SQL Server supports many kinds of different joins including INNER JOIN, SELF JOIN, CROSS JOIN, and OUTER JOIN. In fact, each join type defines the way two tables are related in a query. OUTER JOINS can further be divided into LEFT OUTER JOINS, RIGHT OUTER JOINS, and FULL OUTER JOINS.


2 Answers

If anyone else is looking for answer here is simple query I have written. Change the query as per your schema and it should give your proper structured result.

SELECT Products.*,
(SELECT Suppliers.*
 FROM Suppliers
 WHERE Suppliers.Id = Products.SuppliersId
 FOR JSON AUTO) As Suppliers,
(SELECT Comments.*
 FROM Comments 
 WHERE Comments.ProductId = Products.Id
 FOR JSON AUTO) As Comments
FROM Products
FOR JSON AUTO
like image 170
Muheeb Avatar answered Oct 19 '22 13:10

Muheeb


I know its late, but i faced with same problem but the answers could not help in filtering the null values in where clause, my solution below

SELECT  Products.*, 
        Suppliers.Id as [Suppliers.Id], 
        Suppliers.Name as [Suppliers.Name],
        Comments.Id as [Comments.Id],
        Comments.Text as [Comments.Text],
        Comments.ProductId as [Comments.ProductId] 
FROM Products
LEFT OUTER JOIN X_Product_Supplier ON X_Product_Supplier.ProductId = Products.Id
LEFT OUTER JOIN Suppliers ON X_Product_Supplier.SupplierId = Suppliers.Id
LEFT OUTER JOIN Comments ON Comments.ProductId = Products.Id
FOR JSON PATH 

Tested and working on SQL SERVER 2017

like image 1
Anuroop S Avatar answered Oct 19 '22 13:10

Anuroop S