SQL Запрос, который подсчитывает количество совпадений символов в двух текстовых столбцах - PullRequest
0 голосов
/ 08 января 2020

Мне нужно посчитать, сколько символов равно в двух текстовых столбцах (одинакового размера, в одной таблице). Например:

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

SELECT SOME_COUNT_FUNCTION (Шаблон, Ответы) должен вернуть:

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

База данных MySQL.

Ответы [ 2 ]

1 голос
/ 08 января 2020

Не совсем MySQL, но вот что работает на SQL Сервере. Может быть, это будет преобразовано.

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
0 голосов
/ 08 января 2020

Если вы используете 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) якорь (запрос до union all) выбирает всю таблицу, затем рекурсивный элемент (запрос после union all) сравнивает символы, и текущая позиция (idx) увеличивает результат (res), если они совпадают, и переходит к Следующая позиция, пока (самая маленькая) строка не будет исчерпана. Тогда внешний запрос просто агрегирует по rownum.

Демонстрация на DB Fiddle :

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

Пожалуйста, имейте в виду, что это запрос не будет хорошо работать с большим набором данных. Существуют и другие более эффективные решения (обычно с использованием таблицы чисел вместо рекурсивного cte), но в основном, как прокомментировал Гордон Линофф, вы действительно хотите исправить свою структуру данных , если вам нужно выполнить такие запросы , Вы должны хранить каждый символ в отдельной строке вместе с rownum и его индексом в строке. Материализуйте правильную структуру данных, и тогда вам не нужно будет генерировать ее на лету в каждом запросе.

...