简体   繁体   English

SQL - 返回具有最多列匹配的行

[英]SQL - Return rows with most column matches

Consider this table:考虑这张表:

Name   Color1    Color2    Color3   Prize
-----------------------------------------
Bob    Red       Blue      Green    Stapler
Bob    Red       Blue      NA       Pencil
Bob    Red       NA        NA       Lamp
Bob    Red       NA        NA       Chair
Bob    NA        NA        NA       Mouse Pad

Bob has 3 colors. This is what I'm trying to get: Bob 有 3 个 colors。这就是我想要得到的:

(#1) If Bob has Red, Blue, Green (match 3) ....  Return Stapler
(#2) If Bob has Red, Blue, Purple (match 2) ...  Return Pencil
(#3) If Bob has Red, Orange, Purple (match 1) .  Return Lamp AND Chair rows
(#4) If Bob has Brown, Pink, Black (match 0) ..  Return Mouse Pad

Colors would only appear in their own Columns. Colors 只会出现在他们自己的专栏中。 So in the example above, Red would only be in Color1 column and never in Color2 or Color3.所以在上面的例子中,红色只会出现在 Color1 列中,而不会出现在 Color2 或 Color3 中。 Black would only be in Color3 and never in Color1 or Color2.黑色只会出现在 Color3 中,而不会出现在 Color1 或 Color2 中。 Etc... ETC...

I only want the row(s) with the most matches.我只想要匹配次数最多的行。

I would really prefer not to do this with 4 separate SELECT statements and check each time if they return a row.我真的不想用 4 个单独的 SELECT 语句来执行此操作,并且每次都检查它们是否返回一行。 This is how I do it in a stored procedure and it's clunky.这就是我在存储过程中执行此操作的方式,而且很笨重。

How can I do this in 1 SQL statement?我如何在 1 SQL 语句中执行此操作? Using Oracle if that matters...如果重要,请使用 Oracle...

Thanks!!!谢谢!!!

7 Years later, I think I'll answer my question with what I came up with. 7 年后,我想我会用我的想法来回答我的问题。 Thanks to Ponder Stibbons for his answer to get me started.感谢 Ponder Stibbons 的回答让我开始。 Posting here in case anyone else stumbles upon this.在这里张贴以防其他人偶然发现这一点。

Ponder's answer will return multiple rows. Ponder 的答案将返回多行。 For example, if you match on Red and Blue, it will return both Stapler and Pencil.例如,如果您匹配红色和蓝色,它将同时返回 Stapler 和 Pencil。 Only Pencil should be returned.只应归还铅笔。

So, in my solution, exact matches get 2 points for the ranking and "NA" for the column gets you 1. This bumps up the NA rows and creates "catch all" scenarios for the non-matching columns, which was my intent.因此,在我的解决方案中,完全匹配的排名获得 2 分,列的“NA”获得 1 分。这会增加 NA 行并为不匹配的列创建“捕获所有”场景,这是我的意图。

select *
  from (
    select t.*, rank() over (order by 
          decode(color1, 'Red', 2, 0) 
        + decode(color2, 'Blue', 2, 0) 
        + decode(color3, 'Purple', 2, 0) 
        + decode(color1, 'NA', 1, 0) 
        + decode(color2, 'NA', 1, 0) 
        + decode(color3, 'NA', 1, 0)         
         desc) rnk
      from t
      where t.name = 'Bob'
  )
  where rnk = 1
  

You can count the matches using case and then fetch the row with the most. 您可以使用case来计算匹配项,然后获取最多的行。 In Oracle, this uses a few subqueries: 在Oracle中,这使用了一些子查询:

select name
from (select t.*
      from (select t.*,
                   ((case when color1 in ('Red', 'Blue', 'Green') then 1 else 0 end) +
                    (case when color2 in ('Red', 'Blue', 'Green') then 1 else 0 end) +
                    (case when color3 in ('Red', 'Blue', 'Green') then 1 else 0 end) +
                   ) as numMatches
            from table t
           ) t
      order by nummatches desc
     ) t
where rownum = 1;

I only want the row(s) with the most matches. 我只想要匹配次数最多的行。

You can use function rank() for that: 您可以为此使用函数rank():

SQLFiddle SQLFiddle

select name, color1, color2, color3, prize 
  from (
    select t.*, rank() over (order by decode(color1, 'Red', 1, 0) 
        + decode(color2, 'Blue', 1, 0) + decode(color3, 'Green', 1, 0) desc) rnk
      from t)
  where rnk = 1

This returns row or rows with most matches. 这将返回匹配最多的行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM