SQL 统计关系数据
Posted
技术标签:
【中文标题】SQL 统计关系数据【英文标题】:SQL count relationship data 【发布时间】:2021-10-01 16:33:03 【问题描述】:我想知道如何在存储过程的帮助下将额外的数据添加到dataGridView
注意:这可能是我的 SQL 查询的问题(不确定)。
我有以下代码将我的产品数据返回到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;
这是我与上述代码关联的默认存储过程:
CREATE PROCEDURE [dbo].[GetProducts]
AS
begin
SELECT * from Products
end
以上代码的组合 100% 有效。现在我想将关系表数据添加到我的产品查询中,如下所示:
CREATE PROCEDURE [dbo].[GetProducts]
AS
begin
SELECT * from Products p
Join Serials s ON s.Id = p.Id
end
上面的这个存储过程应该返回我的产品数据+每个产品序列的计数。 (即):
Name: Product 1
Origin: Local
Serials: 15 <-- this is count of relationship table
截图:
问题
正如您在我的屏幕截图中看到的,我的两个产品都在serials
列中收到序列号但是只有我的产品Table
有序列号,因此在产品表的serials
列中应该说2
,对于产品Lamp
,应该说0
更新
我刚刚注意到,在我的查询中,我应该得到像 Join Serials s ON s.ProductId = p.Id
这样的连续剧,而不是像 Join Serials s ON s.Id= p.Id
这样得到它们。
但问题是这次我在dataGridView
中获得了 2 个 Table 和没有 Lamp 产品(因为 Lamp 没有与之关联的任何序列号)。
有什么建议吗?
更新 2
序列表架构
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])
);
【问题讨论】:
在查询中尝试使用 Left out join。如果您需要帮助,请分享示例数据和预期结果。 @AmitVerma 它说out
部分语法不正确
它是左外连接
@AmitVerma 和 left join
我得到以下结果(截图)ibb.co/KXFrvZJ
这意味着序列表有 2 行相同的产品 ID。现在你必须根据业务逻辑来决定如何处理。我再说一遍,分享样本数据和预期结果。
【参考方案1】:
试试这个:
SELECT p.*
,(SELECT Count(*) FROM Serials s WHERE s.ProductId = p.Id) AS Serials
FROM Products p
当您加入Serials
时,您最终会在Serials
表中的每一行的响应中得到一行。
还有其他方法可以实现相同的结果集,但这应该是最容易理解的。
更新:
我正在尝试做的是计算尚未售出的产品序列号(Sold = 0)
为了演示表达这一点的不同方式,您可以将此概念扩展到您的需要:
SELECT p.*
,(SELECT Count(*)
FROM Serials s
WHERE s.ProductId = p.Id
AND s.Sold = 0) AS SerialsRemaining
FROM Products p
您可以像这样添加任意数量的附加列,但执行时间非常低效。
我们可以使用连接来实现相同的记录集,但是我们必须在GROUP BY
子句中包含Products
表中的所有字段才能使其工作:
在此查询中,
SUM
与CASE
表达式一起使用,其中CASE
确定要包含在聚合中的列:
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
对于最终的关闭,如果您想进行实验,请查看这个小提琴:http://sqlfiddle.com/#!18/64f32/2
【讨论】:
谢谢,只要它必须像WHERE s.ProductId = p.Id
那样才能正常工作。
很公平,这就解释了为什么您的屏幕截图有 2 条而不是 15 条记录。
是的,我在更新部分提到过这个错误:),这个查询中是否可能有 2 个 where 条件?
当然可以,但是您确实应该发布您的表架构供我们明确引用。 @amit 的答案显示了如何使用 join 和 group by 来做同样的事情。您在条件中需要的附加字段是什么?
@mafortis 我添加了一个你可以试验的小提琴:sqlfiddle.com/#!18/64f32/2【参考方案2】:
试试这个。与子查询相比,连接的性能总是更好。
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_
【讨论】:
以上是关于SQL 统计关系数据的主要内容,如果未能解决你的问题,请参考以下文章