根据用户输入匹配SQL列

时间:2011-01-24 14:28:20

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

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

我想要实现的是我的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

5 个答案:

答案 0 :(得分:2)

虚拟数据(来自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将源列数据转换为行。现在我们可以加入并聚合以找到没有大量OR子句的3个匹配的位置

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

答案 1 :(得分:1)

您可以遍历这些值并将 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

答案 2 :(得分:0)

我认为这最容易实现

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

答案 3 :(得分:0)

我没有时间编写代码,但是你提到过你尝试过嵌套循环。既然我明白你想做什么,我至少可以给你一个我想认为适合你的方向的推动。

在内部循环中,您将获取要比较输入的第一个列表,然后获取第一个输入并将其与列表中的每个成员进行比较,直到达到匹配或结束。现在是棘手的部分...因为你不想将你输入的第二个数字与列表中的同一个成员匹配两次(例如你输入了2 7个),你应该将你匹配的成员改为某个非法数字。如果只允许正数,则将其更改为-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的任何列表都匹配。

答案 4 :(得分:0)

非常感谢大家的回复,但这对我没有任何帮助:P

嵌套循环遍历数据集或gridview适合您的任何内容..

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

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

谢谢你们:)