【问题标题】:SQL Server dynamic column list in contains function包含函数中的 SQL Server 动态列列表
【发布时间】:2009-10-13 21:44:01
【问题描述】:

我在 SQL Server 2008 中有一个包含 5 个 nvarchar(max) 列的数据库表。我们使用 CONTAINS 函数在这些列中查找文本。

我们可以使用这种查询查看所有五列:

SELECT *
FROM SomeTable ST
WHERE CONTAINS( (ST.ColumnA, ST.ColumnB, ST.ColumnC, ST.ColumnD, ST.ColumnE) , '"Strawberry"')

现在我们要动态搜索这些列中的一个或多个的文本。例如,仅查看 ColumnB 和 ColumnE。我尝试使用 CASE 语句,但我做不到。

我能想到的唯一解决方案是动态 SQL,但我更愿意避免这种情况。 (完整的查询非常复杂。)有没有办法在不使用动态 SQL 的情况下做到这一点?

【问题讨论】:

    标签: sql sql-server tsql sql-server-2008


    【解决方案1】:

    我能想到的避免使用动态 SQL 的唯一方法是使用临时表、if 语句和存储过程。有一个存储过程,其中包含用于搜索该列的文本的每个列的参数。创建临时表或表变量来存储临时结果。

    每个可能的列有五个不同的 if 语句。如果变量不为空,则在每个 if 中插入临时表。类似:

    IF @ColA is not null
    BEGIN
    INSERT INTO #temp
    SELECT * FROM SomeTable ST
            WHERE CONTAINS( (ST.ColumnA) , @ColA)
    END
    

    最后从临时表中选择以显示您的结果。

    这只有在您没有太多列并且不太可能添加更多列的情况下才有效。坦率地说,您有多个列需要对同一个搜索字符串进行全文搜索这一事实向我表明您可能在数据库设计方面存在基本问题。

    【讨论】:

      【解决方案2】:

      我只是可以考虑这样的解决方案,但这不使用全文搜索...如果它对你有用,请告诉我。

      SELECT *
      FROM SomeTable ST
      WHERE 1=1
      AND ((@colA = '') OR ST.ColumnA LIKE @colA)
      AND ((@colB = '') OR ST.ColumnB LIKE @colB)
      AND ((@colC = '') OR ST.ColumnC LIKE @colC)
      AND ((@colD = '') OR ST.ColumnD LIKE @colD)
      AND ((@colE = '') OR ST.ColumnE LIKE @colE)
      

      search_on 参数将是位 (0, 1),因此,当设置为 1 时,将激活对该列的搜索。

      【讨论】:

      • 不使用全文搜索包含的内容。
      • 如果您认为 SQL 将简化逻辑,您不会使用 'and' 子句代替还是使用 'or' 所以第一个子句为 false 创建了快捷方式?
      • 括号内的 OR 会告诉 SQL 如果第一个参数为空,则不要检查第二个条件,以此类推每个“AND”行
      • 是的,可以通过原始数字比较看到您的逻辑与空字符串。它会短路并且足够简单,评估顺序不太可能改变。
      • 其实这是我们一直在使用的解决方案。问题是布尔搜索。如果您搜索“草莓和香蕉”,它只会在单个列中找到同时包含这两个词的内容。如果“草莓”在A列,“香蕉”在B列,则不会返回记录。
      【解决方案3】:

      您可以 UNION 5 个单独的案例,然后 PIVOT 并连接。我不确定它是否比动态 SQL 更好。

      你最终会得到类似的东西:

      SET @FindKey = '%B%E%' -- This is your search which field criteria
      
      WITH RESULTS1 AS (
          SELECT PK, 'A' AS Col
          FROM SomeTable ST
          WHERE @FindKey LIKE '%A%' AND CONTAINS(ST.ColumnA, '"Strawberry"')
          UNION
          SELECT PK, 'B' AS Col
          FROM SomeTable ST
          WHERE @FindKey LIKE '%B%' AND CONTAINS(ST.ColumnB, '"Strawberry"')
          UNION
          SELECT PK, 'C' AS Col
          FROM SomeTable ST
          WHERE @FindKey LIKE '%C%' AND CONTAINS(ST.ColumnC, '"Strawberry"')
          UNION
          SELECT PK, 'D' AS Col
          FROM SomeTable ST
          WHERE @FindKey LIKE '%D%' AND CONTAINS(ST.ColumnD, '"Strawberry"')
          UNION
          SELECT PK, 'E' AS Col
          FROM SomeTable ST
          WHERE @FindKey LIKE '%E%' AND CONTAINS(ST.ColumnE, '"Strawberry"')
      )
      ,RESULTS2 AS (
      SELECT PK, ISNULL([A], '') + ISNULL([B], '') + ISNULL([C], '') + ISNULL([D], '') + ISNULL([E], '') AS FoundKey
      FROM RESULTS PIVOT ( MIN(Col) FOR Col IN ([A], [B], [C], [D], [E]) ) AS pvt
      )
      SELECT *
      FROM SomeTable
      INNER JOIN RESULTS2
          ON RESULTS2.PK = SomeTable.PK
      WHERE RESULTS2.FoundKey LIKE @FindKey
      

      【讨论】:

      • 我没有想到数据透视表,但我认为这会对布尔搜索产生问题。如果您搜索“草莓和香蕉”,它只会在单个列中找到同时包含这两个词的那些。如果“草莓”在 A 列,“香蕉”在 B 列,则不会返回记录。对吗?
      • 是的,这是正确的,要执行类似的操作,您必须将该逻辑扩展到 UNION。我真的认为动态 SQl 在这里是一个不错的选择。
      猜你喜欢
      • 1970-01-01
      • 2017-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-12
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      相关资源
      最近更新 更多