Агрегатная хеш-функция?

#sql #teradata

#sql #teradata

Вопрос:

Точно так же, как у нас есть агрегатные функции sum и count, есть ли какой-нибудь способ сделать агрегированные хэши в поле? Например, предположим, что у вас есть следующий набор записей:

 Name     ID
Bob      1
Bob      2
Bob      3
Bob      4
  

Концептуально я хотел бы сделать это:

 select name, hash(id) from mydb.mytable
group by 1
  

… который вернет это:

 Name     ID
Bob      D8-F0-00-91
  

Если я удалю запись с ID = 3, агрегат вернет это:

 Name     ID
Bob      A8-EB-6D-1D
  

К вашему сведению, я использовал select hashrow(1,2,3,4) и select hashrow(1,2,4) для получения вышеуказанных значений хэша.

Обновление для dnoeth: вероятно, полезно упомянуть, что мне нужно, чтобы результирующий агрегат был уникальным. Вот пример модели данных, которую я использую:

 table office (Id integer)
table employee (Id integer, OfficeId integer)
  

В каждом офисе есть сотрудники, так что это один ко многим от office к employee с таблицей employee, имеющей OfficeId в качестве FK для таблицы office.

 locking row for access
select n, count(n) from
(
    select 
        officeid, 
        sum(cast(from_bytes('00'xb || hashrow(id), 'base10') as bigint)) n 
    from mydb.employee
    group by 1
) x
group by 1
  

Вот отличный пример того, как происходит столкновение. Опять же, я не упомянул, что мне нужно, чтобы результат был уникальным.

 select 
    cast(from_bytes('00'xb || hashrow(2300015), 'base10') as bigint)  
    cast(from_bytes('00'xb || hashrow(14100028), 'base10') as bigint) hash1,

    cast(from_bytes('00'xb || hashrow(1000004), 'base10') as bigint)  
    cast(from_bytes('00'xb || hashrow(3100014), 'base10') as bigint)  
    cast(from_bytes('00'xb || hashrow(12300025), 'base10') as bigint) hash2
  

Комментарии:

1. Существуют функции, связанные с хэшем. Чего вы пытаетесь достичь?

2. @RobPaller Я обновил свой ответ для большей ясности.

Ответ №1:

Вам нужно преобразовать результат хэш-строки в числовое значение, затем вы можете легко его суммировать.

 -- HASHROW to unsigned integer, TD14
SUM(CAST(FROM_BYTES('00'xb||HASHROW(ColumnName), 'base10') AS BIGINT)
   ) AS SumHash

-- HASHROW to unsigned integer, pre-TD14
SUM(  HASHBUCKET(       HASHROW(ColumnName)      (BYTE(4)))  / ((HASHBUCKET() 1)/65536) * CAST(65536 AS BIGINT)
      HASHBUCKET(SUBSTR(HASHROW(ColumnName),3,2) (BYTE(4)))  / ((HASHBUCKET() 1)/65536)
   ) AS SumHash
  

Редактировать:

Нет способа получить гарантированный уникальный результат при хешировании, есть только возрастающая вероятность, основанная на длине вычисляемого хэша. И HASHROW возвращает значение в 4 байта, и вы просто добавляете их:-(

Вы могли бы установить существующий UDF хэширования, возвращающий более 4 байт, например

https://downloads.teradata.com/download/extensibility/sha-1-message-digest-udf

https://downloads.teradata.com/download/extensibility/md5-message-digest-udf

https://github.com/akuroda/teradata-udf-sha2

а затем реализовать агрегатный XOR UDF.

На DevEx от Teradata был блог о сравнении таблиц:

http://developer.teradata.com/blog/ulrich/2013/05/calculation-of-table-hash-values-to-compare-table-content

Комментарии:

1. Вероятно, мне следовало упомянуть, что мне нужно, чтобы агрегированный результат был уникальным (именно поэтому агрегированный хэш был бы отличным). Когда я 1) выполняю ваш метод SUM для поля UPI в таблице с 10 тыс. строк, 2) группирую по родительскому внешнему ключу, а затем 3) подсчитываю суммированные результаты, я получаю некоторые коллизии. Я полагаю, что это тот же тип коллизии, который вы получите при добавлении 10, 30, 50, 70, чтобы получить 160, а затем возьмите совершенно разные числа 5, 35, 40, 80 и также получите 160. Я обновил свой ответ некоторым примером SQL.

2. Хммм… Интересно, будет ли работать «кумулятивный» хэш. По сути, генерируйте хэш, а затем хэшируйте этот хэш с помощью хэша предыдущей строки. Или, возможно, есть способ создать совокупный целочисленный массив, а затем передать этот массив hashrow() . Я просто думаю, на самом деле.

3. В ответ на ваше редактирование я знаю, что хэши не гарантированно уникальны, но я думаю, что суммирование случайных групп хэшей значительно увеличивает вероятность столкновения. Я только что использовал hashrow() для UPI в таблице с 11 тыс. записей, и каждая из них была уникальной, но суммирование групп этих хэшей привело к значительному количеству коллизий (см. Мой предыдущий пример 10,30,50,70). Во всяком случае, я думаю, мы можем сделать вывод, что ответ отрицательный, агрегатной хеш-функции не существует и что потребуется использовать какой-то другой метод, такой как UDFs, как вы предложили.