2009-11-14 5 views
1

Prenez ce scénario: Vous avez quelques énumérations de drapeaux en C# liées à (et en fait générées à partir de) tables Enum-ish dans SQL Server. Supposons que vous êtes un distributeur et que vous autorisiez vos revendeurs à spécifier les États américains auxquels ils livrent. Être un ingénieur logiciel brillant et élégant, vous mis en œuvre ces comme une valeur de drapeau-combinables pour bitwise sauver stockage:Simule un entier non signé de 128 bits dans SQL et C# en utilisant une valeur signée 64 bits?

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 

Sweet. Vous pouvez inclure/exclure dynamiquement à la fois dans SQL et C# en utilisant la logique bit à bit, ce qui vous permet d'hydrater instantanément les listes de cases à cocher et de sélectionner des listes dans Asp.NET tout en n'enregistrant qu'un seul nombre de 64 bits. Et vous n'avez pas besoin d'un opérateur de comparaison non indexable dans les clauses WHERE de vos procédures, sauf par rapport à la table enum elle-même qui a un maximum de 64 lignes. La recherche de vos distributeurs pour tous ceux qui expédient vers l'Indiana et la Californie peut toujours utiliser une comparaison d'égalité et un index.

Vous avez maintenant une demande d'ajout de soutien pour les territoires américains, les codes postaux des forces armées et les provinces canadiennes, et ce, d'une manière rétrocompatible. Il n'y a pas de réduction de la liste à < 64 entrées, et l'entreprise vraiment veut éviter d'avoir à séparer les États de la vieille école du reste des territoires et des divisions.

Que faites-vous? Les réponses créatives sont appréciées, mais le véritable défi est le suivant: existe-t-il un moyen de forcer le même calcul binaire qui fonctionne sur des valeurs 64 bits non signées à travailler sur des valeurs signées tout en utilisant l'espace négatif pour dépasser 64 bits possibles , en C# et en SQL (2008)? Si c'est important, le drapeau est simulé, pas un drapeau "réel", donc techniquement il n'est pas nécessaire que cela fonctionne contre une énumération CLR avec l'attribut [Flags].

+1

Combinaisons oui, mais dans ce cas, une combinaison est comme un navire vers l'Indiana et la Californie, pas un seul État. De toute façon peut-être pourriez-vous essayer d'utiliser des GUID? Ils sont en fait des entiers de 128 bits. – kubal5003

+1

L'espace négatif est l'un des 64 bits, donc non. – Joe

+1

J'ai rencontré exactement le même problème. Comment utilisez-vous un GUID pour stocker des numéros? – arao6

Répondre

5

Vous ne pouvez pas dépasser 64 bits sur une valeur de 64 bits, sans même utiliser "l'espace négatif". Si vous avez 64 bits, vous avez 64 bits. Vous pouvez utiliser un Guid pour obtenir 128 bits, ce qui mettra le problème hors tension pendant un certain temps, mais vous devrez finalement ajouter des champs supplémentaires.

3

Dans SQL Server, vous pouvez essayer décimal (38,0)

Cela vous donne 38 chiffres à gauche du point décimal (1E38). En termes binaires, il s'agit d'environ 126 bits (8.5E37). Et il peut être manipulé comme un nombre. Cependant, une option consisterait à définir ce que vous voulez dans .NET et à utiliser une correspondance CLR data type dans SQL Server. De cette façon, il peut être cohérent entre les deux plates-formes.

Cependant, je voudrais vraiment envisager de changer loin de drapeaux ...

+0

Malheureusement, le type décimal n'est pas valide pour les opérateurs au niveau du bit. L'idée du type de données CLR est intéressante. J'étudierai si je peux retirer des drapeaux de 64 bits avec cet angle. En ce qui concerne les changements de drapeaux, je ne les utilise normalement que là où je suppose qu'une douzaine ou moins de valeurs possibles existent et il n'y a pas d'autre raison pour créer une relation plusieurs-à-plusieurs. J'ai aussi un outil qui génère automatiquement des requêtes indexables du côté SQL et contient des opérateurs du côté .NET pour eux, mais je limite leur utilisation aux instances où ils sont susceptibles d'économiser de l'espace et du temps de codage. –

1

Mon 2c: Vous essayez d'être intelligent, et votre cause de votre propre douleur. Bitfields et SQL ne se mélangent pas bien, principalement parce que les champs de bit ne peuvent pas être correctement indexés et que toute recherche devra faire un scan complet. Par exemple. pour trouver tous les reselers qui expédient à AK, vous devez scanner toute la table des reselers. De plus, la solution n'échelle pas à plus de 64 valeurs (comme vous l'avez déjà découvert). C'est aussi un mauvais choix de stockage, il faut un peu avec la valeur 0 pour stocker les informations négatives (manque d'association). Utilisez un tableau séparé pour modéliser la relation plusieurs-à-plusieurs entre les revendeurs et les états/territoires/provinces/pays dans lesquels ils sont livrés.

+0

Point pris. En ce qui concerne l'indexation cependant, les recherches ne nécessitent * pas * d'analyses de table sur la table des revendeurs. Il y a une analyse sur la table des états max 64-row pour construire la variable de table @ StateIDs indexée, qui contient la sortie de toutes les comparaisons au niveau du bit. (Ce travail pourrait effectivement être persisté aussi, mais ce n'est pas assez de ressource intensive pour la peine à ce point.) Le tableau @StateIDs var rejoint ensuite par la valeur à une clé étrangère de la table des revendeurs pour récupérer les matchs sans analyse de table. –

Questions connexes