Обновить таблицу всеми записями из второй таблицы - PullRequest
0 голосов
/ 18 января 2020

Утро,

У меня есть две таблицы. Первая таблица (SecurityRules) - это список правил безопасности:

ID  srRight srRole
1   4       NULL    
2   2       32  

Вторая таблица (Projects) - это список проектов:

ProjId  prRight prRole
1       0       NULL
2       0       32
3       0       NULL

Мне нужно обновить список проецирует все записи из SecurityRules и обновляет столбец prRight на основе роли из обеих таблиц. Значения Right имеют побитовую организацию. Для этого я использовал SQL запрос на обновление:

Update  Projects
        -- Perform binary sum
Set     prRight = prRight | srRight
From    SecurityRules
Where   (srRole is Null)                            --Always apply srRight if srRole is not defined
        OR (srRole is Not Null And srRole=prRole)   --Apply right if both roles are equal

Ожидаемый результат:

ProjId  prRight prRole
1   4   NULL
2   6   32
3   4   NULL

Но я получаю:

ProjId  prRight prRole
1   4   NULL
2   4   32
3   4   NULL

Это похоже, что обновление выполняется только первой записью таблицы SecurityRules. И мне нужно применить все записи из таблицы SecurityRules ко всем записям таблицы Project. Если я создаю простой l oop и вручную зацикливаю все записи из SecurityRules, он работает нормально, но производительность очень низкая, если вам нужно сравнить 10 правил безопасности с 2000 проектами ...

Любое предложение ?

Арно

Ответы [ 2 ]

2 голосов
/ 18 января 2020

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

WITH Bits AS (
  SELECT 1 AS BitMask
  UNION ALL
  SELECT 2 * BitMask FROM Bits
  WHERE BitMask < 65536
),
NewRights AS (
  SELECT ProjId, SUM(DISTINCT BitMask) AS NewRight
  FROM Projects p
  JOIN SecurityRules s ON s.srRole IS NULL OR s.srRole = p.prRole
  JOIN Bits b ON b.BitMask & s.srRight > 0
  GROUP BY ProjID
)
UPDATE p
SET p.prRight = n.NewRight
FROM Projects p
JOIN NewRights n ON n.ProjId = p.ProjId 

Результирующая Projects таблица:

ProjId  prRight     prRole
1       4           null
2       6           32
3       4           null

Демонстрация на dbfiddle

0 голосов
/ 18 января 2020

Если я правильно понимаю, у вас есть прямое соответствие в столбце srRole, а затем правило по умолчанию, которое применяется ко всем.

Самый простой способ (в данном случае) - использовать join s в update:

update p
    Set prRight = p.prRight | srn.srRight | coalesce(sr.srRight, 0)
From Projects p join
     SecurityRules srn
     on srRole is null left join
     SecurityRules sr
     on sr.srRole = p.prRole;

Здесь - это db <> скрипка.

Возможно, вам будет безопаснее, если не использовать правило по умолчанию. И это prRight может быть NULL:

update p
    Set prRight = coalesce(p.prRight, 0) | coalesce(srn.srRight, 0) | coalesce(sr.srRight, 0)
From Projects p left join
     SecurityRules srn
     on srRole is null left join
     SecurityRules sr
     on sr.srRole = p.prRole;

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

...