[翻译]  How to select the top n from a union of two queries where the resulting order needs to be ranked by individual query?

[CHINESE]  如何从两个查询的并集中选择前n个,其中生成的顺序需要按个别查询排序?


Let's say I have a table with usernames:

假设我有一个包含用户名的表:

Id  |  Name
-----------
1   |  Bobby
20  |  Bob
90  |  Bob
100 |  Joe-Bob
630 |  Bobberino
820 |  Bob Junior

I want to return a list of n matches on name for 'Bob' where the resulting set first contains exact matches followed by similar matches.

我想在'Bob'的名称上返回n个匹配项的列表,其中结果集首先包含完全匹配,然后是类似的匹配。

I thought something like this might work

我觉得这样的事情可能有用

SELECT TOP 4 a.* FROM
(
    SELECT * from Usernames WHERE Name = 'Bob'
    UNION
    SELECT * from Usernames WHERE Name LIKE '%Bob%'
) AS a

but there are two problems:

但有两个问题:

  1. It's an inefficient query since the sub-select could return many rows (looking at the execution plan shows a join happening before top)
  2. 这是一个效率低下的查询,因为子选择可以返回许多行(查看执行计划显示在顶部之前发生的连接)
  3. (Almost) more importantly, the exact match(es) will not appear first in the results since the resulting set appears to be ordered by primary key.
  4. (几乎)更重要的是,完全匹配不会首先出现在结果中,因为结果集似乎是按主键排序的。

I am looking for a query that will return (for TOP 4)

我正在寻找一个将返回的查询(对于TOP 4)

Id | Name
---------
20 | Bob
90 | Bob

(and then 2 results from the LIKE query, e.g. 1 Bobby and 100 Joe-Bob)

Is this possible in a single query?

这可能在一个查询中吗?

6 个解决方案

#1


14  

You could use a case to place the exact matches on top:

您可以使用案例将完全匹配放在最上面:

select  top 4 *
from    Usernames
where   Name like '%Bob%'
order by
        case when Name = 'Bob' then 1 else 2 end

Or, if you're worried about performance and have an index on (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

#2


3  

A slight modification to your original query should solve this. You could add in an additional UNION that matches WHERE Name LIKE 'Bob%' and give this priority 2, changing the '%Bob' priority to 3 and you'd get an even better search IMHO.

对原始查询稍作修改即可解决此问题。你可以添加一个额外的UNION,它匹配WHERE Name LIKE'Bob%'并给予这个优先级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

#3


1  

This might do what you want with better performance.

这可能会以更好的性能做到你想要的。

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

#4


1  

This works for me:

这对我有用:

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

#5


1  

SET ROWCOUNT 4

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

SET ROWCOUNt 0

#6


0  

The answer from Will A got me over the line, but I'd like to add a quick note, that if you're trying to do the same thing and incorporate "FOR XML PATH", you need to write it slightly differently.

Will A的回答让我超越了界限,但我想补充一点,如果你想尝试做同样的事情并加入“FOR XML PATH”,你需要稍微改写一下。

I was specifying XML attributes and so had things like :

我正在指定XML属性,所以有这样的事情:

SELECT Field_1 as [@attr_1]

What you have to do is remove the "@" symbol in the sub queries and then add them back in with the outer query. Like this:

您要做的是删除子查询中的“@”符号,然后使用外部查询将其添加回来。喜欢这个:

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')

This is a cut-down version of my final query, so it doesn't really make sense, but you should get the idea.

这是我最终查询的简化版本,因此它没有用,但你应该明白这一点。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2018 ITdaan.com 粤ICP备14056181号