Итак, я пытаюсь сделать запрос, который проходит через данные 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 и позволить ему циклически проходить через все перечисленные возможности, но должен быть более умный способ. Цели:
выберите * из таблицы, где 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...)
(Похоже, что программная реализация турбоэнкабулятора будет установлена как прошивка в последнем обновлении гонкулятора ВВС.) Но я вернусь, чтобы найти обновления.
@AlwaysLearning - я не согласен. varbinary имеет порядок. Запустите SELECT * FROM @t ORDER BY val
или SELECT MIN(val), MAX(val) FROM @t
против примера данных выше.
Можете ли вы объяснить, откуда берутся эти данные в реальном мире? Данные датчика окружающей среды? Двоичные команды для станка с ЧПУ? Шифрование времен Второй мировой войны? Внеземная связь (возможно, Вгер)? Это может помочь нам понять, чего вы пытаетесь достичь. Пока это звучит так, как будто вы хотите искать поток байтов для определенного шаблона, а затем сразу же проверять значения, чтобы либо включить, либо исключить регистр как совпадение. Будут ли значения, которые вы ищете, всегда выровнены по байтам или они могут быть с любым битовым смещением? Пожалуйста, продолжайте уточнять описание.
Спасибо за обновление. Будут ли данные всегда находиться в группах по 3 байта (6 шестнадцатеричных символов)? Будет ли шаблон поиска всегда находиться в начале 3-байтовой группы? Возможно, имеет смысл сначала разделить входящие данные на отдельные группы, чтобы вам нужно было сопоставить только первый байт, а затем проверить значение в двух других байтах. В качестве альтернативы, если данные не выровнены предсказуемым образом, мы можем разделить ввод, извлекая каждое 3-байтовое значение для передачи на следующий шаг. Пример: 0x1122334455 будет разделен на 0x112233, 0x223344, 0x334455, после чего вы сможете просмотреть каждую группу.
Вы также упомянули 0x000000. Можно ли это использовать в качестве индикатора выравнивания, чтобы первый ненулевой байт после как минимум 3 нулевых байтов указывал на начало группы? Наличие образцов прочитанных данных для работы очень помогает. (Я отключусь от сети, но завтра проверю ваши ответы.)
Рассмотрим свою задачу, если ваши входные данные выглядели как: 0x032900, 0x041400, 0x0b1400, 0x0c1400, 0x0d0f00, 0x177800, 0x224600, 0x467800, 0x473c00, 0x550f00, 0x000000, 0x000000000000000000000000000000000000000000000000.
Это может быть частичным ответом, из которого вы можете построить.
Следующее разделит входные данные на группы по 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
--^-----^-----^-----^-----^-----^-----^-----^-----^-----^-----^-----^-----^-----^-----
Извлекаются следующие результаты:
Смотрите эту скрипку 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
Как сейчас написано, ваш ответ неясен. Пожалуйста, отредактируйте , чтобы добавить дополнительные сведения, которые помогут другим понять, как это отвечает на заданный вопрос. Вы можете найти больше информации о том, как писать хорошие ответы в справочном центре.
Пожалуйста, вернитесь и уточните свое заявление о требованиях. Каково ваше определение шаблона и как он предназначен для выбора (включения или исключения) ваших данных. Включите ожидаемые результаты для нескольких типовых шаблонов и объясните, почему. Я прочитал ваше описание три раза, и я был потерян. Кажется, ваш код использует шаблон для соответствия префиксу, но я не был уверен. Вы полностью потеряли меня в «пока у него есть 3 двоичных пробела».