Reputation: 7138
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:
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?
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
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.
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 aCASE
expression, whereCASE
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
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