» »

[T-SQL] Kako vnest podatek v bazo in da ti hkrati vrne id?

[T-SQL] Kako vnest podatek v bazo in da ti hkrati vrne id?

Microsoft ::

Skratka. Sedaj mam jst nareto tako, da grem v bazo in preberem najvecji id (SELECT MAX (id) FROM Tabela). Zatem pa uporabim ta id (pristejem mu se 1) pri insertanju podatkov v nov rov.

Samo sem ze enih parkat videl, da se lahko ta id sam generira. Nastavi se mu increment in seed. To je kul. Samo tu me zdej zaminata dve stvari.

- Ko insertas podatke, pri tem pa izpustis id? Naprimer, v tabelo z dvema stolpcema (id, ime) bi potem moglo iti takole: INSERT INTO Tabela (ime) VALUES @ime. Al je kako drugace?
- In potem drugo. Kako dobit id, katerega je baza zdej naredila za ta nov vnos? Ker ta id pride kar prav, da se znas potem sklicevat na pravkra vnesene podatke z idjem.


by Miha
s8eqaWrumatu*h-+r5wre3$ev_pheNeyut#VUbraS@e2$u5ESwE67&uhukuCh3pr

MaCoFaCo ::

Microsoft ::

Sweet & tnx


by Miha
s8eqaWrumatu*h-+r5wre3$ev_pheNeyut#VUbraS@e2$u5ESwE67&uhukuCh3pr

frudi ::

pazi, če lahko več uporabnikov hkrati dostopa do baze! v tem primeru se lahko doda nov zapis, preden ti prebereš @@IDENTITY, ki se je zgeneriral po tvojem insertu. v takem primeru uporabi transakcijo ali pa vsaj zakleni tabelo.
tudi če imaš kak trigger, ki piše v kako drugo tabelo z identity stolpcem, boš dobil nazaj 'napačno' vrednost.
1ACDoHVj3wn7N4EMpGVU4YGLR9HTfkNhTd... in case I've written something useful :)

Microsoft ::

Hm, ce prav razumem. Najprej vneses nov vnos v bazo, takoj za tem pa se en drug vnese nov vpis v bazo (oba prakticno v istem trenutku), a oba boma dobila nazaj id od zadnjega vnosa.

Ok. Zdej tale transakcija je men tolko znana, da zagotavlja, da se serija (ali pa tudi en sam) vnosov zapise v bazo izvede v celoti ali pa cisto nic. Samo ne vem, kako bi mi tole pomagalo pri tem, da ne bi dobil napacnega idja nazaj? Kaj, a takrat ko se ta transakcija izvaja na dolocenih tabelih, so te zaklenjene al kaj?


by Miha
s8eqaWrumatu*h-+r5wre3$ev_pheNeyut#VUbraS@e2$u5ESwE67&uhukuCh3pr

frudi ::

ja, tabele, na katerih izvajaš operacije, so med transakcijo načeloma zaklenjene. tako se ti ne more zgoditi, da nekdo vnese še eno vrstico, dokler ti ne zaključiš svoje transakcije.
zdaj, če nimaš izkušenj s transakcijami, potem se jih loti zelo previdno; nezaključene transakcije lahko naredijo še in još štale, tako da presneto pazi, da jih sproti potrjuješ ali zavračaš (to pomeni, da moraš poskrbeti za vse transakcije tudi, če se tvoja aplikacija vsuje ali se ji zgodi kaj podobno nepričakovanega).

kar se pa triggerjev tiče, pa se ti sprožijo takoj po vnosu vrstice v tabelo. če bi torej imel na serverju funkcijo, ki bi vsebovala naslednjo kodo:

INSERT INTO dbo.tabela (stolpec2, stolpec3, stolpec4) VALUES(@x2, @x3, @x4) --recimo, da je stolpec1 identity, zato ga ne vnašamo eksplicitno
RETURN @@IDENTITY

in bi na tabeli 'dbo.tabela' imel definiran FOR INSERT trigger, ki bi pisal v neko drugo tabelo z identity stolpcem, bi se ta trigger izvedel pred RETURN @@IDENTITY vrstico. tako bi se po sprožitvi triggerja @@IDENTITY spremenil in tako ne bi dobil IDja, ki se je zapisal v dbo.tabela!

ampak to s triggerji je specifičen primer in če nimaš na tej tabeli nobenega triggerja, ki bi sam pisal v kako tabelo z identity stolpci, se glede tega ne rabiš sekirat.
1ACDoHVj3wn7N4EMpGVU4YGLR9HTfkNhTd... in case I've written something useful :)

darkolord ::

Če uporabiš stored procedure, potem ti afaik ni treba delat novega selecta za @@identity

BigWhale ::

Trik je v tem, da tisti auto_increment key ki ga baza sama generira uporabljas za nekaj drugega, ce ga sploh.

Sam pa dolocis svoj primary key na bazi, ki ga zgeneriras vsakic sproti preden vnasas stvar v bazo. Kako prepreciti, da bi imel dva enaka vnosa. Prvo kot prvo itak baza ne pusti vnesti dveh enakih kljucev. Ce se to slucajno zgodi pac error ulovis in popravis kljuc. Se pred tem pa pazis, da imas kljuc vedno dovolj pametno sestavljen. Recimo

Datum-username-random-stevilka

Tako se bo redko kdaj zgodilo, da bosta dva uporabnika hkrati vnesla v bazo isti kljuc oziroma se ne bo zgodilo to.

BigWhale ::

Aja, pa ker kljuc sam zgeneriras, ti potem tudi baze ni treba sprasevati po njem, ko te zanima kaj si ravnokar vnesel. To ze ves.

frudi ::

vse lepo in prav, ampak zaradi hitrosti je boljše imeti clustered indekse na int poljih, zaradi manšje fragmentacije pa je boljše, da so ti id-ji lepo zaporedni. in clustered indeks je običajno kar primarni ključ, razen če imaš dober razlog, da ga postaviš drugam.

se pa strinjam - izogibaj se identity stolpcev. raje pred zapisovanjem pogledaš, koliko je max id, prišteješ 1 in to je id za tvojo novo vrstico. tako vnaprej veš, kakšen id bo dobila, hkrati pa imaš vrstice vpisane z lepo zaporednimi id-ji (razen tistih, ki jih vmes izbrišeš seveda).
da si še na varnem, zadevo lepo zaviješ v transakcijo, tako da po tem, ko že prebereš max id, tega pred zapisom ne naredi še kdo drug.
1ACDoHVj3wn7N4EMpGVU4YGLR9HTfkNhTd... in case I've written something useful :)

MaCoFaCo ::

Dosti priročno je če je polje id v bazi namesto tipa int, kar tipa uniqueidentifier (vsaj za MS SQL vem da ima ta tip). Pri SQL insertu lahko to vrednost izpustiš in ti sistem samodejno generira unique id, lahko pa ga generiraš sam v kodi s pomočjo funkcije System.Guid.NewGuid() in na ta način odpadejo tisti problemi z @@IDENTITY in transakcijami.

Microsoft ::

Ok, bom jst tole v naslednjih dneh malo precekiral, da vidim, kako kaj te resitve delajo.

Je pa takole. Koncal sem en mini projekt, ki je za interno uporabo, je na Access bazi, gor pa ene 5 uporabnikov. Zdej mam pa za naprej, da naredim dolocene stvari odprte navzven. Gre za narocanje, tako da bodo lahko drugi prisli na internetno stran, se registrirali, potem bo eden iz podjetja kontaktiral registriranega in potrdil, da ni ko kaka zajebancija. Sledi to, da se lahko ta oseba prijavi gor, spreminija svoje podatke, in pa seveda doda novo narocilo. Premisljujem o neke wizardu, ki bo sel tako step by step in vodil stranko.
Pri tem se spremeni to, da bo baza SQL 2005 Express. Sem samo na hitro preletel in ima ta baza kar dosti uporabnih stvari, ki jih Access nima. In zdej bi rad naredil neko tako bazo, da bo to dobra osnova za naprej, da ne bo prisli do napak pri vnosih, da bodo vkljucene procedure (ne pa tko, kot zdej, ko je sql stavek kar v kodi napisan:8)) in podobno.

Mi lahka svetujete kake osnovne smernice glede varnosti, procedur, nacin vnasanja in spreminjanja podatkov in podobno? Upam, da bom v nekaj dneh naredil osnovno bazo, pa jo lahko poslikam in potem pokomentiramo skupaj. Slo bo za dosti podobno bazo oz. model baze, kot je ze sedaj, s tem da bodo prisli kaki novi stolpci za dodatne informacije.

Imam se tudi en problem, ki ga tezko resujem ze sedaj. Stranka recimo zeli nekaj novega, za kar je potrebno dodat nov stolpec, da se ta informacija shrani. To mi potem naredi cel hlev, ker moram kar na dosti krajih popravljat kodo. Nekako nimam toliko izkusenj z izdelavo genericne kode, ki potem nima tezav prebavit se en dodaten stolpec, recimo.
Sicer mi je za iskanje kar dobro uspelo. Imam tako, da v bazi spremenim, po katerih stolpcih se da iskat in katere stolpce ti vrne. Tako, da koda ostane ista, spremenijo se le podatki v bazi. Kar je dosti lazje. Samo novi stolpci so se vedno problem.


by Miha
s8eqaWrumatu*h-+r5wre3$ev_pheNeyut#VUbraS@e2$u5ESwE67&uhukuCh3pr

Zgodovina sprememb…

OwcA ::

Imam se tudi en problem, ki ga tezko resujem ze sedaj. Stranka recimo zeli nekaj novega, za kar je potrebno dodat nov stolpec, da se ta informacija shrani. To mi potem naredi cel hlev, ker moram kar na dosti krajih popravljat kodo. Nekako nimam toliko izkusenj z izdelavo genericne kode, ki potem nima tezav prebavit se en dodaten stolpec, recimo.

Na en, dva, tri se je dober design težko naučiti. Najlažje in najhitreje boš to osvojil, če ti za začetek nekdo drug naredi design, ti pa ga le implementiraš.
Drugače je literature o generičnem programiranju, design vzorcih, objektinh paradigmah,... ogromno.
Otroška radovednost - gonilo napredka.

Microsoft ::

Ok. Imam dva nova vprasanja.

Prvo je problem, da mi ena procedura v SQLu ne locuje med velikimi in malimi crkami, ko jih primerja. Pa bi si zelel, da jih. Gre za preverjanje uporabniskega imena in gesla. Procedura je cisto preprosta in gre takole:
ALTER PROCEDURE [dbo].[SelectCountZaposleni]
@Uime nvarchar(255),
@Geslo nvarchar(255)
AS
BEGIN
SET NOCOUNT ON;
SELECT COUNT(id) [count] FROM Zaposleni
WHERE [Uime] = @Uime AND [Geslo] = @Geslo
END

Zdej, kaj bi moral spremeniti, da bi tole locevalo med velikimi in malimi crkami?

Drugo pa je, recimo pri proceduri, ki je dosti podobna tejle, le da gre za insert ali update t-sql, imam tako, da vneses nekaj parametrov, katere potem uporabis pri insert ali update. Zanima pa me, ce recimo pred koncem procedure (vrstica nad END) dodam RETURN @@error. Bom dobil prav error nazaj in kak error bo to? Ker, recimo da se zgodi, da vnesem tak vnos, pri katerem je podvojen PRIMARY KEY, bo prislo do errorja. Jst bi pa pri vnosu rad, da mi procedura vrne 1, ce je bil vnos vnese, ali pa kaj drugega, a se vedno berljivega, da bom vedel, da ni prislo do vnoso in priblizno zakaj ne.


by Miha
s8eqaWrumatu*h-+r5wre3$ev_pheNeyut#VUbraS@e2$u5ESwE67&uhukuCh3pr

Zgodovina sprememb…

frudi ::

za prvi primer:
najprej poglej, kako imaš nastavljen collation svoje baze. očitno je nastavljen na case insensitive; recimo, da imaš Slovenian_CI_AS. v selectih lahko za vsak char, varchar in nvarchar stolpec posebej definiraš collation, tako da se uporabi ta specificiran in ne default. v tvojem konkretnem primeru bi zadevo spremenil recimo takole:

WHERE [Uime] COLLATE Slovenian_CS_AS = @Uime AND [Geslo] COLLATE Slovenian_CS_AS = @Geslo

seveda pa prvo poglej, kakšen collation imaš dejansko nastavljen, nato pa v where pogoj vstavi isti collation, le da _CI_ zamenjaš s _CS_.


pri drugem primeru pa po insertu enostavno preveri vrednost @@ERROR - če je 0, je vnos uspel, če je karkoli druga, ni uspel. lahko pa iz tega, koliko je @@ERROR tudi izveš, do dakšne napake je prišlo - recimo 2627 je ravno primary key violation.
1ACDoHVj3wn7N4EMpGVU4YGLR9HTfkNhTd... in case I've written something useful :)

Microsoft ::

Tole cisto kul dela. Collation je na nivoju baze nastavljen na Slovenian_CI_AS, ce ga poskusam spremenit na Slovenian_CS_AS, pa ne spremeni ampak dobim en error. Bo treba kar v kodi tole pisat, ce bom kje rabil. Vseeno hvala!


by Miha
s8eqaWrumatu*h-+r5wre3$ev_pheNeyut#VUbraS@e2$u5ESwE67&uhukuCh3pr

dmok ::

pazi, če lahko več uporabnikov hkrati dostopa do baze! v tem primeru se lahko doda nov zapis, preden ti prebereš @@IDENTITY, ki se je zgeneriral po tvojem insertu. v takem primeru uporabi transakcijo ali pa vsaj zakleni tabelo.


To ni problem, @@IDENTITY namreč vrne "last identity value generated in any table in the current session". Uporaba transakcije pri "single" insertih pa je po mojem večinoma nepotrebno trošenje sistemskih sredstev.

d.


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

[SQL] primary key inkrementalno dodajanje (strani: 1 2 )

Oddelek: Programiranje
514610 (3800) ejresnevem
»

[C#] kako dobiti ID iz podatkovne baze

Oddelek: Programiranje
61023 (963) iggy1
»

postgreSQL trigger

Oddelek: Programiranje
51405 (1315) WarpedGone
»

MySQL in czs

Oddelek: Izdelava spletišč
423486 (2576) krho
»

Izvorna koda mojega par dnevnega dela; ce jo malo pokomentirate :) (strani: 1 2 )

Oddelek: Programiranje
606152 (4497) Microsoft

Več podobnih tem