如何从两个查询的联合中选择前n个,需要根据单个查询对结果顺序进行排序?

| 假设我有一个包含用户名的表:
Id  |  Name
-----------
1   |  Bobby
20  |  Bob
90  |  Bob
100 |  Joe-Bob
630 |  Bobberino
820 |  Bob Junior
我想返回名称为\'Bob \'的
n
个匹配项的列表,其中结果集首先包含完全匹配项,然后是相似的匹配项。 我以为这样的事情可能有用
SELECT TOP 4 a.* FROM
(
    SELECT * from Usernames WHERE Name = \'Bob\'
    UNION
    SELECT * from Usernames WHERE Name LIKE \'%Bob%\'
) AS a
但是有两个问题: 这是一个效率低下的查询,因为子选择可能返回许多行(查看执行计划显示联接发生在顶部之前) (几乎)更重要的是,由于结果集似乎按主键排序,因此精确匹配将不会首先出现在结果中。 我正在寻找将返回的查询(针对TOP 4)
Id | Name
---------
20 | Bob
90 | Bob

(and then 2 results from the LIKE query, e.g. 1 Bobby and 100 Joe-Bob)
在单个查询中有可能吗?     
已邀请:
您可以使用
case
将精确匹配项放在顶部:
select  top 4 *
from    Usernames
where   Name like \'%Bob%\'
order by
        case when Name = \'Bob\' then 1 else 2 end
或者,如果您担心性能并在
(Name)
上建立索引:
select  top 4 *
from    (
        select  1 as SortOrder
        ,       *
        from    Usernames
        where   Name = \'Bob\'
        union all
        select  2
        ,       *
        from    Usernames
        where   Name like  \'%Bob%\'
                and Name <> \'Bob\'
                and 4 >
                (
                select  count(*)
                from    Usernames
                where   Name = \'Bob\'
                )
        ) as SubqueryAlias
order by
        SortOrder
    
稍作修改即可解决此问题。您可以添加一个与
WHERE Name LIKE \'Bob%\'
匹配的附加UNION,并将此优先级设置为2,将
\'%Bob\'
优先级更改为3,这样您将获得更好的搜索恕我直言。
SELECT TOP 4 a.* FROM
(
    SELECT *, 1 AS Priority from Usernames WHERE Name = \'Bob\'
    UNION
    SELECT *, 2 from Usernames WHERE Name LIKE \'%Bob%\'
) AS a
ORDER BY Priority ASC
    
这对我有用:
SELECT TOP 4 * FROM (
SELECT 1 as Rank , I, name  FROM Foo  WHERE Name = \'Bob\' 
UNION ALL
SELECT 2 as Rank,i,name  FROM Foo  WHERE Name LIKE \'%Bob%\' 
) as Q1
ORDER BY Q1.Rank, Q1.I
    
SET ROWCOUNT 4

SELECT * from Usernames WHERE Name = \'Bob\'
UNION
SELECT * from Usernames WHERE Name LIKE \'%Bob%\'

SET ROWCOUNt 0
    
这可能会实现您想要的更好的性能。
SELECT TOP 4 a.* FROM
(
    SELECT TOP 4 *, 1 AS Sort from Usernames WHERE Name = \'Bob\'
    UNION ALL
    SELECT TOP 4 *, 2 AS Sort from Usernames WHERE Name LIKE \'%Bob%\' and Name <> \'Bob\'
) AS a
ORDER BY Sort
    
来自Will A的答案使我很困惑,但是我想补充一下,如果您尝试做相同的事情并合并“ FOR XML PATH”,则需要编写它略有不同。 我正在指定XML属性,所以有类似以下内容:
SELECT Field_1 as [@attr_1]
您要做的是删除子查询中的\“ @ \”符号,然后将其与外部查询一起添加回去。像这样:
SELECT top 1 a.SupervisorName as [@SupervisorName]
FROM
(
    SELECT (FirstNames + \' \' + LastName) AS [SupervisorName],1 as OrderingVal
    FROM ExamSupervisor SupervisorTable1

    UNION ALL

    SELECT (FirstNames + \' \' + LastName) AS [SupervisorName],2 as OrderingVal
    FROM ExamSupervisor SupervisorTable2

) as a
ORDER BY a.OrderingVal ASC
FOR XML PATH(\'Supervisor\')
这是我最终查询的简化版本,因此它没有任何意义,但是您应该明白这一点。     

要回复问题请先登录注册