请问SQL语句中的with tie代表的含义

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了请问SQL语句中的with tie代表的含义相关的知识,希望对你有一定的参考价值。

请问SQL语句Select top <数字> with tie * from <表> 中的with tie代表的含义,若去掉with tie与与原SQL语句在执行效果上有何区别?在哪一本数上提到了with tie代表的含义?

参考技术A 应该是WITH TIES吧?
WITH TIES指定从基本结果集中返回额外的行,对于 ORDER BY 列中指定的排序方式参数,这些额外的返回行的该参数值与 TOP n (PERCENT) 行中的最后一行的该参数值相同。只能在 SELECT 语句中且只有在指定了 ORDER BY 子句之后,才能指定 TOP...WITH TIES。
注意:返回的记录关联顺序是任意的。ORDER BY 不影响此规则。
例如:
“从100万条记录中的得到成绩最高的记录”。通常用:
select top 1 * from student order by score desc
但是如果有几个人分数并列第一,这样就只能取到一个记录。用下面的代码的话,就可以正确地取出分数第一的所有记录:
select top 1 with ties * from student order by score desc本回答被提问者采纳

将“SELECT TOP (1) WITH TIES”转换为 EF Core

【中文标题】将“SELECT TOP (1) WITH TIES”转换为 EF Core【英文标题】:Converting `SELECT TOP (1) WITH TIES` to EF Core 【发布时间】:2021-12-25 19:13:02 【问题描述】:

T-SQL 版本的查询

让我们用一些数据建立一个简单的表格:

DROP TABLE IF EXISTS #OrdersTable

CREATE TABLE #OrdersTable
(
    Id int,
    Custid int
);

INSERT INTO #OrdersTable (Id, Custid) VALUES (1, 71);
INSERT INTO #OrdersTable (Id, Custid) VALUES (2, 71);
INSERT INTO #OrdersTable (Id, Custid) VALUES (3, 71);
INSERT INTO #OrdersTable (Id, Custid) VALUES (4, 72);
INSERT INTO #OrdersTable (Id, Custid) VALUES (5, 72);
INSERT INTO #OrdersTable (Id, Custid) VALUES (6, 72);
INSERT INTO #OrdersTable (Id, Custid) VALUES (7, 73);
INSERT INTO #OrdersTable (Id, Custid) VALUES (8, 74);
INSERT INTO #OrdersTable (Id, Custid) VALUES (9, 74);

在这种情况下,客户 71 和 72 各有 3 个订单。客户 73 有 1 个订单。客户 74 有 2 个订单。

假设我们想了解订单数量最多的客户。

以下查询:

SELECT TOP (1) WITH TIES Custid
FROM #OrdersTable
GROUP BY Custid
ORDER BY COUNT(*) DESC;

结果如下:

Custid
-----------
71
72

(2 rows affected)

到 EF Core 的朴素转换

给定以下类:

public class Order

    public int Id  get; set; 
    public int Custid  get; set; 

以及以下数据:

var OrdersTable = new List<Order>()

    new Order() Id = 1, Custid = 71,
    new Order() Id = 2, Custid = 71,
    new Order() Id = 3, Custid = 71,
    new Order() Id = 4, Custid = 72,
    new Order() Id = 5, Custid = 72,
    new Order() Id = 6, Custid = 72,
    new Order() Id = 7, Custid = 73,
    new Order() Id = 8, Custid = 74,
    new Order() Id = 9, Custid = 74,
;

这是查询到 EF Core 的简单转换:

var n = OrdersTable.GroupBy(order => order.Custid).Select(grouping => grouping.Count()).Max();

var custids = OrdersTable.GroupBy(order => order.Custid).Where(grouping => grouping.Count() == n).Select(grouping => grouping.Key);

使用以下方式显示数据:

foreach (var custid in custids)
    Console.WriteLine(custid);

我们得到:

71
72

问题

让我们将 T-SQL 和 EF Core 版本并排放置。 T-SQL:

SELECT TOP (1) WITH TIES Custid
FROM #OrdersTable
GROUP BY Custid
ORDER BY COUNT(*) DESC;

EF 核心:

var n = OrdersTable.GroupBy(order => order.Custid).Select(grouping => grouping.Count()).Max();

var custids = OrdersTable.GroupBy(order => order.Custid).Where(grouping => grouping.Count() == n).Select(grouping => grouping.Key);

我的问题是,有没有更有效的方法在 EF Core 中实现这个查询?

完整程序

演示上述查询的完整 C# 控制台程序:

using System;
using System.Collections.Generic;
using System.Linq;

namespace EfCoreTop1Ties

    public class Order
    
        public int Id  get; set; 
        public int Custid  get; set; 
    

    internal class Program
    
        static void Main(string[] args)
        
            var OrdersTable = new List<Order>()
            
                new Order() Id = 1, Custid = 71,
                new Order() Id = 2, Custid = 71,
                new Order() Id = 3, Custid = 71,
                new Order() Id = 4, Custid = 72,
                new Order() Id = 5, Custid = 72,
                new Order() Id = 6, Custid = 72,
                new Order() Id = 7, Custid = 73,
                new Order() Id = 8, Custid = 74,
                new Order() Id = 9, Custid = 74,
            ;

            var n = OrdersTable.GroupBy(order => order.Custid).Select(grouping => grouping.Count()).Max();

            var custids = OrdersTable.GroupBy(order => order.Custid).Where(grouping => grouping.Count() == n).Select(grouping => grouping.Key);

            foreach (var custid in custids)
                Console.WriteLine(custid);
        
    

【问题讨论】:

可能值得指出的是,EF 核心可以使用原始 SQL 作为实体集的源,甚至可以在它们之上编写更多查询 【参考方案1】:

您应该能够通过一个查询来做到这一点:

var n = OrdersTable
    .GroupBy(order => order.Custid)
    .Select(grouping => new  CustomerId = grouping.Key, OrderCount = grouping.Count() )
    .OrderByDescending(g => g.OrderCount)
    .ToList();

var maxCount = n.First().OrderCount;
var custIds = n.Where(g => g.OrderCount == maxCount)
    .Select(g => g.CustomerId)
    .ToList();

在 OrdersTable 是 DbContext DBSet 的情况下,这将导致对数据库进行 1 次查询。与该计数匹配的返回项目的检查是在内存中从结果中完成的,无需返回。

如果您正在处理一个特别大的数据集,您可以考虑一些合理的假设,例如,如果有成千上万的客户,那么 100 或 1000 可能会与最大的订单“平局”。

var n = OrdersTable
    .GroupBy(order => order.Custid)
    .Select(grouping => new  CustomerId = grouping.Key, OrderCount = grouping.Count() )
    .OrderByDescending(g => g.OrderCount)
    .Take(100)
    .ToList();

if (n.All(g => g.OrderCount == n.First().OrderCount)
   // Redo query with larger threshold.

如果所有返回的行恰好具有相同的订单计数,它将再次运行查询。您可能希望以不同的方式处理这种情况,例如当所有客户都有 0 个订单时。 (如果您有选择要比较的客户的标准,例如每个城市/州等)

如果要覆盖一个非常大的数据表,另一种选择就是查询最大计数,前提是您的实体配置了导航属性,以便您的客户实体可以与它的订单集合相关:

var maxOrderCount = dbContext.Customers
    .OrderByDescending(x => x.Orders.Count)
    .Select(x => x.Orders.Count)
    .First();

var customers = dbContext.Customers
    .Where(x => x.Orders.Count == maxOrderCount)
    .ToList();

如果您只需要客户 ID,请在 ToList() 之前添加 .Select(x =&gt; x.CustomerId)。它运行两个查询,但它们相当简单,只返回所需的数据,而不是可能返回所有客户 ID/数据。

【讨论】:

很棒的答案。谢谢史蒂夫。

以上是关于请问SQL语句中的with tie代表的含义的主要内容,如果未能解决你的问题,请参考以下文章

SQL with ties的理解与 top 10 with ties

SQL 语句中的With(index(0))

请问一下,那位高手知道数据库语句中 in ,on ,with 等关键字的用法啊,求解.......

SQL With As 用法

SQL Server2008中的MERGE SQL语句中的MERGE的全称是什麼?代表什麼意思? 有没有

sql server with as 能提高性能吗