【问题标题】:Why can't TOP be used with SQLDependency?为什么 TOP 不能和 SQLDependency 一起使用?
【发布时间】:2012-09-12 18:16:05
【问题描述】:

我有一个使用 SQLDependency 的应用程序。我想在插入新行时向用户显示插入到数据库表中的最新行。

当我的查询是一个简单的选择语句时,这可以按预期工作,但鉴于我想显示最近插入的行,我将查询编写为 SELECT TOP 语句。这导致了多个异常。在查看this 问题后,我了解到TOP 对 SQLDependency 无效,因此我将不得不寻找其他解决方案。

这让我想知道两件事:

A) SQLDependency 不支持TOP 表达式的原因是什么?

B) 我想出的解决方案是根据 id 对结果进行排序并只显示最后一个。这工作正常,但我的表目前只有很少的行。我正在使用数据集,因此我预计一旦插入更多行,它就会变慢 - 这就是为什么我想将查询限制为仅最近的行。有没有更好的方法来做到这一点?

【问题讨论】:

  • 向他们展示插入的最后一行是否真的是您的目标(即使它是由其他人插入的)?通常您使用现有机制来执行此操作,例如SCOPE_IDENTITY().
  • 是的。这个应用程序所做的只是显示一些其他数据的计数。它使用“临时”表 - 另一个进程以特定间隔更新计数并将新行插入包含更新计数的“临时”表中。由于最后一行总是有最新的计数,这就是我要显示它的原因。
  • 为什么不也(或替代地)用计数更新单行表?
  • 这是我最初的想法,但我们决定保留特定时间计数的历史记录,因此向表中添加新行而不是更新一行。
  • 你可以同时解决这个问题。虽然我不确定为什么这里不支持完全有效的 SQL。

标签: .net sql-server service-broker sqldependency


【解决方案1】:

This article 解释了查询通知技术如何利用索引视图技术,因此它具有相同的限制。为了创建有效的索引视图,必须能够仅从当前更新更新索引,而无需查看表中的任何其他行。如果允许 TOP,那么百万美元的问题是:如果您删除 TOP 中的一行应该由哪一行代替?回答这个问题需要在表中搜索现在应该包含在 TOP 索引视图中的另一行,而不是已删除的行。因此,包含 TOP(或者,同样问题的 MAX 或 MIN)的索引视图不能被有效地维护并且是不允许的。

可以通过查询COUNT_BIG(*) 来检测插入的行。一旦通知您计数已更改,查询新插入的行就很简单了。您还将收到有关 DELETES 的通知(即误报)。

【讨论】:

  • 优秀。正是我想要的!
【解决方案2】:

@Remus Rusanu 解释得很好。您不能对 SQL 命令使用 TOP 关键字。但是,如果你想选择一些TOP 数据,你可以使用下面的替代解决方案。

我正在从数据库中选择所有记录,但我只在我的列表中添加了 10 条记录,并且我正在将此列表返回到我的仪表板。所以,每次我收到最新的十条记录。

您可以在没有TOP 关键字的情况下使用当前的SQL 命令。我的是:

SQL 命令:

Select [Id], [Name] FROM dbo.CUSTOMER where InsertDate = @InsertDate ORDER BY [ID] DESC;

然后,在您的应用程序中,您可以根据您的最高计数填写您的列表。
检查我对以下源代码的评论。

public List<CustomerModel> GetAllCustomer()
        {
            List<CustomerModel> lstCustomerModel = new List<CustomerModel>();
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                conn.Open();
                string InsertDate = string.Empty;
                InsertDate = DateTime.Now.ToString("yyyyMMdd");

                string query = "SELECT [Id] " +
                                    ",[Name] " +
                                "FROM [dbo].[Customer] where InsertDate = " + InsertDate + "   ORDER BY [Id] DESC;";
                SqlCommand cmd = new SqlCommand(query, conn);
                cmd.CommandType = CommandType.Text;
                cmd.Notification = null;
                SqlDependency.Stop(connectionString);
                SqlDependency.Start(connectionString);
                SqlDependency sqlDependency = new SqlDependency(cmd);
                sqlDependency.OnChange += OnDependencyChange;

                using (SqlDataReader reader = cmd.ExecuteReader())
                {
                    if (reader.HasRows)
                    {
                        int counter = 0;
                        while (reader.Read())
                        {
                            if (counter == 10) /* Here, I am reading just first ten record. After 10 records, I am not filling my List. So, It is kind of top 10 records.. Alternative solution.*/
                                break;
                            counter++;
                            
                            lstCustomerModel.Add(new CustomerModel
                            {
                               Id = Convert.ToInt32(reader.GetValue("Id")),
                               Name = WeightUnit = reader.GetValue("Name")
                            });

                            //break;
                        }
                    }
                }
            }

            return lstCustomerModel;
        }

        private void OnDependencyChange(object sender, SqlNotificationEventArgs e)
        {
            if (e.Type == SqlNotificationType.Change)
            {
                _context.Clients.All.SendAsync("refreshCustomers");
            }
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-20
    • 2020-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-23
    • 1970-01-01
    相关资源
    最近更新 更多