OK, ako mozes da menjas tip podatka po volji, znaci da si jos u fazi projektovanja tabele. To znaci da su i druge izmene dozvoljene. prelozio bih jos jednu - kolona Kolicina ti ne treba. Vidim fda je kolicina izracunata vrednost, Kolicina = DoBroja - OdBroja + 1. Predlazem da za sada radimo sa ovakvim dizajnom:
Code:
--- izmenjena tabela:
IF OBject_ID('[InterniMagacin]') IS NOT NULL DROP TABLE [InterniMagacin]
GO
CREATE TABLE [dbo].[InterniMagacin](
[id] [bigint] IDENTITY(1,1) NOT NULL,
[TipKarte] [nvarchar](3) NOT NULL,
[OdBroja] int NOT NULL,
[DoBroja] int NOT NULL,
--[Kolicina] [int] NOT NULL,
[Status] [int] NULL,
[UserName] [nvarchar](4) NOT NULL,
[DatumVreme] [datetime] NOT NULL,
CONSTRAINT [PK_InterniMagacin] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF
, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON
, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
)
Insert into InterniMagacin VALUES ('ZZ1',100,199,0,'user',getdate())
Insert into InterniMagacin VALUES ('ZZ1',450,589,0,'user',getdate())
Insert into InterniMagacin VALUES ('ZZ1',780,800,0,'user',getdate())
SELECT TipKarte, OdBroja, DoBroja, Kolicina = DoBroja - ODBroja +1 , Status
FROM [InterniMagacin]
/* Rezultat:
TipKarte OdBroja DoBroja Kolicina Status
-------- ----------- ----------- ----------- -----------
ZZ1 100 199 100 0
ZZ1 450 589 140 0
ZZ1 780 800 21 0
*/
(3 row(s) affected)
Rezultat je isti kao sto smo imali dok je kolona Kolicina bila u tabeli. Da se razummemo, ni ovo nije verovatno najbolji dizajn, nije verovatno ni dobar, ali cemo se z atrenutak zadrzati, koliko d apokazemo kako se u ovakvom slucaju proverava da li se ponudjeni opseg brojeva preklapa sa nekim od postojecih. to si pitaona pocetku. A na kraju cemo da predlozimo kako treba da izgleda tabela, ili skup tabela za tvoj slucaj.
Elem, data je dakle tabele sa kolonama OdBroja, DoBroja koje cuvaju pocetnu i poslednju vrednost u nekom neprekidniom i kompletnom nizu brojeva, kao sto smo je upravo napravili. Kako proveriti da li neki novi opseg brojeva vec postoji u tabeli, ceo ili bar neki njegov deo? Ovde se radi o poredjenu dva intervala. Nazovimo ih (a,b) i (OdBroja, DoBroja). Ta dba intervala mogu da imaju sledece polozaje na brojnoj osi:
Code:
----- a ----- b ------ OdBroja -------- DoBroja -------> ova dva se ne preklapaju uopste
----- a ------ OdBroja ---- b ---- DoBroja ------------> preklapanje, bar jedan deo (a,b) se poklapa sa (OdBroja, DoBroja)
----- a ------ OdBroja ---- a ----- b ---- DoBroja -----> (a,b) je potpuno unutar (OdBroja, DoBroja) => preklapanje
----- a ------ OdBroja -------- DoBroja ----- b -------> (OdBroja, DoBroja) potpuno unutar (a,b) => preklapanje
----------- OdBroja ---- a ---- DoBroja ------ b ------> delimicno preklapanje
----- OdBroja -------- DoBroja ----a ----- b ------ ---> ova dva se ne preklapaju uopste
Moguci su i slucajevi kada se a ili b poklapa sa tackama OdBroja do Broja, sto pretpostavljam nije dozvoljeno.
Moguce je napisati rogobatan izraz koji ce da sadrzi sve moguce slucajeve, ali nema potrebe.
Jedna dva slucaja koja dozvoljavamo su prvi i poslednji - kada je (a,b) potpuno izvan intervala (OdBroja, DOBroja).
Ovo se moze zapisati kao:
b < OdBroja OR a> DoBroja (vece ili jednako i manje ili jednako ne dolaze u obzir)
Znaci, ako ima sinterval (a,b) i zelis da vidis da li se preklapa sa nekim od postojecih intervala u tabeli, treba da proveris da li je tacno
b < OdBroja OR a> DoBroja
Ako je ovo tacno, intervali se ne preklapaju. Ako nije tacno, intervali se preklapaju i INSERT nije dozvoljen.
Primer, sa postojeciom tabelom i postojecim podacima, koje smo dali na pocetku.
Prva dva primera pokazuju preklapanje, poslednji interval nema preklapanje.
Code:
DECLARE @a int, @b int
SELECT @a = 150, @b = 250
-- Pokazi intervale koji se preklapaju sa (@a,@b)
SELECT
TipKarte, OdBroja, DoBroja, Status
FROM [InterniMagacin]
WHERE NOT (@b < OdBroja OR @a>DoBroja)
TipKarte OdBroja DoBroja Status
-------- ----------- ----------- -----------
ZZ1 100 199 0
DECLARE @a int, @b int
SELECT @a = 50, @b = 1200
-- Pokazi intervale koji se preklapaju sa (@a,@b)
SELECT
TipKarte, OdBroja, DoBroja, Status
FROM [InterniMagacin]
WHERE NOT (@b < OdBroja OR @a>DoBroja)
TipKarte OdBroja DoBroja Status
-------- ----------- ----------- -----------
ZZ1 100 199 0
ZZ1 450 589 0
ZZ1 780 800 0
DECLARE @a int, @b int
SELECT @a = 250, @b = 400
-- Pokazi intervale koji se preklapaju sa (@a,@b)
SELECT
TipKarte, OdBroja, DoBroja, Status
FROM [InterniMagacin]
WHERE NOT (@b < OdBroja OR @a>DoBroja)
TipKarte OdBroja DoBroja Status
-------- ----------- ----------- -----------
(0 row(s) affected)
Znaci, ako kveri kao u primeru vrati neke redove - ti redovi se preklapaju sa zadatim intervalom.
Ako ne vrati nista, interval je dobar. Ako imas stored proceduru koja kontrolise INSERT u tabelu InterniMagacin, onda treba da proveris broj redova koje vraca kveri koji smo pokazali. Ovako nekako:
Code:
-- Izvrsi celu skriptu, do znaka ;
DECLARE @a int, @b int
DECLARE @count int
SELECT @a = 50, @b = 1200
-- Pokazi intervale koji se preklapaju sa (@a,@b)
SET @Count = (SELECT COUNT(*)
FROM [InterniMagacin]
WHERE NOT (@b < OdBroja OR @a>DoBroja)
)
IF @Count > 0 -- ako imamo preklapanje, ispis poruku
BEGIN
Print 'Zadati interval se preklapa sa nekim od postojecih intervala'
RETURN ---- prekini dalje izvrsavanje koda
END
---- ovo ce se izvrsiti ako i samo ako je @Count = 0
BEGIN
Insert into InterniMagacin VALUES ('ZZ1',@a,@b,0,'user',getdate())
END
; --- skriptu izvrsi dovde
-- proveri sta se desilo:
/*
SELECT TipKarte, OdBroja, DoBroja, Kolicina = DoBroja - ODBroja +1 , Status
FROM [InterniMagacin]
*/
-- Sad jedan koji prolazi:
-- pocetak skripte (ova treba da prodje)
DECLARE @a int, @b int
DECLARE @count int
SELECT @a = 250, @b = 400
-- Pokazi intervale koji se preklapaju sa (@a,@b)
SET @Count = (SELECT COUNT(*)
FROM [InterniMagacin]
WHERE NOT (@b < OdBroja OR @a>DoBroja)
)
IF @Count > 0 -- ako imamo preklapanje, ispis poruku
BEGIN
Print 'Zadati interval se preklapa sa nekim od postojecih intervala'
RETURN ---- prekini dalje izvrsavanje koda
END
---- ovo ce se izvrsiti ako i samo ako je @Count = 0
BEGIN
Insert into InterniMagacin VALUES ('ZZ1',@a,@b,0,'user',getdate())
END
; -- karj skripte
-- Rezultat:
/*
SELECT TipKarte, OdBroja, DoBroja, Kolicina = DoBroja - ODBroja +1 , Status
FROM [InterniMagacin]
TipKarte OdBroja DoBroja Kolicina Status
-------- ----------- ----------- ----------- -----------
ZZ1 100 199 100 0
ZZ1 450 589 140 0
ZZ1 780 800 21 0
ZZ1 250 400 151 0
(4 row(s) affected)
*/
Tako nekako. Medjutim ,rekoh da ni ovo nije dobar dizajn. Problem je sto sav insert moar da ide kroz stored proceduru koju en razumes bas najbolje i nisi siguran da mozes da je napravis. A nema garncije da ce INSERT uvek ici kroz stored proceduru. Boje bi bilo da postoji neki CONSTRAINT. Moguce je napisati CONSTRAINT koji radi ovako kao sto smo opisali, ali to nije lako. Zahteva pisanje korisnicke funkcije koja s epoziva iz CHECK CONSTRAINT. Primer sa CHECK CONSTARINT i UDF funkcijom imas ovde
http://www.baze-podataka.net/2...nstraint-sql-rezervacija-soba/ Primer je o rezervaciji soba - ne dozvoljva se da se rezervise soba u intervalu kad je soba zauzeta. Veoma slicno ovome sto ti radis, pa vidi.
Medjutim, prava stvar bi bila da se potpuno promeni dizajn tabele. Ako umesto intervala pamtis sve brojeve, tabela bi zigledala otprilike ovako:
Code:
TipKarte BrojKarte
ZZ1 100
ZZ1 101
ZZ1 102
....
ZZ1 199
ZZ1 450
ZZ1 451
ZZ1 452
.....
ZZ1 588
ZZ1 589
.....
Onda je dovoljno da kazes BRojKarte NOT NULL UNIQUE.
To ce te spreciti da uneses duplikate. I ne treba ti sva ova komplikacija. Kako da vidis koji brojevi su duplikati/ Upotrebi tabelu brojeva....., to je za neku drugu temu, a mislim da smo o tome pisali negde na ovom ili SQL forumu, a imas i ovde
http://sqlserver2000.databases...n-auxiliary-numbers-table.html
Nadam se da je pomoglo.
:-)