mafortis
mafortis

Reputation: 7138

SQL count relationship data

I wonder how to add extra data into dataGridView with help of Stored Procedure

Note: This is must probably issue with my SQL query (not sure).

I have following code which return my products data into dataGridView

using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["SampleDatabaseWalkthrough.Properties.Settings.SampleDatabaseConnectionString"].ConnectionString))
{
  if (cn.State == ConnectionState.Closed)
    cn.Open();
  using (DataTable dt = new DataTable())
  {
    using (SqlCommand cmd = new SqlCommand("exec dbo.GetProducts", cn))
    {
      SqlDataAdapter adapter = new SqlDataAdapter(cmd);
      adapter.Fill(dt);
      dataGridViewProducts.DataSource = dt;
      dataGridViewProducts.AutoGenerateColumns = false;
    }
  }
}

And here is my default stored procedure associated to code above:

CREATE PROCEDURE [dbo].[GetProducts]
AS
    begin
    SELECT * from Products
    end

Combined of codes above works 100%. Now I want to add relationship table data into my products query as following:

CREATE PROCEDURE [dbo].[GetProducts]
AS
    begin
    SELECT * from Products p
    Join Serials s ON s.Id = p.Id
    end

This stored procedure above supposed to return data of my products + count of each product serials. (i.e):

Name: Product 1
Origin: Local
Serials: 15 <-- this is count of relationship table

Screenshot:

one

Issue

As you see in my screenshot both my products are receiving serial numbers in column serials BUT only my product Table has serial number, Therefore in serials column of product table it should say 2 and for product Lamp it should say 0

Update

I just noticed that in my query I should get serials like Join Serials s ON s.ProductId = p.Id instead I am getting them like this Join Serials s ON s.Id= p.Id.

BUT the problem with that is this time I'm getting 2 Table and no Lamp product in my dataGridView (as lamp does not have any serial associated with it).

Any suggestion?

Update 2

Serials table schema

CREATE TABLE [dbo].[Serials] (
    [Id]        INT           NOT NULL,
    [ProductId] INT           NOT NULL,
    [Serial]    NVARCHAR (50) NOT NULL,
    [Sold] bit NOT NULL DEFAULT 0,
    PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_Serials_Products] FOREIGN KEY ([ProductId]) REFERENCES [dbo].[Products] ([Id])
);

Upvotes: 1

Views: 56

Answers (2)

Chris Schaller
Chris Schaller

Reputation: 16689

Try this:

SELECT p.*
  ,(SELECT Count(*) FROM Serials s WHERE s.ProductId = p.Id) AS Serials
FROM Products p

When you join onto Serials you end up with one row in the response for each row in the Serials table. There are other ways to achieve the same resultset, but this should be the simplest to understand.


UPDATE:

what I'm trying to do is to count product serials if they are not sold yet (Sold = 0)

To demonstrate different ways to express this, you may be able to extend this concept to your needs:

SELECT p.*
  ,(SELECT Count(*) 
    FROM Serials s 
    WHERE s.ProductId = p.Id
      AND s.Sold = 0) AS SerialsRemaining
FROM Products p

You could add any number of additional columns like this, but the execution time is very inefficient.

We can use a join instead to acheive the same reocrd set, however we must include all the fields in the Products table in the GROUP BY clause for this to work:

In this query SUM is used with a CASE expression, where CASE determines which column to include in the aggregate:

SELECT p.*
   , COUNT(s.Id) AS Total
   , SUM(CASE s.Sold WHEN 1 THEN 1 ELSE 0 END) AS Sold
   , SUM(CASE s.Sold WHEN 0 THEN 1 ELSE 0 END) AS Remaining
FROM Products p
LEFT OUTER JOIN Serials s ON (s.ProductId = p.Id)
GROUP BY p.Id,p.Photo,p.Name,p.Qty,p.Origin,p.[Buy Price],p.[Sell Price],p.SN 

For a final closure, have a look at this fiddle if you want to experiment: http://sqlfiddle.com/#!18/64f32/2

Upvotes: 1

Amit Verma
Amit Verma

Reputation: 2490

try this. Performance of join is always better as compared to subquery.

SELECT P.*, COUNT(s.serail)serialCount
FROM product P
LEFT OUTER JOIN serail S ON (p.id = s.PID)
GROUP BY P.id, P.Name, P.Quantity -- _and all other columns of product table_

Upvotes: 1

Related Questions