::: MS SQL 2000 trikid ja nipid

Autor: Ingmar Tammeväli   tingmar<.a.t. >starman.ee


Üldiselt hakkasin uuemaid trikke oma blogis kirjeldama (title algab seal enamasti MSSQL : ) Blogi link

Tänud ka inimestele, kes teavitavad mind võimalikest vigadest

Sisukord:


* MSSQL 2005 - exceptionid / märkused

Lõpuks tuli ka see aeg, kus MSSQL sai omale normaalse veahalduse. Varem erilisi päästerõngaid nagu polnud (@@error muutuja siiani olemas).

Süntaks siis:

begin try
   raiserror 99999 'Nii tekitame vea'
end try
begin catch
   select error_number() as veanumber,
   -- Märkus: error_procedure kasulik muutuja, hea debugimisel, et teada saada süsteemselt, kus protseduuris viga tekkis.
             error_procedure() as vproc,
             error_line() as rida,
             error_message() as sonum
end catch

Märkused: kahjuks MSSQL 2005 natuke tekitas ka pettumust, indeksi max suurus(varchar/char) on 900 märki,nvarchar(450).
Südamest lootsin, et ehk jõutakse vähemalt 2048 märgini. Ebameeldiv on see, et varchar(1024) saab indeksit luua, aga kui sinna tabelisse lisada kirje,
mis on >=991 märki, siis seda kirjet ei sisestata.

Üks muudatus samuti, et enam "ametlikult" text/ntext muutujat ei toetata, nende asemel nüüd: varchar(MAX), nvarchar(MAX).


Kuna pidevalt suur kiire, siis hetkel pole aega formateerida, siia panen mõne vajaliku SQL koodi:

Asjad, mida minult küsitud:

* Kuidas teada saada kohaliku aja erinevust GMT ajast tundides?

select datediff(hh,GETUTCDATE(),getdate())

* Kuidas konverteerida ajaformaat stringi kujule dd.mm.yyyy või (odbc str )yyyy-mm-dd ?

select convert(char(10),getdate(),120),convert(char(10),getdate(),104)





* CTE, mis loom see on veel


Kõige lihtsam oleks vist öelda, ajutine resulset, mille skoop kehtib kuni järgmise SQL lauseni(kaasa arvatud).

Näide:

declare @at table(id int identity(1,1),sona varchar(255))
insert into @at(sona)
values('maasika')
 
insert into @at(sona)
values('jäätis')
 
insert into @at(sona)
values('on')
 
insert into @at(sona)
values('hea')


WITH ajutineRez(sona) as
(
 select sona
 from @at
 where sona in ('jäätis','hea')
)

select * from ajutineRez
-- select * from ajutineRez näiteks nüüd uuesti sqli välja kutsudes saame vea, et tabelit pole, sest skoop lõppes.



Milleks, CTE kasulik on...parim suurte päringute tükeldamiseks.



* COALESCE ja ISNULL, mis on nende erinevus

Näiteks:

select 'Töö telefon : '+telefon+'; Mobiil: '+mobiil+';' as telefonid
from mingitabel


Nüüd, kui telefon või mobiil sisaldab NULL väärtust, oleks selle kirjet kogu väärtuseks samuti NULL.

select 'Töö telefon : '+isnull(telefon,'puudub')+'; Mobiil: '+isnull(mobiil,'puudub')+';' as telefonid
from mingitabel


Nüüd, kui telefon puudub, on ka asendatakse NULL väärtus "puudub"; siin pole vaja ka enam karta, et kirje annaks tulemuseks NULL. Coalesce't antud juhul pole mõtet kasutada, kuigi sisult teeb ta sama.

Coalesce näited:

declare @muutuja varchar(15)
declare @muutuja1 varchar(15)
declare @muutuja2 varchar(15)


set @muutuja=null
set @muutuja1=null
set @muutuja2='OK'
select COALESCE(@muutuja,@muutuja1,@muutuja2)


Põhimõtteliselt käib antud juhul coalesce läbi kõik muutujad, kuni leiab esimese muutuja, mis ei ole tühi (NULL).

Kui oleksime soovinud, et telefoni numbri päring oleks tagastanud ühe numbritest, mis polnud tühi, tuleks teha järgnevalt:

select 'Telefon : '+coalesce(telefon,mobiil,'puudub') as telefon
from mingitabel





:::Tutvustan ka lühidalt mõningaid ühenduse spetsiifilisi SQL direktiive.

SET ANSI_NULLS (ON|OFF) direktiiv


Loome esmalt ajutise tabeli

create table #ajutine(i int null)

insert into #ajutine(i) values (123)
insert into #ajutine(i) values (null)

SET ANSI_NULLS ON -- vaikimisi (jälgitakse SQL-92 standardit)

select * from #ajutine where i=NULL

select * from #ajutine where i<>NULL


Tulemuseks mõlemal juhul 0 kirjet, mis ongi õige (määramatus ei võrdu kunagi määramatusega !)


SET ANSI_NULLS off

select * from #ajutine where i=NULL

select * from #ajutine where i<>NULL

Nüüd saate mõlemal juhul tulemuseks 1 kirje. Esimesel juhul kirje väärtuseks NULL ja teisel juhul 123.

MÄRKUS !

Igasugune standartidest kõrvale kaldumine võib tuua kaasa ebameeldivaid tagajärgi !

SET ANSI_NULLS off kasutada ainult väga äärmuslikes olukordades.

Kasutage ikka süntaksit :

select * from #ajutine where i IS NULL -- ehk on määramatus /väli tühi

select * from #ajutine where i IS NOT NULL -- ei sisalda määramatust

Kui soovite, et päringusse ikka tuleks ka NULL väärtusega välja; kasutage järgmis lahendust.

select * from #ajutine where isnull(i,0)<>100000

Kui Teil peaks tekkima olukord, kus võrreldakse kahte NULL väärtusega välja, kasutage lahendust

select * from #ajutine where isnull(i,0)=isnull(i,0)

SET ANSI_WARNINGS (ON|OFF)

Näite illustreerimiseks loome esmalt ajutise tabeli.

create table #test(i int)

insert into #test(i) values (5)

insert into #test(i) values (145)

insert into #test(i) values (null)

Vaikimisi on ANSI_WARNINGS peal. Nüüd, kui summeerime kõik I väärtused saame hoiatuse:

Warning: Null value is eliminated by an aggregate or other SET operation.

Sama viga tekib ka, kui update lauses liidate, lahutate "I" muutujat.

update #test set i=i-1 või update #test set i=i+1

Kui Te ei soovi, et antud hoiatus tekiks, seadke SET ANSI_WARNINGS OFF

SET ANSI_PADDING (ON|OFF) -- vaike-väärtuseks soovitatakse SET ANSI_PADDING ON

See tähendab, et kui toimub insert :
  • ON  - antud juhul insert lause puhul täidetakse char välja vaba osa tühikutega ning ning varchar väljale sisestatava väärtuse lõpust tühikuid ei koristada ära.

  • OFF - char tüüpi välja vaba osa ei täideta tühikutega ja varchar väljale sisestatava väärtuse lõpp trimmitakse (tühikud eemaldatakse)
  • if object_id("tempdb..#test")!=0 drop table #test
    create table #test
    (
    numbridv varchar(10),
    numbridc char(10)
    )

    SET ANSI_PADDING OFF -- Sooritage kaks päringut, kus ühel juhul ON ja teisel OFF ning jälgige päringu tulemust

    insert into #test(numbridv,numbridc) values('TEST  ','TEST')
    select '['+numbridv+']','['+numbridc+']'
    from #test

    ::: Välja väärtused muutujasse

    Mõnikord on olukordi, kus tuleb terve välja väärtused omistada muutujale (ntx koma separated list).
    Tihti olen kohanud, et programmeerijad teostavad selle operatsiooni cursori abil, kuid on olemas palju lihtsam meetod.

    CREATE TABLE laused (
    [id] [int] IDENTITY (1, 1) NOT NULL ,
    [laused] [varchar] (25) NOT NULL ,
    CONSTRAINT [PK_laused] PRIMARY KEY CLUSTERED
    (
    [id]
    ) ON [PRIMARY]
    )



    Set nocount on -- ütleme serverile, et ei tagastaks meile infot, mitu kirjet sisestati

    insert into laused(laused) values('mina')
    insert into laused(laused) values('olen')
    insert into laused(laused) values('inimene')

    declare @muutuja varchar(8000)
    select @muutuja = COALESCE(@muutuja,'')+laused.laused +';'
    from laused
    where laused.laused is not null

    select @muutuja


    -- Väljund: mina;olen;inimene;






    ::: MSSQL server ja ajutised tabelid

    Ajutisi tabeleid on kahte tüüpi:
    1. Ühe trelliga #tabel1

    2. Kahe trelliga ##tabel1
    Nii, nüüd nende erinevused. Ühe trelliga tabelit on võimalik kasutada ainult loodud ühenduse piires.
    Kahe trelliga tabeline saavad ka ligi teised kasutajad (globaalne ajutine tabel)!


    Ajutised tabelid on alati soovitav ära kustutada, kui Te enam neid ei kasuta. Antud reeglit peaks järgima eriti siis, kui ajutised tabelid sisaldavad palju kirjeid, sest muidu nad raiskavad mõtetult SQL serveri kettaressursi.

    Ajutised tabelid kustuvad serverist ka siis, kui lõpetatakse ühendus, mille käigus nad loodi.
    St. ka kahe trelliga tabel kustub, enam teised kasutajad seda ei näe.

    Näited, ajutiste tabelite loomiseks:

    1. Kirjeldame ära tabeli struktuurid:


    create table #test1
    (
    id int not null,
    automark varchar(45) not null
    )

    või siis

    create table ##test1
    (
    id int not null,
    automark varchar(45) not null
    )


    On veel üks võimalus, kuidas ajutist tabelit luua, see tipa "laisk" meetod.
    (teeme uue ajutise tabeli, kasutades olemas-oleva tabeli struktuuri)

    select id,automark
    into #test1 või vajadusel into ##test1
    from koikautod
    where 0=1


    Märkus: ajutises tabelis jääb väli Id ikka Identity tüüpi (kuna põhitabelis on identity), kuid ta on kaotanud primary key constraindi !

    Soovitav ka ajutise tabeli ID väli muuta Primary Key'ks.

    Kuid tegelikkuses, me ei vajaks ajutises tabelis IDENTITY tüüpi ID välja, meile piisaks "tavaliselt" ID väljast.

    select cast(null as int) as id,automark
    into #test1 või vajadusel into ##test1
    from koikautod
    where 0=1


    ALTER TABLE #test1 ADD PRIMARY KEY(id)



    Nüüd liigume tutvustava osa juurest reaalsema näite poole;
    järgnevalt üritamegi kasutada ajutisi tabeleid, et päringut kiirendada !


    MIKS üldse kasutada ajutisi tabeleid; näiteks on kolm tabelit; esimeses on 9 miljonit kirjet,
    teises 5 miljonit,kolmandas ka 7 miljonit.


    Näiteks tahaksime teada isikuid, kelle autoks on (VW või BMW) ning rahvus oleks türklane.

    select k.automark,i.isikunimi,e.pusiaadress
    from isikud i,koikautod k,elukoht e
    where (i.rahvus="türklane")
    and (k.omanikuId=i.id)
    -- MÄRKUS: kui siin kasutada OR lauset ((k.automark="VW") or (k.automark="BMW")),
    -- oleks päring veel aeglasem. OR võrdlused suht aeglased !!!
    and (k.automark in ("VW","BMW"))
    and (e.isikuId=i.id)


    Antud päring optimiseeritud kujul:

    create table #turklased
    (
    id int not null primary key,
    isikunimi varchar(85) not null,
    )

    ID väljad tähistame, kui primary key; teisisõnu unikaalsust tagav constraint, mille peale MSSQL server loob ka automaatselt unikaalse indeksi.


    create table #autod
    (
    omanikuId int not null,
    automark varchar(45) not null
    )

    Kuna joinis kasutame omanikuId välja, tekitame antud välja peale ka indeksi

    CREATE INDEX omanikId ON #autod(omanikuId)

    Nüüd meie optimiseeritud päring:

    insert into #turklased(id,isikunimi)
    select id,isikunimi
    from isikud
    -- PS. üks trikk, lisades parameetri from isikud (NOLOCK), võimaldab meil päringut veelgi kiirendada.
    -- nö. "Dirty read"; me ei saa ootama teiste poolt muutmiseks lukustatud kirjete taha, vaid loeme julmalt
    -- kõik kirjed. Seda võimalust kasutada vaid siis, kui pole tegemist aeg-kriitiliste andmetega !
    where (rahvus="türklane")
    order by id


    insert into #autod(omanikuId,automark)
    select omanikuId,automark
    from koikautod (nolock) -- !!
    where (automark in ("VW","BMW"))
    order by id


    select k.automark,i.isikunimi,e.elukoht
    from #turklased a,#autod k,elukohad e (nolock)
    where (k.omanikuId=a.id)
        and (e.isikuId=a.id)
    order by e.elukoht,i.isikunimi


    Hea tava on ise ajutised tabelid kustutada (eriti ühe trelliga tabelid) !

    Nipp, mida mina isiklikult kasutan, enne kustutamist ikka kontrollin, kas tabel ka reaalselt olemas.
    Järsku mingi insert veadas alt ning ajutist tabelit ei loodud...:(

    if object_id("tempdb..#autod")!=0 drop table #autod
     
    if object_id("tempdb..#turklased")!=0 drop table #turklased


    Antud näites kasutasin ajutisi tabeleid päringu tükeldamiseks. Selline tükeldus annab tihti ajalist võitu !
    Kui joinis on ohtralt staatilisi tabeleid, jääb päring aeglaseks.

    Lõpetuseks üks täiendav võimalus ajutise tabeli loomiseks, on kasutada TABEL tüüpi muutujat.

    declare @tabelmuutuja table
    (id int primary key,midagiveel varchar(255))


    Kahjuks neile tabelitele ei saa indeksit genereerida (va. primary key) ning protseduurist saadud selecti pole võimalik sinna tabelisse inseritida.

    Tabel tüüpi muutuja võib olla näiteks funktsiooni väljundiks, mis on mõnikord ülimalt mugav võimalus. Seda tüüpi muutuja, aga ei saa olla protseduuri/ega funktsiooni sisendiks.


    Natuke spetsiifikat:

    See lahendus muutuja puhul ei tööta !

    update @tabelmuutuja
    set midagiveel='B'
    from @tabelmuutuja tbl
    where tbl.midagiveel='A'
    and @tabelmuutuja.id=tbl2.id


    Antud lahendus töötab

    update tbl
    set midagiveel='B'
    from @tabelmuutuja tbl,@tabelmuutuja tbl2
    where tbl2.midagiveel='A'
    and tbl.id=tbl2.id

    SQL Table tüübi muutujad kustuvad automaatselt skoobist väljumise hetkel.
    Lõpetuseks mõned märkused
    • Kui kasutate mssql protseduuri sees (ühe trelliga) ajutist tabelit, siis kustutatakse see tabel automaatselt;

    • Ajutised tabelid create table #a.... tasuks luua alati protseduuri alguses, muidu kompileeritakse SQL protseduur ümber peale igat ajutise tabeli loomist, mis mõjub palju protseduuri kiirusele.

    • Võimaluse korral kasutada protseduuride sees muutujatel baseeruvaid tabeleid, siis uuesti kompileerimist ei toimu.





    :::MSSQL serveri veahaldus

    Kahjuks MSSQL server ei paku vea haldamiseks exception handlereid; kuid järgmises MSSQL serveris on exception handling täitsa olemas (versioon nimega Yukon).

    MSSQL serveris saab vea tõstatada: RAISERROR 50000 'Tekkis viga' sellist tüüpi vea tõstatamist kasutan ka mina enamasti.

    Esimene parameeter on veakood, mis soovituste järgi algaks alates 50000, kuna allpool on MSSQL enda veakoodid.

    Raiserrorit saab kasutada ka järgmiselt: RAISERROR('Tekkis viga', 16, 1)

    * Esimene parameeter on siis, kas Teie veasõnum või eeldevalt defineeritud veakood(sp_addmessage);
    seda viimast varianti kasutatakse suht harva.

    * Teine parameeter näitab vea tõsiduse astet: võib-olla vahemikus 0-16; kui on vahemik 0-10, siis viga ei loeta eriti tõsiseks pigem informatiivseks ja süsteemsetmuutujat @@ERROR ei väärtustata.

    Enamalt jaolt tõstatatakse viga tõsidusega 16; 17-18 on süsteemsed vead.

    Tõsiduse nivood 19-25 saavad kasutada vaid süsteemiadministraatorid. Kui tuleb viga nivooga alates 20 ühendus kliendiga katkestatakse ja viga kirjutatakse MSSQL serveri logisse.

    Näiteks andmebaasi administraator võib teha protseduuri:

    create proc kliendiYhendusKatkestada
    as
    raiserror('Peale selle veateate saamist katkeb ühendus serveriga',20,1)
    WITH LOG

    * Kolmas parameeter on veakoodi täiustav informatiivne väli, väärtus saab olla vahemikus 1..127

    Täiendavat infot vigade nivoodest saab siit:

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/trblsql/tr_errorformats_0tpv.asp

    Näited:

    Eelnevalt, kui lähme näidete juurde, pean mainima, et kõik vead, mis on nivooga >10 jõuavad exceptionina kohale Teie programmi. Kas kasutate ADO,JDBC,ODBC jne...viga

    Näiteks:

     raiserror (17820,10,123)
    -- Antud näites kutsume välja informatiivse vea (nivoo 0;10),
    -- 17820 - on süsteemis kirjeldatud viga "Invalid data type parameter."
    -- Kõiki eeldefineeritud vigu saab vaadata tabelist: select * from master.dbo.sysmessages

    või

     raiserror ('Ei tohi andmeid töödelda',10,123)

    Antud nivooga vead võrduks print käsuga. Neid vigu ei kuva ka Teie andmebaasi lõpprakendused, kui nivoo tõstate üle 10, on vead olemas.

    Puuduseks on nivoodel 0-10 see, et SQLi süsteemset muutujat @@ERROR ei väärtustata,
    mille kontrollimisel saaksime otsustada, kas jätkame oma SQL loogikaga.

    Väike trikk, mis võimaldab meil kasutada nö silent exceptioni

    create proc vaikeviga
    as
    raiserror ('Meil tekkis väike viga',10,123)
    with seterror -- @@ERROR muutujale omistatakse väärtus 50000


    -- Nüüd kutsume protseduuri välja
    exec vaikeviga
    if (@@ERROR=0) print 'update ... midagi' else print 'Eelmises SQL käsus ilmnes viga'


    @@ERROR muutujat kasutamisel tuleb kindlasti jälgida, et antud muutuja väärtust küsitakse kohe näiteks peale protseduuri käivitamist, update lauset, inserti jne

    declare @mingiMuutuja int
    exec vaikeviga
    set @mingiMuutuja=123


    -- nüüd saab @@ERROR muutuja väärtuseks 0, iga uue SQL käsu järgi, veamuutuja väärtust uuendatakse.
    -- Selliseid vigu võib üsna tihti kohata

    if (@@ERROR=0) print 'update ... midagi' else print 'Eelmises SQL käsus ilmnes viga'

    *** SQL vigade vältimiseks võiks kasutada järgnevaid süsteemseid muutujaid:

    @@ROWCOUNT - annab töödeldud(INSERT,UPDATE)/selekteeritud (SELECT) kirjete arvu
    (viimase SQL batchi tulemus)

          Näiteks: select * from mingitabel
                        if (@@ROWCOUNT=0) print 'päring oli tühi'

    @@TRANCOUNT - juhul, kui meil on vaja transaktioon tagasi tõmmata, siis võiks eelnevalt kontrollida, kas transaktioon üldse töötab või on juba mõni triger eelnevalt rollback ära teinud.

    if @@TRANCOUNT!=0 commit tran või rollback tran
    Kui soovite kõiki transaktioone kinnitada / või tagasi tõmmata:

    while @@trancount>0
              rollback tran või commit tran

    Kursori operatsioonide puhul on soovitatav kontrollida tema olemasolu

    -- nö mina kasutan tavaliselt kursoreid muutuja kujul, nimelised kursorid mulle ei meeldi
    if cursor_status('variable', '@sinucursormuutuja')>=0
       begin
        fetch next from @sinucursormuutuja into @mingidmuutujad

    -- Näitab, kas cursor tagastas andmeid 0 - siis kõik korras
        while @@fetch_status = 0
          begin
           fetch next from @sinucursormuutuja into @mingidmuutujad
          end

        close @sinucursormuutuja
        deallocate @sinucursormuutuja
       end

    ...SQL protseduuris võiks veahalduse lahendada järgmise loogika kohaselt...

    create proc test(@parameeter int)
    as
    begin

    declare @olivigu int
    set @olivigu=0 -- staatus, et pole probleemi


    ...teen midagi...
    set @olivigu=@@ERROR
    if isnull(@olivigu,0)!=0
    goto lopp


    ...tegevused...
    select top 0 *
    from andmed
    if @@rowcount=0
    begin
     set @olivigu=55009 -- vajadusel Teie poolt defineeritud veakood
     goto lopp
    end

    lopp: -- goto label
    ...vajadusel kustutan ajutised tabelid, sulgen kursorid, teen rollbacki jne...

    return @olivigu -- märkus, return lõpetab protseduuri töö
    end




    :::Lühidalt funktsioonidest

    Funktsioonid on tekkisid MSSQL-2000

    -- Andmetüübid, mis ei või olla sisendiks : timestamp, table(muutuja)
    create function test1(@b int,@a smallint)
    -- Defineerime väljundi tüübi
    returns int
    -- andmetüübid, mida ei saa olla väljundiks timestamp, image, text, ntext, cursor.


    as
    begin

     declare @c int
     set @c=@a+@b
     return @c
    end


    Funktsiooni väljakutse:

    select dbo.test1(5,6)
    -- märkus: funktsiooni ees peate ära märkima, kes funktsiooni looja.
    -- Enamasti dbo - ehk admin; väljakutse select test(5,6) annaks vea !


    Funktsioone võime rakendada paljudes kohtades, viewd, selectid, where tingimused jne

    select a,b
    from suvalinetabel
    where dbo.test1(a,b)>555



    create table test3
    (
      a int default 1,
      b int default 2,
      c as (dbo.test1(a,b)) -- kasutame funktsiooni calculated field tüübi jaoks
    )



    Funktsioonide puudused (tuginedes enda kogemustele):
    • Ei võimalda kasutada funktsioone ntx. GETDATE !, GETUTCDATE ! põhjuseks see, et nende funktsioonide väärtus muutub n-ajahetkel pidevalt. Sama kehtib veel mõningate teiste süsteemsete muutujate kohta, mida kasutatakse harvemini.

    • Funktsiooni sees ei saa kasutada/ega luua ajutisi tabeleid (# / ##) !
      See-eest saab kasutada funktsioonis TABLE tüüpi muutujaid. declare

      ntx. declare @muutuja table (nr int)

    • Veel üks koht, mis minule peavalu on tekitanud, on see, et funktsioonis ei saa välja kutsuda protseduuri (va extended protseduur)! Funktsiooni isegi kompileerib ära, kui seal sees exec välja kutsed, kuid funktsiooni käivitamisel saate vea.

    • Funktsioonide poole pöörumisel ei kasutata korrektselt vaikeväärtust. st. kui teeme sellise funktsiooni:

      create function test(@b int = 9,@a smallint = 5) ...

      Oleks loogiline, et välja kutse toimuks järgnevalt:

      select dbo.test()

      Kuid asjad pole sugugi nii !

      Et me ei peaks vaikeväärtusi uuesti initsialiseerima teeme nii:

      select dbo.test(default,default)

    • Funktsiooni sees ei ole võimalik uuendada / lisada / kustutada andmeid tabelites.

      Samas on võimalik seda teha tabel muutujate peal.


    Nüüd tuli küll hulgi miinuseid, kuid funktsioon on mõningates olukordades asendamatu abimees:)

    Toon veel mõningaid näiteid funktsiooni kasutusvõimalustest:

    -- Antud funktsiooni väljundiks on tabel

    create function test2()
    -- Defineerime väljundi tüübi
    returns @proov table
    (id int IDENTITY(1,1) not null primary key,
    sona varchar(50) not null)
    as
    begin
    declare @id int

    insert into @proov(sona) values('Võitleva Sõna ')
    insert into @proov(sona) values('baarist')
    set @id= scope_identity()

    update @proov
    set sona=sona+' saab juua '
    where id=@id

    return

    end

    -- Funktsiooni testimine
    select a.sona from dbo.test2() a

    Täiendav märkus !

    Table muutujatele ei kehti transaktsioonid
    Näide:

    declare @test table(i int)
    insert into @test(i)
    values(5)
    begin tran
    update @test set i=9
    select * from @test
    rollback tran
    select * from @test


    Normaalse loogika alusel oleks @test tulemuseks 5, aga ...on 9



    ::: Mõned kasulikud SQL funktsioonid

    select SUSER_SNAME() -- annab SQLserveri kasutajanime
    select ISDATE('07.12.2005')-- kontrollib, kas kuupäev on korrektne (SQLserveri mõistes)
    select NEWID() -- genereerib unikaalse guid stringi
    select NULLIF(0,1) -- kontrollib, kas kaks väärtust võrdsed, kuid jah, siis tulemus NULL
    select ISNUMERIC('51.2') -- kontrollib, kas arv korrektne, ka reaalarv .255 on korrektne
    select YEAR(getdate()) -- eraldab kuupäevast aasta osa
    select MONTH(getdate()) -- eraldab kuupäevast kuu osa
    select DAY(getdate()) -- eraldab kuupäeva
    select DATEADD(day,5,getdate()) -- ntx. lisab hetke ajale +5 päeva, võib ka neg. number olla -5
    select DATEPART(mi,getdate()) -- ntx. eraldab ajaühikust minutite osa
    select DATENAME(dw,getdate()) -- ütleb, mis päev on
    select DATENAME(mm,getdate()) -- ütleb kuu nime

    /* muudab kuupäev char kujule formaadis mm.dd.yyyy, 3 parameeter converdi puhul ütleb,
    mis kujule kuupäev teisendada */
    select convert(char(10),getdate(),104)

     

    Kunagi küsiti minult, kuidas kontrollida, et kas ma tohin mingist tabelist selecti teha või kas mul on insert õigus...

    0x1 SELECT ALL
    0x2 UPDATE ALL
    0x4 REFERENCES ALL
    0x8 INSERT
    0x10 DELETE
    0x20 EXECUTE (procedures only)
    0x1000 SELECT ANY (at least one column)
    0x2000 UPDATE ANY
    0x4000 REFERENCES ANY

    Ülejäänud õiguste väärtused saate SQL server books online abil.

    if PERMISSIONS (object_id('teie tabel'))&0x2000=0x2000
       select 'võid küll update teha'

    Soovitan ka uurida protseduuri sp_helprotect