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 表中的所有字段才能使其工作:

在此查询中,SUMCASE 表达式一起使用,其中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 统计关系数据的主要内容,如果未能解决你的问题,请参考以下文章

SQL——数据定义

bug统计分析续基于SQL的Bug统计方法

SQL-对同一字段的不同内容项进行统计

sql统计行数,但是需要去重中间的重复数据

sql题 如何统计查询一个月中每天的记录

SQL:查询每门课程的课程名、选课学生姓名及其学号,选课人数