简体   繁体   English

匹配多列中的数据

[英]Match Data in a Multiple Column

I have a 20 Column in a Table Col1, Col2, Col3 .... Col20. 我在表Col1,Col2,Col3中有一个20列.... Col20。 RowNo column is a primary column, Col1 to Col20 is a not null int column RowNo列是主列,Col1到Col20是非null int列

in each Column has unique data for single row(means Col1 has 10 so in Col2 to Col20 values is not repeat). 在每列中具有单行的唯一数据(意味着Col1具有10,因此在Col2到Col20值中不重复)。 table has approx 100000 records. 表有大约100000条记录。

i have a 10 values like 18, 3, 15, 16, 11, 5, 41, 61, 43, 80 i want to search each records in all 20 column. 我有10个值,如18,3,15,16,11,5,41,61,43,80我想搜索所有20列中的每个记录。

select only those rows which has all 10 values in col1 to col20 只选择col1到col20中具有全部10个值的那些行

For Ex. 对于Ex。 18 can be match in col1 to col20 18可以匹配col1到col20

as per the below data return 4th row result may be return more then one row 根据以下数据返回第4行结果可能返回多于一行

在此输入图像描述

SELECT * FROM
yourTable
WHERE
  CASE WHEN 18 IN (col1, col2, col3, ...col20) THEN 1 ELSE 0 END
+ CASE WHEN  3 IN (col1, col2, col3, ...col20) THEN 1 ELSE 0 END
+ CASE WHEN 15 IN (col1, col2, col3, ...col20) THEN 1 ELSE 0 END
+ CASE WHEN 16 IN (col1, col2, col3, ...col20) THEN 1 ELSE 0 END
+ CASE WHEN 11 IN (col1, col2, col3, ...col20) THEN 1 ELSE 0 END
+ CASE WHEN  5 IN (col1, col2, col3, ...col20) THEN 1 ELSE 0 END
+ CASE WHEN 41 IN (col1, col2, col3, ...col20) THEN 1 ELSE 0 END
+ CASE WHEN 61 IN (col1, col2, col3, ...col20) THEN 1 ELSE 0 END
+ CASE WHEN 43 IN (col1, col2, col3, ...col20) THEN 1 ELSE 0 END
+ CASE WHEN 80 IN (col1, col2, col3, ...col20) THEN 1 ELSE 0 END
= 10

An Alternative: Copy your data into a query-friendly table. 替代方案:将数据复制到查询友好的表中。

The table: 桌子:

   CREATE TABLE [dbo].[tblX](
        [ID] [int] IDENTITY(1,1) NOT NULL,
        [ColN] [int] NULL,
        [Value] [int] NULL,
        [RowNo] [int] NULL
    );

Copy data over: 复制数据:

    INSERT INTO tblX(RowNo, ColN, Value)
    SELECT RowNo, 1, Col1 FROM tblCols;
    INSERT INTO tblX(RowNo, ColN, Value)
    SELECT RowNo, 2, Col2 FROM tblCols;
    INSERT INTO tblX(RowNo, ColN, Value)
    SELECT RowNo, 3, Col3 FROM tblCols;
    INSERT INTO tblX(RowNo, ColN, Value)
    ...
    INSERT INTO tblX(RowNo, ColN, Value)
    SELECT RowNo, 20, Col20 FROM tblCols;

The query: 查询:

    SELECT
        * 
    FROM
        tblX
        WHERE RowNo IN 
        (
                SELECT 
                    RowNo
                FROM
                    tblX
                WHERE
                    Value IN (18, 3, 15, 16, 11, 5, 41, 61, 43, 80)
                GROUP BY RowNo
                HAVING COUNT(*) = 10 -- the number of numbers above
         ) 
    ORDER BY RowNo, ColN

you first get the filter value as a comma separated, and then using below function get it in a table in different rows 首先以逗号分隔的方式获取过滤器值,然后使用下面的函数将其放入不同行的表中

CREATE FUNCTION [dbo].[Split]
(
@String VARCHAR(200),
@Delimiter VARCHAR(5)
)

RETURNS @SplittedValues TABLE
(
OccurenceId SMALLINT IDENTITY(1,1),
SplitValue VARCHAR(200)
)

AS

BEGIN

DECLARE @SplitLength INT

WHILE LEN(@String) > 0
BEGIN

SELECT @SplitLength = (CASE CHARINDEX(@Delimiter,@String) WHEN 0 THEN

LEN(@String) ELSE CHARINDEX(@Delimiter,@String) -1 END)

INSERT INTO @SplittedValues

SELECT SUBSTRING(@String,1,@SplitLength)

SELECT @String = (CASE (LEN(@String) - @SplitLength) WHEN 0 THEN ''

ELSE RIGHT(@String, LEN(@String) - @SplitLength - 1) END)

END

RETURN

now declare a cusor for this table to get one by one value 现在声明这个表的cusor来逐个获取值

now in side this cursor using 现在在这个光标旁边使用

SELECT s.name SchemaName, t.name TableName, c.name ColumnName
FROM sys.columns c INNER JOIN
     sys.tables t ON c.object_id = t.object_id INNER JOIN
     sys.schemas s ON t.schema_id = s.schema_id
;

get all the columns of one row in different rows and run loop of it and check with it filter value, basically inside above cursor you have to run another cursor 获取不同行中一行的所有列并运行它的循环并检查它的过滤值,基本上在游标上方你必须运行另一个游标

its ugly, lengthy , but better than nothing :-) 它丑陋,冗长,但总比没有好:-)

before your answer i am use below function which is return me a match count and get where count = 10 在你的答案之前,我使用下面的功能,它返回一个匹配计数,并得到count = 10的地方

Create FUNCTION [dbo].[MatchRows]
(
    @id int, 
    @No1 int, 
    @No2 int,
    @No3 int,
    @No4 int,
    @No5 int,
    @No6 int,
    @No7 int,
    @No8 int,
    @No9 int,
    @No10 int   
)
RETURNS bit
AS
BEGIN
    Declare @ReturnVal bit = 0; 
    Declare @Allvalue varchar(max);
    Declare @CntMatch int;

    SELECT  @Allvalue = ',' + Convert(varchar(3),No1)+ ',' +
                        Convert(varchar(3),No2)+ ',' +
                        Convert(varchar(3),No3)+ ',' +
                        Convert(varchar(3),No4)+ ',' +
                        Convert(varchar(3),No5)+ ',' +
                        Convert(varchar(3),No6)+ ',' +
                        Convert(varchar(3),No7)+ ',' +
                        Convert(varchar(3),No8)+ ',' +
                        Convert(varchar(3),No9)+ ',' +
                        Convert(varchar(3),No10)+ ',' +
                        Convert(varchar(3),No11)+ ',' +
                        Convert(varchar(3),No12)+ ',' +
                        Convert(varchar(3),No13)+ ',' +
                        Convert(varchar(3),No14)+ ',' +
                        Convert(varchar(3),No15)+ ',' +
                        Convert(varchar(3),No16)+ ',' +
                        Convert(varchar(3),No17)+ ',' +
                        Convert(varchar(3),No18)+ ',' +
                        Convert(varchar(3),No19)+ ',' +
                        Convert(varchar(3),No20)+ ','
    FROM    DrawFinalResult
    WHERE   ID = @ID;

    SET @CntMatch = 0;

    Select @CntMatch += (CASE  WHEN CHARINDEX(','+ Convert (varchar(3),@No1) +',',@Allvalue) > 0 THEN 1 Else 0 END); 
    Select @CntMatch += (CASE  WHEN CHARINDEX(','+ Convert (varchar(3),@No2) +',',@Allvalue) > 0 THEN 1 Else 0 END); 
    Select @CntMatch += (CASE  WHEN CHARINDEX(','+ Convert (varchar(3),@No3) +',',@Allvalue) > 0 THEN 1 Else 0 END); 
    Select @CntMatch += (CASE  WHEN CHARINDEX(','+ Convert (varchar(3),@No4) +',',@Allvalue) > 0 THEN 1 Else 0 END); 
    Select @CntMatch += (CASE  WHEN CHARINDEX(','+ Convert (varchar(3),@No5) +',',@Allvalue) > 0 THEN 1 Else 0 END); 
    Select @CntMatch += (CASE  WHEN CHARINDEX(','+ Convert (varchar(3),@No6) +',',@Allvalue) > 0 THEN 1 Else 0 END); 
    Select @CntMatch += (CASE  WHEN CHARINDEX(','+ Convert (varchar(3),@No7) +',',@Allvalue) > 0 THEN 1 Else 0 END); 
    Select @CntMatch += (CASE  WHEN CHARINDEX(','+ Convert (varchar(3),@No8) +',',@Allvalue) > 0 THEN 1 Else 0 END); 
    Select @CntMatch += (CASE  WHEN CHARINDEX(','+ Convert (varchar(3),@No9) +',',@Allvalue) > 0 THEN 1 Else 0 END); 
    Select @CntMatch += (CASE  WHEN CHARINDEX(','+ Convert (varchar(3),@No10) +',',@Allvalue) > 0 THEN 1 Else 0 END); 

    Set @ReturnVal = (CASE WHEN @CntMatch = 10 THEN 1 ELSE 0 END);

    RETURN @ReturnVal
END

You also can use unpivot to reduce typing col1, col2, ..., colN (especially if it will differ in future). 您还可以使用unpivot来减少输入col1, col2, ..., colN (特别是如果它将来会有所不同)。 You can try smth like this: 你可以尝试这样的smth:

create table Unpivoted (RoNo int, Value int primary key)

insert Unpivoted
select
  upvt.RoNo, upvt.Value
from (
  select * from YourTable
) src
unpivot (
  Value for ColNo in (
    col1, col2, col3, col4, col5, 
    col6, col7, col8, col9, col10 -- etc.
  )
) upvt

select
  *
from YourTable yt
join (
  select
    RoNo
  from Unpivoted
  where
    Value in (
      18, 3, -- etc. N values at all
    )
  group by
    RoNo
  having
    count(*) = N
) x on 
  yt.RoNo = x.RoNo

drop table Unpivoted

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

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