同一列中的多个过滤器

时间:2015-04-21 06:26:49

标签: sql sql-server

我有一个包含一些值和大量过滤器的SQL表

ID | Name  | Filter1 | Filter2 | Filter3 | Filter4 ... and so on...

现在,过滤器已设置为int,我按如下方式运行查询以获取所需数据

select Name 
from tblABC 
where Filter1=1 and Filter2 = 7 and Filter3 = 33 ... and so on...'

我的问题是我想要一个过滤列来保存多个数字。例如: - 第3行将在Filter1单元格中包含数字8和13,因此当我运行8或13的查询时,我得到相同的结果。 即我希望以下两个查询返回相同的结果。

select... where  Filter1=8 
select... where  Filter1=13 

如何做到这一点?我尝试将Filter列转换为nvarchar并输入数据为.8.13。在哪里'。'在哪里用作分隔符。在此之后,运行查询'select ...其中Filter1 LIKE'%。8.。%'对我有用..但是有12个Filter列,当这样的字符串搜索大量运行时,不会使查询变慢。什么是更有效的方法呢?

我正在使用Microsoft SQL 2014

3 个答案:

答案 0 :(得分:3)

一种更有效的方式,嗯。从过滤器中分离 tblABC 将是我建议的方法,即使它不是最有效的方式来弥补它的维护(并且它肯定比使用通配符更有效) )。

tblABC            ID    Name
                  1     Somename
                  2     Othername

tblABCFilter      ID    AbcID     Filter
                  1     1         8
                  2     1         13
                  3     1         33
                  4     2         5

如何查询此数据取决于您当前所需的输出。一种方法是使用以下内容:

SELECT tblABC.Name FROM tblABC
INNER JOIN tblABCFilter ON tblABC.ID = tblABCFilter.AbcID
WHERE tblABCFilter.Filter = 33

这将使用 33 过滤器返回所有名称

如果要查询多个过滤器:

SELECT tblABC.Name FROM tblABC
INNER JOIN tblABCFilter ON tblABC.ID = tblABCFilter.AbcID
WHERE tblABCFilter.Filter IN (33,7)

这将在 33 7 中使用过滤器返回所有名称

我创建了一个小example fiddle.

答案 1 :(得分:1)

我要发布我使用的解决方案。我使用拆分功能(整个互联网上有很多SQL Server拆分功能)

你可以举例如

CREATE FUNCTION [dbo].[SplitString]
    (
        @List NVARCHAR(MAX),
        @Delim VARCHAR(255)
    )
    RETURNS TABLE
    AS
        RETURN ( SELECT [Value] FROM 
          ( 
            SELECT 
              [Value] = LTRIM(RTRIM(SUBSTRING(@List, [Number],
              CHARINDEX(@Delim, @List + @Delim, [Number]) - [Number])))
            FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name)
              FROM sys.all_objects) AS x
              WHERE Number <= LEN(@List)
              AND SUBSTRING(@Delim + @List, [Number], LEN(@Delim)) = @Delim
          ) AS y
        );

并像这样运行您的查询

select Name 
from tblABC 
where Filter1 IN (
         SELECT * FROM SplitString(@DatatoFilter,',') and 
      Filter2 (IN (
         SELECT * FROM SplitString(@DatatoFilter,',') and 
..so on. 

如果你有成千上万的记录,它可能表现不佳。但它应该工作。

我个人的aproch将是一个存储过程和临时表。创建一个临时表,其中包含要用作过滤器的所有值

SELECT * 
INTO #Filter1
FROM SplitString(@DatatoFilter,',')

SELECT *
INTO #Filter2
FROM SplitString(@DatatoFilter,',')

然后是最终选择

SELECT * FROM yourtable 
WHERE Filter1 IN (SELECT DISTINCT Part FROM #Filter1) and 
      Filter2 IN (SELECT DISTINCT Part FROM #Filter2)

我认为它与第一个查询没什么大不同,但它更容易阅读。

答案 2 :(得分:0)

您可以尝试的另一种解决方案是将列转换为XML。它比将列转换为VARCHAR更好。您可以使用.exist仅获取符合条件的记录。这样的事情。

DECLARE @table1 TABLE
(
   [ID] int, [Name] varchar(9),Filter1 XML
)

INSERT INTO @table1
    ([ID], [Name],Filter1)
VALUES
    (1, 'Somename','<Filter>8</Filter>'),
    (2, 'Othername','<Filter>8</Filter><Filter>13</Filter>'),
    (3, 'Thirdname','<Filter>25</Filter>')


DECLARE @FilterValue INT = 8
SELECT Filter1.query('/Filter'),* 
FROM @table1
WHERE Filter1.exist('/Filter[. = sql:variable("@FilterValue")]') = 1

修改

您甚至可以使用XML列来存储所有12个过滤器。所以这个过滤器xml列存储了所有过滤器及其多个值。

DECLARE @table1 TABLE
(
   [ID] int, [Name] varchar(9),Filter XML
)

INSERT INTO @table1
    ([ID], [Name],Filter)
VALUES
    (1, 'Somename','<Filter ID = "1"><FilterVal>8</FilterVal></Filter><Filter ID = "2"><FilterVal>3</FilterVal><FilterVal>12</FilterVal></Filter>'),
    (2, 'Othername','<Filter ID = "1"><FilterVal>8</FilterVal><FilterVal>13</FilterVal></Filter><Filter ID = "2"><FilterVal>8</FilterVal><FilterVal>13</FilterVal></Filter>'),
    (3, 'Thirdname','<Filter ID = "2"><FilterVal>12</FilterVal><FilterVal>25</FilterVal></Filter><Filter ID = "3"><FilterVal>33</FilterVal></Filter>')

DECLARE @Filter1Value INT = 8
DECLARE @Filter2Value INT = 12

SELECT * 
FROM @table1
WHERE Filter.exist('/Filter[@ID = 1]/FilterVal[. = sql:variable("@Filter1Value")]') = 1
AND   Filter.exist('/Filter[@ID = 2]/FilterVal[. = sql:variable("@Filter2Value")]') = 1