返回在同一列或不同列中找到多个关键字的行,以将这些关键字和相应的列一起显示

时间:2019-03-05 21:49:52

标签: sql sql-server

我希望根据以下示例表,对以下内容有个快速的建议:

|Column1 |Column2 |Column3 |Column4 |
|--------|--------|--------|--------|
|ABC XYZ |DFG KIL |YUI XYZ |ABC IOH |
|YDT NJK |ABC HJK |NJM XYZ |WEC OPP |

我当时想能够建立一个查询来搜索同一列或不同列中的多个单词,以显示那些关键字和相关列。这,不用依靠游标。

即如果用户搜索关键字'ABC', 'YUI', 'OPP',我希望得到以下输出:

|Col1    |Col2    |Col3    |Col4    |Found Keyword|Keyword Found in |
|--------|--------|--------|--------|-------------|-----------------|
|ABC XYZ |DFG KIL |YUI XYZ |ABC IOH |ABC, YUI     |Col1,Col3,Col4   | 
|YDT NJK |ABC HJK |NJM XYZ |WEC OPP |ABC, OPP     |Col2,Col4        |

我一直在尝试做(sys.columns, UNION ALL, CROSS JOIN)之类的各种事情,但到目前为止收效甚微。

行数超过10万,什么是最好的方法?

注意:我正在使用SQL Server 2012版本。

2 个答案:

答案 0 :(得分:0)

糟糕!这是一种可怕的数据格式。您不应在列中存储多个值。但是您可以使用巨型case表达式。例如,对于“找到的关键字”结果:

select t.*,
       stuff( (case when col1 like '%' + @word1 + '%' or col1 like '%' + @word2 + '%' or col1 like '%' + @word3'
                    then ',col1' else ''
               end) +
              (case when col2 like '%' + @word1 + '%' or col2 like '%' + @word2 + '%' or col2 like '%' + @word3'
                    then ',col2' else ''
               end) +
              (case when col3 like '%' + @word1 + '%' or col3 like '%' + @word2 + '%' or col3 like '%' + @word3'
                    then ',col3' else ''
               end), 1, 1, '') as keyword_found_in            
from t;

您可以将类似的逻辑应用于找到的关键字。如果需要,您可以调整逻辑以考虑定界符。

答案 1 :(得分:0)

已经有人评论您的设计应该重新设计。

现在,这是一个应该响应您的用例的查询。通过在子查询中声明要搜索的词(这样就很容易添加更多的词),然后声明JOIN与表:基本上,检查所有串联的列是否与搜索到的列匹配就足够了值(假设使用空格分隔符)。

然后,外部查询使用STRING_AGG()(在SQL Server 2017中可用)执行聚合作业。生成与之匹配的列表的部分有些棘手,因为需要为每条记录手动生成CSV值。

NB:如果您有一个唯一的列(或列的组合),可以避免在汇总时混合记录,这将是很好的选择。我假设一个名为id的主键列。

查询:

SELECT
    t.Col1,
    t.Col2,
    t.Col3,
    t.Col4,
    STRING_AGG(words.txt, ',') FoundKeywords,
    STRING_AGG(
        STUFF(CONCAT( 
            IIF(CONCAT(' ', t.Col1, ' ') LIKE CONCAT(' %', words.txt, '% '), ',Col1', ''),
            IIF(CONCAT(' ', t.Col2, ' ') LIKE CONCAT(' %', words.txt, '% '), ',Col2', ''),
            IIF(CONCAT(' ', t.Col3, ' ') LIKE CONCAT(' %', words.txt, '% '), ',Col3', ''),
            IIF(CONCAT(' ', t.Col4, ' ') LIKE CONCAT(' %', words.txt, '% '), ',Col4', '')
        ), 1, 1, ''),
        ','
    ) KeywordFoundin

FROM
    mytable t
    INNER JOIN (
        SELECT 'ABC' txt UNION ALL SELECT 'YUI' UNION ALL SELECT 'OOP'
    ) words
        ON CONCAT(' ', t.Col1, ' ', t.Col2, ' ', t.Col3, ' ', t.col4, ' ') 
            LIKE CONCAT(' %', words.txt, '% ')
GROUP BY 
    t.id,
    t.Col1,
    t.Col2,
    t.Col3,
    t.Col4

Demo on DB Fiddle

Col1    | Col2    | Col3    | Col4    | FoundKeywords | KeywordFoundin
:------ | :------ | :------ | :------ | :------------ | :-------------
ABC XYZ | DFG KIL | YUI XYZ | ABC IOH | ABC,YUI       | Col1,Col4,Col3
YDT NJK | ABC HJK | NJM XYZ | WEC OPP | ABC           | Col2          

在无法使用STRING_AGG()的SQL Server <2017中,我将使用一个带有很长表达式的简单SELECT来比较和连接所需的信息:

SELECT
    Col1,
    Col2,
    Col3,
    Col4,
    STUFF(CONCAT(
        IIF(CONCAT(' ', Col1, ' ', Col2, ' ', Col3, ' ', Col4, ' ') LIKE CONCAT(' %', 'ABC', '% '), ',ABC', ''),
        IIF(CONCAT(' ', Col1, ' ', Col2, ' ', Col3, ' ', Col4, ' ') LIKE CONCAT(' %', 'YUI', '% '), ',YUI', ''),
        IIF(CONCAT(' ', Col1, ' ', Col2, ' ', Col3, ' ', Col4, ' ') LIKE CONCAT(' %', 'OOP', '% '), ',OOP', '')
    ), 1, 1, '') FoundKeywords,
    STUFF(CONCAT( 
        IIF(
            CONCAT(' ', Col1, ' ') LIKE CONCAT(' %', 'ABC', '% ')
                OR CONCAT(' ', Col1, ' ') LIKE CONCAT(' %', 'YUI', '% ')
                OR CONCAT(' ', Col1, ' ') LIKE CONCAT(' %', 'OOP', '% '),
            ',Col1', 
            ''
        ),
        IIF(
            CONCAT(' ', Col2, ' ') LIKE CONCAT(' %', 'ABC', '% ')
                OR CONCAT(' ', Col2, ' ') LIKE CONCAT(' %', 'YUI', '% ')
                OR CONCAT(' ', Col2, ' ') LIKE CONCAT(' %', 'OOP', '% '),
            ',Col2', 
            ''
        ),
        IIF(
            CONCAT(' ', Col3, ' ') LIKE CONCAT(' %', 'ABC', '% ')
                OR CONCAT(' ', Col3, ' ') LIKE CONCAT(' %', 'YUI', '% ')
                OR CONCAT(' ', Col3, ' ') LIKE CONCAT(' %', 'OOP', '% '),
            ',Col3', 
            ''
        ),
        IIF(
            CONCAT(' ', Col4, ' ') LIKE CONCAT(' %', 'ABC', '% ')
                OR CONCAT(' ', Col4, ' ') LIKE CONCAT(' %', 'YUI', '% ')
                OR CONCAT(' ', Col4, ' ') LIKE CONCAT(' %', 'OOP', '% '),
            ',Col4', 
            ''
        )
    ), 1, 1, '') KeywordFoundin
FROM mytable 
WHERE
    CONCAT(' ', Col1, ' ', Col2, ' ', Col3, ' ', col4, ' ') LIKE CONCAT(' %', 'ABC', '% ')
    OR CONCAT(' ', Col1, ' ', Col2, ' ', Col3, ' ', col4, ' ') LIKE CONCAT(' %', 'YUI', '% ')
    OR CONCAT(' ', Col1, ' ', Col2, ' ', Col3, ' ', col4, ' ') LIKE CONCAT(' %', 'OOP', '% ')

Demo on DB Fiddle