2009-11-14 1 views
1

Возьмите этот сценарий: у вас есть несколько перечислений флагов в C#, связанных с (и фактически сгенерированными) таблицами Enum-ish в SQL Server. Скажите, что вы являетесь дистрибьютором, и вы разрешаете своим реселлерам указывать, в какие штаты США они отправляются. Будучи блестящим и элегантным инженером программного обеспечения, вы реализуете их в качестве значения флага побитового комбинируемых, чтобы сохранить память:Имитировать 128-разрядное целое число без знака в SQL и C# с использованием 64-разрядного знакового значения?

create table USState (
    StateID bigint, StateAbbr char(2), StateName varchar(50)) 
/* insert all US States + DC into USState, StateIDs must be in powers of two */ 
/* StateID 0 reserved for 'None': */ 
create procedure GetStatesByFlag (@StateFlags bigint) as 
declare @StateIDs table 
(
StateID bigint, 
primary key (StateID) 
) 
insert into @StateIDs 
    select StateID 
    from USState 
    where @StateFlags & StateID != 0 
     or (@StateFlags = 0 and StateID = 0) 

select s.StateID, s.StateAbbr, s.StateName 
from 
    USState s join 
    @StateIDs si 
    on si.StateID = s.StateID 

помадка. Вы можете включать/исключать динамически как в SQL, так и в C# с помощью побитовой логики, которая позволяет мгновенно убрать списки флажков и выбирать списки в Asp.NET, сохраняя при этом только одно 64-разрядное число, чтобы сохранить любую комбинацию выбранных. И вам не нужен неиндексируемый оператор сравнения в ваших процедурах. Предложения WHERE, за исключением самой таблицы перечислений, которая имеет максимум 64 строки. Поиск ваших дистрибьюторов для всех, кто отправляется в Индию и Калифорнию, по-прежнему может использовать сравнение равенства и индекс.

Теперь у вас есть просьба добавить поддержку территорий США, коды почтовых отправлений вооруженных сил и провинций Канады и сделать это в обратном порядке. Там нет резки списка до < 64 записей, а бизнес действительно хочет избежать необходимости отделять государства старой школы от остальной территории и подразделений.

Что вы будете делать?

Творческие ответы приветствуются, но настоящая проблема заключается в следующем: существует ли способ заставить одну и ту же побитовую математику, которая работает с 64-разрядными значениями без знака, работать на подписанных, используя отрицательное пространство, чтобы превысить 64 возможных бита , как в C#, так и в SQL (2008)? Если это имеет значение, флаг моделируется, а не «реальный» флаг, поэтому технически не обязательно, чтобы это работало против перечня CLR с атрибутом [Flags].

+1

Комбинации да, но в этом случае комбинация похожа на корабль в Индиану и Калифорнию, а не на одно государство. В любом случае, возможно, вы можете попробовать использовать GUID? Они на самом деле 128-битные целые числа. – kubal5003

+1

Негативное пространство - это только один из 64 бит, поэтому нет. – Joe

+1

Я столкнулся с той же проблемой. Как вы используете идентификатор GUID для хранения чисел? – arao6

ответ

5

Вы не можете превышать 64 бит по 64-битовому значению, даже не используя «отрицательное пространство». Если у вас 64 бит, у вас есть 64 бит. Вы можете использовать Guid, чтобы получить 128 бит, что помешает проблеме на некоторое время, но в конечном итоге вам нужно будет добавить дополнительные поля.

3

В SQL Server, можно попробовать десятичное (38,0)

Это дает вам 38 цифр слева от десятичной точки (1E38). В двоичных выражениях это около 126 бит (8.5E37). И его можно манипулировать как число.

Однако одним из вариантов было бы определить, что вы хотите в .NET, и использовать соответствующий код CLR data type в SQL Server. Таким образом, это может быть согласовано между двумя платформами.

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

+0

К сожалению, десятичный тип недействителен для побитовых операторов. Идея типа CLR интересна; Я исследую, могу ли я снять> 64-битные флаги с этим углом. Что касается перехода от флагов, я обычно использую их только там, где я ожидаю, что существует дюжина или меньше возможных значений, и нет другой причины для создания отношения «многие ко многим». У меня также есть инструмент, который автоматически генерирует индексируемые запросы на стороне SQL и содержит для них операторы на стороне .NET, но я ограничиваю их использование экземплярами, где они, вероятно, будут сохранять как пространство, так и время кодирования. –

1

Моего 2са: Вы пытаетесь быть умными, и ваша причина вашей собственной боли. Битфилды и SQL не очень хорошо смешиваются, прежде всего потому, что битовые поля не могут быть правильно проиндексированы, и любой поиск должен будет выполнить полное сканирование. Например. чтобы найти всех реселлеров, отправляющихся в АК, вам нужно отсканировать всю таблицу реселлеров. Также решение не масштабируется до более чем 64 значений (как вы уже обнаружили). Это также плохой выбор памяти, для хранения отрицательной информации (отсутствия связи) требуется бит со значением 0.

Используйте отдельную таблицу, чтобы смоделировать отношения «многие-ко-многим» между реселлерами и штатами/территориями/провинциями/странами, куда они отправляются.

+0

Точка взята. Что касается индексирования, поиск делает * not * требует сканирования таблиц в таблице реселлеров. Существует одно сканирование в таблице максимальных состояний из 64 строк, чтобы построить переменную таблицы indexed @ StateIDs, которая содержит вывод всех побитовых сравнений. (Эта работа также может быть сохранена, но она недостаточно ресурсоемкая, чтобы беспокоиться об этом.) Таблица @StateIDs var затем объединяется по значению в внешний ключ таблицы реселлеров для получения совпадений без сканирования таблицы. –