2010-07-09 5 views
1

est-il possible de créer une identité par mois? essentiellement ce que j'ai besoin estsql par mois identité

create table 
(
id identity primary key 
regDate DateTime not null, 
regDateNumber int not null 
) 

et quand j'insérer des données que je besoin de définir la regDateNumber comme une identité dans le cadre du mois

du regDate comme ceci:

id regDate regDateNumber 
1 1 jan 2008 1 
2 3 jan 2008 2 
3 7 jan 2008 3 
4 1 feb 2008 1 
5 1 feb 2008 2 
6 1 aug 2008 1 
7 1 aug 2008 2 
8 1 sep 2008 1 
9 1 sep 2008 2 

Répondre

1

Je crois que vous pouvez le faire en utilisant une procédure stockée:

CREATE PROCEDURE month_indentity 
    @myInput DateTime 
AS 
SELECT COUNT(*) + 1 FROM mytable 
WHERE MONTH(regDate) = MONTH(@myInput) 
    AND YEAR(regDate) = YEAR(@myInput) 
GO 
+0

c'est comment je pourrais calculer la valeur dans un SP pour l'insertion, je crois que le verrouillage de table est nécessaire pour cela? cela peut-il arriver s'il y a 2 appels à ce sp en même temps, puis-je obtenir 2 enregistrements avec la même valeur pour regDateNumber – Omu

+0

Je ne pense pas que cela fonctionnera correctement dans un environnement de serveur occupé - vous finirez par avec des valeurs en double pour votre "month_identity" puisque vous ne regardez pas du tout la concurrence ici ..... –

2

Vous ne pouvez pas faire avec l'identité, de sorte que vous pouvez calculer à la volée. Quelque chose comme:

select id, regDate, 
row_number() over(partition by year(regDate), month(regDate) as regDateNumber order by id) 
from t 
+0

effectivement je n'ai pas besoin de partitionner à la volée lors de la sélection, j'ai besoin de calculer quand je fais l'insertion – Omu

+2

Vous pouvez essayer de le faire avec un déclencheur. Je ne le conseille pas, car il est très sujet aux erreurs. Peut-être que si vous décrivez comment utiliser ce champ, nous trouverons une meilleure solution – burnall

2

Vous pouvez simplement ajouter une colonne calculée à votre table:

ALTER TABLE dbo.YourTable 
    ADD regMonth AS MONTH(regDate) PERSISTED 

et être fait avec elle. Cela sera calculé, persistant (par exemple, non recalculé à chaque accès, mais seulement lorsque regDate changements), contient les informations MONTH pour la date, et peut même être indexé pour la vitesse.

Mise à jour: ok, donc maintenant je comprends - votre "identité par mois" est un peu flou et trompeur. Qu'est-ce que vous voulez est de numéroter séquentiellement les entrées pour chaque mois, non?

Une façon de le faire ne le fait pas/ne le stocke pas, mais en utilisant l'approche burnall avec la fonction ROW_NUMBER().

Sinon, vous devez faire un déclencheur AFTER INSERT qui calcule la nouvelle valeur sur INSERT - mais cela devient a) désordonné et b) vous coûtera pas mal de performance quand vous faites beaucoup d'insertions.

Ma recommandation serait d'utiliser la fonction de burnall et de laisser cette fonction s'exécuter par exemple. une fois par heure environ pour mettre à jour ces champs. N'essayez pas de comprendre cela à la volée, sur INSERT - votre performance sera terrible.

+0

comment cela va-t-il m'aider à générer le regDateNumber quand je fais l'insertion? – Omu

+0

mais j'ai besoin d'une identité par mois, pas seulement un mois – Omu

+0

Je dois le mettre sur l'insertion parce que si quelqu'un va supprimer des enregistrements, je devrais obtenir une liste ou des enregistrements comme 1,2,5,6 au lieu de 1,2,3 , 4 (dans votre cas) – Omu

1
create table #table (iid int identity (1, 1), dy int, mth varchar(3)) 

insert into #table (dy, mth) 
select 1, 'jan' union all 
select 2, 'jan' union all 
select 20, 'jan' union all 
select 10, 'jan' union all 
select 1, 'feb' union all 
select 3, 'feb' union all 
select 28, 'feb' 

select T.dy, T.mth, 
    (select count(X.iid) from #table X where X.mth = T.mth and X.iid < T.iid) + 1 as month_rank 
from #table T 
order by T.mth, month_rank 

je ne voudrais pas stocker la valeur comme un champ calculé car il peut changer au fil du temps et il constitue une violation des règles de normalisation.