Поиск Varbinary с минимальным и максимальным типом шаблона

Итак, я пытаюсь сделать запрос, который проходит через данные varbinary. Проблема в том, что я не могу закончить то, чего пытаюсь достичь. Что вы должны знать о столбце, так это varbinary(50), и встречающиеся шаблоны не имеют определенного порядка записи, что означает, что каждый префикс может быть где угодно, если он имеет 3 байта (0x000000). Первый - это префикс, второй и третий - данные значения. что я хочу проверить, находится ли он в пределах диапазона, который мне нравится. Все данные пишутся так.

Что я пробовал:

DECLARE @t TABLE (
    val VARBINARY(MAX)
)

INSERT INTO @t SELECT 0x00000100000000000000000000000000000000000000000000000000
INSERT INTO @t SELECT 0x00001000000000000000000000000000000000000000000000000000
INSERT INTO @t SELECT 0x00010000000000000000000000000000000000000000000000000000
INSERT INTO @t SELECT 0x00100000000000000000000000000000000000000000000000000000
INSERT INTO @t SELECT 0x00000f00000000000000000000000000000000000000000000000000

declare @pattern varbinary(max)
declare @pattern2 varbinary(max)
set @pattern = 0x0001
set @pattern2 = @pattern+0xFF

select @pattern,@pattern2

SELECT
    *
FROM @t
WHERE val<@pattern
OR val>@pattern2

Это был полный провал, паттерны были точными до 2 символов, если бы я использовал 4 символа в качестве паттерна, это сработало бы, только если паттерн находится в предопределенной позиции. Я пробовал комбинацию этого и всего ниже.

WHERE CONVERT(varbinary(2), val) = 0xdata

также это:

select * 
from table
where CONVERT(varchar(max),val,2) like '%data%'

Что отлично работает для поиска точных шаблонов, но не для диапазонов, мне нужна комбинация обоих.

Я знаю, что технически я мог бы добавить каждый возможный результат 1 к 1 и позволить ему циклически проходить через все перечисленные возможности, но должен быть более умный способ. Цели:

  1. Поиск префикса (первая пара двоичных данных)
  2. Определив максимальное значение после префикса, все, что выше этого порога, будет указано в результатах. Допустим, «26» — это префикс, максимально допустимое число после «9600» или «269600». По сути, любые данные, которые превышают этот шаблон «269600», должны быть обнаружены, например, «269700». или результат запроса опубликует это:

выберите * из таблицы, где CONVERT (varchar (max), attr, 2), например '%269700%'

Мне нужно что-то, что обнаружит это само по себе, в то время как я просто даю ему начало и конец, чтобы искать между ними, например, наибольший вариант числа будет «26ffff», но ограничение его чем-то вроде «ff00» приемлемо для того, что я ищу для.

Мое лучшее предположение - 2 определенных числа, 1 - допустимый максимальный диапазон. и 2-й для кепки, поэтому он не проходит через все возможные результаты. Но я был бы рад тому, что работает. Я знаю, что это объяснение довольно ужасное, но потерпите меня, спасибо.

* Обновление после последнего предложения

SELECT MIN(val), MAX(val) FROM @t where CONVERT(varchar(max),val,2) like '%26%'

Это довольно близко, но этого недостаточно, мне нужно просмотреть много данных и использовать их после того, как это выберет только минимум или максимум даже с фильтром префикса. Я считаю, что мне нужно, чтобы min и max были определены как начальный и конечный диапазоны, в которых должен искать запрос.

**Обновление2

Боюсь, вы разочаруетесь, в этом нет ничего интересного. Источник данных связан с игровым сервером, который хранит такие данные. Есть предопределенные префиксы, которые являются типом статистики, а остальные данные являются фактическим числовым значением статистики. Данные представлены 6-символьными интервалами данных. Вот пример потока данных. Это всегда 6-6-6-6-6, пока есть место для записи данных, поскольку оно ограничено 50 символами.

0x0329000414000B14000C14000D0F00177800224600467800473C00550F00000000000000000000000000

**Обновление3

Да, группы всегда трехбайтовые, да, моя идея заключалась именно в том, чтобы использовать первый байт для сужения поиска, а затем использовать вторые 2 байта для его фильтрации. Я просто не знаю, как сделать это эффективным способом. Я не уверен, понял ли я, что вы имели в виду под предиктивным выравниванием, предполагая, что вы имели в виду, что stat/prefix/header всегда будут заканчиваться в одном и том же двоичном расположении, если это правильно, ответ - нет. Если 3-байтовый шаблон нарушен, данные становятся нечитаемыми, что означает, что даже если вам не нужен дополнительный байт, вы должны его подсчитать, иначе данные нарушают пример рабочих данных.

0x032900'041400'

пример неработающих данных:

 0x0329'041400'

Единственная проблема, о которой я мог подумать, это когда префикс и часть значения являются истинными примерами:

0x262600

Если запрос специально не заказан для чтения данных в 3-байтовой последовательности, это означает, что он знает, что первый байт всегда является префиксом, а другие 2 байта — значением.

В: Можно ли использовать это как индикатор выравнивания, чтобы первый ненулевой байт после как минимум 3 нулевых байтов указывал на начало группы?

О: Да, но вряд ли я это имел в виду, хотя, возможно, это было бы написано по порядку, например:

0x260000'270000'

Он не будет пропускать всю 3-байтовую группу, заполненную без данных. Этот тип записи возникнет, если кто-то вручную вставит его в БД, насколько мне известно, сервер не делает записи с такими пробелами:

0x260000'000000'270000'

Чтобы ответить на ваш последний комментарий, я не знаю, как выразить это в рабочем запросе, за исключением тупоголовой версии, в которой я вручную добавляю все возможные числа в пределах моего желаемого диапазона с +1 битом после этого числа. Как вы понимаете, запрос будет выглядеть ужасно. Вот почему я ищу более разумное решение, которое я не могу понять, как это сделать самостоятельно.

select * from @t 
where (CONVERT(varchar(max),val,2) like '%262100%' or 
CONVERT(varchar(max),attr,2) like '%262200%' or 
etc...)

Пожалуйста, вернитесь и уточните свое заявление о требованиях. Каково ваше определение шаблона и как он предназначен для выбора (включения или исключения) ваших данных. Включите ожидаемые результаты для нескольких типовых шаблонов и объясните, почему. Я прочитал ваше описание три раза, и я был потерян. Кажется, ваш код использует шаблон для соответствия префиксу, но я не был уверен. Вы полностью потеряли меня в «пока у него есть 3 двоичных пробела».

T N 07.02.2023 03:13

(Похоже, что программная реализация турбоэнкабулятора будет установлена ​​как прошивка в последнем обновлении гонкулятора ВВС.) Но я вернусь, чтобы найти обновления.

T N 07.02.2023 03:26

@AlwaysLearning - я не согласен. varbinary имеет порядок. Запустите SELECT * FROM @t ORDER BY val или SELECT MIN(val), MAX(val) FROM @t против примера данных выше.

T N 07.02.2023 04:22

Можете ли вы объяснить, откуда берутся эти данные в реальном мире? Данные датчика окружающей среды? Двоичные команды для станка с ЧПУ? Шифрование времен Второй мировой войны? Внеземная связь (возможно, Вгер)? Это может помочь нам понять, чего вы пытаетесь достичь. Пока это звучит так, как будто вы хотите искать поток байтов для определенного шаблона, а затем сразу же проверять значения, чтобы либо включить, либо исключить регистр как совпадение. Будут ли значения, которые вы ищете, всегда выровнены по байтам или они могут быть с любым битовым смещением? Пожалуйста, продолжайте уточнять описание.

T N 07.02.2023 05:08

Спасибо за обновление. Будут ли данные всегда находиться в группах по 3 байта (6 шестнадцатеричных символов)? Будет ли шаблон поиска всегда находиться в начале 3-байтовой группы? Возможно, имеет смысл сначала разделить входящие данные на отдельные группы, чтобы вам нужно было сопоставить только первый байт, а затем проверить значение в двух других байтах. В качестве альтернативы, если данные не выровнены предсказуемым образом, мы можем разделить ввод, извлекая каждое 3-байтовое значение для передачи на следующий шаг. Пример: 0x1122334455 будет разделен на 0x112233, 0x223344, 0x334455, после чего вы сможете просмотреть каждую группу.

T N 07.02.2023 06:45

Вы также упомянули 0x000000. Можно ли это использовать в качестве индикатора выравнивания, чтобы первый ненулевой байт после как минимум 3 нулевых байтов указывал на начало группы? Наличие образцов прочитанных данных для работы очень помогает. (Я отключусь от сети, но завтра проверю ваши ответы.)

T N 07.02.2023 06:46

Рассмотрим свою задачу, если ваши входные данные выглядели как: 0x032900, 0x041400, 0x0b1400, 0x0c1400, 0x0d0f00, 0x177800, 0x224600, 0x467800, 0x473c00, 0x550f00, 0x000000, 0x000000000000000000000000000000000000000000000000.

T N 07.02.2023 06:53
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
103
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Это может быть частичным ответом, из которого вы можете построить.

Следующее разделит входные данные на группы по 3 байта (6 шестнадцатеричных символов). Затем он извлекает первый байт в качестве ключа и несколько представлений оставшихся двух байтов в качестве значений.

SELECT S.*, P.*
FROM @t T
CROSS APPLY (
    SELECT
        N.Offset,
        SUBSTRING(T.val, N.Offset + 1, 3) AS Segment
    FROM (
        VALUES
            (0), (3), (6), (9), (12), (15), (18), (21), (24), (27),
            (30), (33), (36), (39)
    ) N(Offset)
    WHERE N.Offset < LEN(T.val) - 3
) S
CROSS APPLY(
    SELECT
        CONVERT(TINYINT, SUBSTRING(S.Segment, 1, 1)) AS [Key],
        CONVERT(TINYINT, SUBSTRING(S.Segment, 2, 1)) AS [Value1],
        CONVERT(TINYINT, SUBSTRING(S.Segment, 3, 1)) AS [Value2],
        CONVERT(SMALLINT, SUBSTRING(S.Segment, 2, 2)) AS [Value12],
        CONVERT(SMALLINT, SUBSTRING(S.Segment, 3, 1) + SUBSTRING(S.Segment, 2, 1)) AS [Value21]
) P

Учитывая следующие входные данные

0x0329000414000B14000C14000D0F00177800224600467800473C00550F00000000000000000000000000
--^-----^-----^-----^-----^-----^-----^-----^-----^-----^-----^-----^-----^-----^-----

Извлекаются следующие результаты:

Компенсировать Сегмент Ключ Значение1 Значение2 Значение12 Значение21 0 0x032900 3 41 0 10496 41 3 0x041400 4 20 0 5120 20 6 0x0B1400 11 20 0 5120 20 9 0x0C1400 12 20 0 5120 20 12 0x0D0F00 13 15 0 3840 15 15 0x177800 23 120 0 30720 120 18 0x224600 34 70 0 17920 70 21 0x467800 70 120 0 30720 120 24 0x473C00 71 60 0 15360 60 27 0x550F00 85 15 0 3840 15 30 0x000000 0 0 0 0 0 33 0x000000 0 0 0 0 0 36 0x000000 0 0 0 0 0

Смотрите эту скрипку db<>.

Ответ принят как подходящий
DECLARE @YourTable table
(
Id INT PRIMARY KEY,
Val VARBINARY(50)
)

INSERT @YourTable
VALUES (1, 0x0329000414000B14000C14000D0F00177800224600467800473C00550F00000000000000000000000000),
       (2, 0x0329002637000B14000C14000D0F00177800224600467800473C00550F00000000000000000000000000);

SELECT Id, Triplet
FROM @YourTable T
CROSS APPLY GENERATE_SERIES(1,DATALENGTH(T.Val),3) s
CROSS APPLY (VALUES (SUBSTRING(T.Val, s.value, 3))) V(Triplet)
WHERE Triplet BETWEEN 0x263700 AND 0x2637FF

Это работает только с сервером 22 sql из-за «generate_series».

DECLARE @YourTable table
(
Id INT PRIMARY KEY,
Val VARBINARY(50)
)

INSERT @YourTable
VALUES (1, 0x0329000414000B14000C14000D0F00177800224600467800473C00550F00000000000000000000000000),
       (2, 0x0329002637000B14000C14000D0F00177800224600467800473C00550F00000000000000000000000000);


SELECT Id, Triplet
FROM @YourTable T
JOIN (VALUES (1),(4),(7),(10),(13),(16),(19),(22),(25),(28),(31),(34),(37),(40),(43),(46),(49)) Nums(Num) ON Num <= DATALENGTH(T.Val)
CROSS APPLY (VALUES (SUBSTRING(T.Val, Num, 3))) V(Triplet)
WHERE Triplet BETWEEN 0x263700 AND 0x2637FF

Этот работает на более старых версиях без «generate_series».

Кредит принадлежит @Martin Smith из stackexchange https://dba.stackexchange.com/questions/323235/varbinary-pattern-search

Другие вопросы по теме