【问题标题】:Match SQL Columns based on user input根据用户输入匹配 SQL 列
【发布时间】:2011-01-24 14:28:20
【问题描述】:

这是我在这个论坛上的第一篇文章,我当然希望得到大师的帮助:)

我想要实现的是我的 db 表中有 7 列。一个是主键,其余 6 个是整数列。现在我的应用程序将允许用户输入 6 个值。我想将用户输入的 6 个值与这 6 个整数列进行比较,如果任何行中的 3 列或更多列与用户输入的匹配,则返回该表的主键..

我尝试过使用查询、游标、嵌套循环,但我仍然无法达到我的结果..

任何帮助将不胜感激!

谢谢

更新

数据库表结构.. 我正在输入2,3,7,11,45,65。返回的行数应为 5。例如..

UID A1 A2 A3 A4 A5 A6
-----------------------
1   2  3  4  5  6  7
2   2  3  4  55 56 57
3   65 11 45 66 67 68
4   45 7  11 99 98 97
5   7  7  7  7  7  7
6   7  7  7  7  7  7
7   8  8  8  8  8  8
8   8  8  8  8  8  8
9   45 45 0  3  1  2
10  65 7  4  0  0  0

返回的 ID 应为 1,3,4,9,10

【问题讨论】:

  • 你是如何生成主键的?
  • 重要问题:您是在尝试将输入匹配到相应的列(组合锁)还是任何输入都可以匹配任何列?换句话说,1,2,3,4,5,6 匹配 6,5,4,7,7,7 是 3 次还是 0 次?另外,是否允许重复数字或者这更像是基诺问题?
  • 任何输入都可以匹配数据库中的任何列..
  • 您只输入了 5 个数字。你错过了一个吗?这将有助于理解您的回答以查看所有数据。另外,我假设您不想匹配多个匹配项。我的意思是,如果用户在他的 6 个号码中输入 7 一次,您只想匹配 UID 5 和 6 一次,而不是 6 次,对吗?如果用户输入 2,2,2,2,2,2 会怎样?您是否只想与任何个人 2 匹配一次,因此第 1 行和第 2 行不会成功?
  • 嗨 nycdan.. 不,你错了.. 上面给出了 db 表.. 假设我在查询中将 2,3,45,7,11,65 作为 6 个值发送..现在,如果您看到 db 表,那么它应该返回 uid 1,3,4,9,10.. 原因?他们都有至少 3 个输入的数字。不应提取 777777 行.. 因为它只包含一个数字 7 6 次而不是 3 个不同的列.. 你明白了吗?

标签: c# asp.net sql-server vb.net


【解决方案1】:

虚拟数据(来自 MSDN PIVOT 示例)

CREATE TABLE Mytable (PK int, col1 int, col2 int, col3 int, col4 int, col5 int, col6 int)
GO
INSERT INTO Mytable VALUES (1, 1,4,3,5,4,4)
INSERT INTO Mytable VALUES (2, 2,4,1,5,5,5)
INSERT INTO Mytable VALUES (3, 3,4,3,5,4,4)
INSERT INTO Mytable VALUES (4, 4,4,2,5,5,4)
INSERT INTO Mytable VALUES (5, 5,5,1,5,5,5)
GO

输入数据

DECLARE @MyInput TABLE (InputValue int)
INSERT @MyInput VALUES (2)
INSERT @MyInput VALUES (4)
INSERT @MyInput VALUES (5)

UNPIVOT 将源列数据转换为行。现在我们可以 JOIN 和聚合来查找我们有 3 个匹配项的位置,而无需大量的 OR 子句

SELECT
    *
FROM
    myTable MT2 --effectively PIVOT back to get original rows
    JOIN
    (
    SELECT
        PK
    FROM --7 columns into 3, make column name a row identifier
        (SELECT PK, col1, col2, col3, col4, col5, col6 FROM myTable) MT
        UNPIVOT
        (colvalue FOR RowNumber IN (col1, col2, col3, col4, col5, col6)) cols
        JOIN   --match to user input, set based
        @MyInput MD ON cols.colvalue = MD.InputValue
    GROUP BY
        PK  --per original row
    HAVING 
        COUNT(DISTINCT MD.InputValue) >= 3
    ) foo ON MT2.PK = foo.PK

这适用于第 2、4、5 组和第 1、4、5 组

【讨论】:

    【解决方案2】:

    您可以遍历这些值并将 1 添加到满足比较条件的每一列的变量中。

    类似这样的:

    DECLARE @Accumulator int
    DECLARE @Threshold int
    DECLARE @ReturnValue int
    
    DECLARE @PK int
    DECLARE @Col1 int
    DECLARE @Col2 int
    DECLARE @Col3 int
    DECLARE @Col4 int
    DECLARE @Col5 int
    DECLARE @Col6 int
    
    DECLARE @UserInput1 int
    DECLARE @UserInput2 int
    DECLARE @UserInput3 int
    DECLARE @UserInput4 int
    DECLARE @UserInput5 int
    DECLARE @UserInput6 int
    
    -- Assuming you would set each @UserInputx above to a value input by the user...
    
    SET @Accumulator = 0
    SET @Threshold = 3
    SET @ReturnValue = 0
    
    SELECT
        @PK = PrimaryKey,
        @Col1 = Col1,
        @Col2 = Col2,
        @Col3 = Col3,
        @Col4 = Col4,
        @Col5 = Col5,
        @Col6 = Col6
    FROM TheTable
    
    IF @Col1 IN (@UserInput1, @UserInput2, @UserInput3, @UserInput4, @UserInput5, @UserInput6) 
        SET @Accumulator = @Accumulator + 1
    
    IF @Col2 IN (@UserInput1, @UserInput2, @UserInput3, @UserInput4, @UserInput5, @UserInput6) 
        SET @Accumulator = @Accumulator + 1
    
    IF @Col3 IN (@UserInput1, @UserInput2, @UserInput3, @UserInput4, @UserInput5, @UserInput6) 
        SET @Accumulator = @Accumulator + 1
    
    IF @Col4 IN (@UserInput1, @UserInput2, @UserInput3, @UserInput4, @UserInput5, @UserInput6) 
        SET @Accumulator = @Accumulator + 1
    
    IF @Col5 IN (@UserInput1, @UserInput2, @UserInput3, @UserInput4, @UserInput5, @UserInput6) 
        SET @Accumulator = @Accumulator + 1
    
    IF @Col6 IN (@UserInput1, @UserInput2, @UserInput3, @UserInput4, @UserInput5, @UserInput6) 
        SET @Accumulator = @Accumulator + 1
    
    IF @Accumulator >= 3
        SET @ReturnValue = @PK
    

    【讨论】:

      【解决方案3】:

      我认为这将是最容易实现的

      SELECT ID
      
      from TABLE
      
      WHERE 
      
      CASE WHEN integerCol1 IN 
      (@user1,@user2,@user3,@user4,@user5,@user6) THEN 1 ELSE 0 END +
      CASE WHEN integerCol2 IN 
      (@user1,@user2,@user3,@user4,@user5,@user6) THEN 1 ELSE 0 END +
      CASE WHEN integerCol3 IN 
      (@user1,@user2,@user3,@user4,@user5,@user6) THEN 1 ELSE 0 END +
      CASE WHEN integerCol4 IN 
      (@user1,@user2,@user3,@user4,@user5,@user6) THEN 1 ELSE 0 END +
      CASE WHEN integerCol5 IN 
      (@user1,@user2,@user3,@user4,@user5,@user6) THEN 1 ELSE 0 END +
      CASE WHEN integerCol6 IN 
      (@user1,@user2,@user3,@user4,@user5,@user6) THEN 1 ELSE 0 END >=3
      

      【讨论】:

      • El Ronnoco,我厌倦了使用你的 sql 查询,它返回错误。它甚至返回在所有 6 列中具有相同字符的行.. 它错过了应该返回的 2 列
      • @user587619 啊,是的,我的错误。它只关心 3 列是否有任何用户输入。它不检查三列是否唯一......嗯......
      • @user587619 但是我不知道为什么它会返回应该返回的行?...
      【解决方案4】:

      我没有时间编写代码,但您提到您尝试了嵌套循环。既然我了解了您想要做什么,我至少可以向您推荐一个我认为对您有用的方向。

      在您的内部循环中,您将获取要与输入进行比较的第一个列表,然后获取您的第一个输入并将其与列表中的每个成员进行比较,直到匹配或结束。现在棘手的部分...因为您不想将输入的第二个数字与列表的同一成员匹配两次(例如,如果您输入 2 7s),您应该将匹配的成员更改为某个非法数字.如果只允许正数,请将其更改为 -1。这样可以确保您不会匹配两次。

      现在在我们的中间循环中,根据同一个列表处理其余输入数字,直到完成。为了确定匹配,计算该列表中 -1(或任何你用来表示匹配的)的出现次数,你将获得成功/失败指示器。

      在您的外部循环中,以相同的方式遍历每个列表。

      在非常粗略的伪代码中:

      var x = set of all lists  
      foreach (list l in x)  //go through each list
      {  
       foreach (item i in inputlist)  //go through each item in your input
        {
          foreach (item j in l) //compare to each item in the current list
            {
               if (i = j) 
                 {
                    j = -1;  //set matched item to -1 to avoid rematching
                    sum[l]++;
                 }
            }
        }
      }
      

      当完成时,任何 sum[l] >=3 的列表都是匹配的。

      【讨论】:

      • 有点像你的方法:)
      【解决方案5】:

      谢谢大家的回复,但都没有帮助我:P

      嵌套循环遍历数据集或 gridview 任何适合你的东西..

      我扭转它的方法是连接一行的所有列值,包括一些特殊字符..就像一行有 1 2 3 4 5 6 值..它变成 [1][2][3][4 ][5][6] 然后使用 .Contains 函数比较值,如果发现使用 .Replace 将其从字符串中排除,确保在循环增加时它不被计数..

      一个经典的方法..但它是值得的!

      谢谢大家:)

      【讨论】:

        猜你喜欢
        • 2010-11-27
        • 1970-01-01
        • 1970-01-01
        • 2017-08-15
        • 2022-11-15
        • 2018-05-13
        • 2015-10-15
        • 1970-01-01
        • 2013-02-28
        相关资源
        最近更新 更多