通过匹配特定条件的某一行排序,然后是其他条件的其他条件?

时间:2014-02-26 21:04:57

标签: sql sql-server

我正在开发一个名为Fablelane的协作式写作网站,人们可以在这里创建故事。现在,系统(当人们创建故事时)检测到故事的语言,并将其保存在数据库中。

在首页(http://fablelane.com)上,有3个“值得关注的故事”。现在,它只选择了3个最高的投票故事,并附有一个简单的ORDER BY条款。

但如果有一个用用户的语言写的故事(让我们只说丹麦语 - da_DK),那么我希望这三个故事中的第一个与用户的语言相匹配,并且其余的2英文。

换句话说:

  • 获得用用户语言编写的最高投票故事。
    • 如果存在,请将其显示为第一个故事。
  • 然后获得3(或如果找到与该语言匹配的最高投票故事,则为2)用英语写的最高投票故事,并显示这些故事。

这有意义吗?如果没有,这里有一些用例。

用例1:访问该网站的丹麦用户,但没有丹麦故事

  • 值得注意的故事#1:用英语写的最高投票故事。
  • 值得注意的故事#2:用英语写的第二高的投票故事。
  • 值得注意的故事#3:用英语写的第三高的投票故事。

用例2:访问该网站的丹麦用户,其中至少有一个丹麦故事

  • 值得注意的故事#1:用丹麦语写的最高票数。
  • 值得注意的故事#2:用英语写的最高票数。
  • 值得注意的故事#3:用英语写的第二高的投票故事。

使用案例3:访问该网站的英语用户

这与用例1 完全相同。


修改1

我们只是说(为了更容易)每个故事的语言都存储在名为VARCHAR(MAX)的{​​{1}}列中,故事的表格称为Language

我获取用户语言的方式是通过ASP .NET MVC中的Story属性。换句话说,它是一个字符串。为了使示例更容易,我们假设它与Request.UserLanguages的{​​{1}}列中的值完全匹配。

3 个答案:

答案 0 :(得分:1)

这是一种做你想做的事情的方法:

select top 3 s.*
from ((select top 1 s.*, 1 as inlang
       from stories s
       where s.lang = @UserLang
       order by votes desc
      ) union all
      (select s.*, 0 as inlang
       from stories s
       where s.lang = 'English'
      )
     ) s
order by inlang desc, votes desc;
但是,我怀疑你没有考虑到所有最高投票的故事都可能都是用户语言的事实。

答案 1 :(得分:1)

在不了解您的架构的情况下......我认为实现这一目标的一种方法可能是生成两个结果集并将它们联合起来并从中获得前3个。它可能不是最好的方式,我确信查询可以更好地编写(并且可能具有更好的性能)。

这样的事情可能是:

// first some sample data
declare @stories table (story varchar(20), lang char(2), votes int)
insert @stories values 
('Story 1', 'DK', 1),('Story 2', 'DK', 3),
('Story 3', 'EN', 4),('Story 4', 'EN', 3),
('Story 5', 'EN', 2),('Story 6', 'EN', 1)

// and the query
select top 3 * from (
    (select top 1 *, 1 as ranking from @stories where lang = 'DK' order by votes desc)
    union
    (select top 3 *, 2 as ranking from @stories where lang = 'EN' order by votes desc)
) x 
order by ranking, votes desc

示例SQL Fiddle

这当然不适合您的具体情况,但它应该让您了解可行的方法。

答案 2 :(得分:0)

在您的订单中添加Case

select top 3 * from
stories
order by case when lang = 'DK' then 1 when lang='ENG' then 2 else 3 end, votes desc

示例SQL Fiddle