簡體   English   中英

計算兩個文本列中匹配字符數的 SQL 查詢

[英]SQL Query that counts the number of characters match in two text columns

我需要計算兩個文本列(相同大小,在同一個表中)中有多少個字符相等。 例如:

RowNum: Template:         Answers:
------- ---------         --------
   1    ABCDEABCDEABCDE   ABCDAABCDBABCDC
   2    EDAEDAEDAEDAEDA   EDBEDBEDBEDBEDB

SELECT SOME_COUNT_FUNCTION (Template, Answers) 應該返回:

RowNum: Result:
------- -------
   1       12
   2       10

數據庫是一個 MySQL。

不完全是 MySQL,但這里有一些適用於 SQL Server 的東西。 也許它會翻譯過來。

DROP TABLE IF EXISTS #tmp
CREATE TABLE #tmp (
    [RowNum] INT IDENTITY(1,1) PRIMARY KEY,
    [Template] NVARCHAR(20),
    [Answer] NVARCHAR(20),
    [Result] INT
)

INSERT INTO #tmp
VALUES ('ABCDEABCDEABCDE','ABCDAABCDBABCDC', NULL),
('EDAEDAEDAEDAEDA','EDBEDBEDBEDBEDB', NULL)
--SELECT * FROM #tmp

DECLARE @current_template NVARCHAR(50) -- Variable to hold the current template
,   @current_answer NVARCHAR(50) -- Variable to hold the current answer
,   @template_char CHAR(1) -- Char for template letter
,   @answer_char CHAR(1) -- Char for answer letter
,   @word_index INT -- Index (position) within each word
,   @match_counter INT -- Match counter for each word
,   @max_iter INT = (SELECT TOP 1 RowNum FROM #tmp ORDER BY RowNum DESC) -- Max iterations
,   @row_idx INT = (SELECT TOP 1 RowNum FROM #tmp) -- Minimum RowNum as initial row index value.

WHILE (@row_idx <= @max_iter)
    BEGIN
        SET @match_counter = 0 -- Reset match counter for each row
        SET @word_index = 1 -- Reset word index for each row
        SET @current_template = (SELECT [Template] FROM #tmp WHERE RowNum = @row_idx)
        SET @current_answer = (SELECT [Answer] FROM #tmp WHERE RowNum = @row_idx)
        WHILE (@word_index <= LEN(@current_template))
            BEGIN
                SET @template_char = SUBSTRING(@current_template, @word_index, 1)
                SET @answer_char = SUBSTRING(@current_answer, @word_index, 1)
                IF (@answer_char = @template_char)
                    BEGIN
                        SET @match_counter += 1
                    END
                SET @word_index += 1
            END

    UPDATE #tmp
    SET Result = @match_counter
    WHERE RowNum = @row_idx

    SET @row_idx += 1
    END

從臨時表中獲取值:

SELECT * FROM #tmp

輸出:

RowNum  Template        Answer          Result
1       ABCDEABCDEABCDE ABCDAABCDBABCDC 12
2       EDAEDAEDAEDAEDA EDBEDBEDBEDBEDB 10

如果您運行的是 MySQL 8.0,則可以使用遞歸查詢逐個字符比較字符串:

with recursive chars as (
    select rownum, template, answers, 1 idx, 0 res from mytable
    union all
    select 
        rownum, 
        template, 
        answers,
        idx + 1,
        res + ( substr(template, idx, 1) = substr(answers, idx, 1) )
    from chars
    where idx <= least(char_length(template), char_length(answers))
)
select rownum, max(res) result from chars group by rownum order by rownum

在CTE( with子句)中,anchor( union all之前的查詢)選擇全表,然后遞歸成員( union all之后的查詢)比較字符,當前位置( idx )遞增結果( res )如果它們匹配,則前進到下一個位置,直到(最小的)字符串用完。 然后,外部查詢僅按rownum聚合。

DB Fiddle 上的演示

rownum | result
-----: | -----:
     1 |     12
     2 |     10

請記住,此查詢對大型數據集的性能不佳。 存在其他稍微更有效的解決方案(通常使用數字表而不是遞歸 cte),但基本上,正如 Gordon Linoff 所評論的,如果您需要運行此類查詢,您確實希望修復您的數據結構 您應該將每個字符以及它的rownum和它在字符串中的索引存儲在一個單獨的行中。 物化為合適的數據結構,然后你就不需要生成它在每一個查詢的飛行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM