Avatar billede cwboy Nybegynder
13. juli 2004 - 14:24 Der er 23 kommentarer og
2 løsninger

Hvordan laver jeg LIMIT i MS SQL?

Er der nogen, der kender en måde at lave mySQL's "LIMIT" i MS SQL?

Forestil jer, at der er en dynamisk opbygget forespørgsel, som enten kan være sorteret efter et navn, et symbol, en dato (eller noget helt syttende)

Nu har jeg så brug for på side 1 at få resultaterne 1-100, side 2 101-200 osv...

Med mySQL ville jeg have tilføjet noget lignende "LIMIT " + side*100 + ",100"

Jeg har desværre ikke mulighed for at bruge "where id > " + sidsteid
eller lignende løsninger.
Avatar billede arne_v Ekspert
13. juli 2004 - 14:31 #1
SELECT TOP n ...
Avatar billede cwboy Nybegynder
13. juli 2004 - 14:35 #2
Ja, hvis det bare så vel :)  Men hvordan får jeg resultaterne fra 101-200, 201-300 osv.?
Avatar billede arne_v Ekspert
13. juli 2004 - 14:50 #3
Ah.

Den feature mangler MS SQL.

TOP er kun et antal - der er ingen offset.

Sorry.

Jeg kan umiddelbart kun se følgende muligheder:
1)  hent 100, 200, 300 og smid de første 0, 100, 200 væk
2)  gem resultset mellem forespørgslerne
3)  en stored procedure

Men måske er der et trick som jeg ikke kender !
Avatar billede -mundi- Nybegynder
13. juli 2004 - 15:00 #4
Du kunne lave en
"Select top @sidenr*100 from tabel where id  not in (select top @sidenr*100-100 id from tabel )
men den er ikke særligt performance venlig :-)
Avatar billede -mundi- Nybegynder
13. juli 2004 - 15:02 #5
hov
"Select top 100 from tabel where id not in (select top @sidenr*100-100 id from tabel order by felt) order by felt
Avatar billede cwboy Nybegynder
13. juli 2004 - 15:11 #6
Det var da trist at der ikke lige er nogen nem måde :(
Jeg lader den lige stå en dags tid for at se, om nogen graver en super hemmelig ting frem, ellers må I dele points (arne_v og -mundi-) for de gode forslag.
Avatar billede barkov Nybegynder
13. juli 2004 - 15:40 #7
For at gøre det hurtigst muligt, så henter du hele sql tabellen og bruger dit sideantal til at tælle ned i recordsettet. Det er bestemt det hurtigste at gøre.

Dvs.:
strSQL = "Select * from tabel"
Set RS  = conn.execute(strSQL)

For I = 1 to ((Sidenr*100)-100)
  RS.Movenext
Next

Og så søger du bare for at spytte de efterfølgende 100 records ud på skærmen med følgende parameter:

I = 0
Do until RS.EOF or I = 100
  Response.Write "blablabla"
  RS.MoveNext
  I = I +1
loop

Set RS = Nothing
Avatar billede -mundi- Nybegynder
13. juli 2004 - 15:47 #8
Undskyld ,men det er ikke rigtigt !

For det første er det ikke særligt smart at hive hele tabellen over, når der ikke er brug for det.

For det andet kunne
For I = 1 to ((Sidenr*100)-100)
  RS.Movenext
Next

omskrives til

RS.Move(((Sidenr*100)-100)

Det hurtigste er at udvælge så få data som muligt skrive dem ud.
Avatar billede arne_v Ekspert
13. juli 2004 - 15:53 #9
I parentes bemærket er det mit forslag #1.
Avatar billede arne_v Ekspert
13. juli 2004 - 15:54 #10
Mundis forslag er nok det mest kreative SQL
Avatar billede arne_v Ekspert
13. juli 2004 - 15:56 #11
Grunden til at featuren ikke er der formentlig at selv om den er ekstrem nyttig, så
er det noget "kun 99% korrekt".

Fordi hvis der bliver slettet eller indsat rækker mellem queries, så er
resultaterne misvisende.
Avatar billede cwboy Nybegynder
13. juli 2004 - 16:00 #12
barkov - forslaget er, som arne_v skriver, identisk med hans forslag. Men det var netop dette, jeg gerne ville udenom, da vi sidder med et temmelig stort site og en SQL-server der har travlt i forvejen...
Avatar billede cwboy Nybegynder
13. juli 2004 - 16:03 #13
arne_v - ja, men en gang imellem ville man ønske at man kunne få lov alligevel - der er jo mange tilfælde, hvor man ville prioritere performance højere end det at være sikker på at brugeren ser hver eneste række...
Avatar billede -mundi- Nybegynder
13. juli 2004 - 16:08 #14
Så vidt jeg ved er den eneste løsning at gøre som arne_v foreslår i punkt 1.

hvis du har 100 records per side, og er nået til side 10 så lav en
"select top side*recordsPerSide from tabel"

Fyr din SQL af med cursorlocation = adUseServer
rs.move((side-1)*recordsrecordsPerSide )

på den måde har du endnu ikke hentet data fra serveren

recordArray = rs.getrows()

hent alle records på engang, hvilket giver den bedste performance, da du kun connecter til serveren en gang

Nu ved jeg jo ikke hvilket sprog du programmerer i, men princippet burde holde :-)
Avatar billede arne_v Ekspert
13. juli 2004 - 16:10 #15
Det forstår jeg godt.

Har du overvejet min #2 ?

Den sender kun en query til databasen og henter kun hver række en gang.

Ulempen er at den kræver mange åbne connections og result sets.
Avatar billede arne_v Ekspert
13. juli 2004 - 16:20 #16
Jeg vil nu gætte på at:

rs.move((side-1)*recordsrecordsPerSide )

rent faktisk læser dataene fra databasen.
Avatar billede arne_v Ekspert
13. juli 2004 - 18:59 #17
#2 er i J2EE verden kendt som "page by page pattern" eller "value list handler pattern"
Avatar billede arne_v Ekspert
13. juli 2004 - 18:59 #18
Og et svar fra mig igen
Avatar billede cwboy Nybegynder
13. juli 2004 - 19:10 #19
Som nævnt tidligere, bliver det -mundi- og arne_v der deler pointene - tak for jeres forslag. Jeg ved endnu ikke hvad valget falder endeligt på, men I har begge ledt mig på vej :)

Evt. kan der blive tale om en utrolig lang, kedelig stored procedure med separate SELECTs alt efter hvilket kriterie, der søges efter - og så holde styr på, hvilket emne man er nået til...
Avatar billede janus_007 Nybegynder
13. juli 2004 - 19:27 #20
Der var nu ellers en forholdsvis nem måde at løse det på :O( - Men okay, den må jeg komme emd en anden god gang.

Hygge
Avatar billede cwboy Nybegynder
13. juli 2004 - 20:35 #21
janus_007 - hvis du har en simpel måde (som sparer ressourcer) må du meget gerne skrive den, så skal du nok få 30 point... jeg er stadig på jagt efter "den lette udvej" :)
Avatar billede janus_007 Nybegynder
13. juli 2004 - 23:49 #22
Simpel og simpel.. hmmm

Men jeg har da lavet noget ala det her et par gange, det forudsætter at du enten har et nogenlunde statisk table så det her ikke skal laves så tit eller du ved noget om usercaching af tabeller. Den sidste er der flere indgangsvinkler til og laves efter behovet, men handler i bund og grund om at cache nogle arbejdstabeller evt. for hver dag eller for hver session hvis det nu var igennem noget webhejs....

Jeg forudsætter bla. at din tabel indeholder en primarykey :O)

create table tmpTOP
(
id int identity(1,1),
orig_id int
)

insert into tmpTOP select identitycol from origTable order by...

Du kan anføre den order by du vil... Nu har du altså en lille tabel med id's i, dvs. du kan sige :

select ot.* from origTable ot
inner join tmpTOP tt on tt.orig_id = ot.identitycol
where tt.id between 10 and 19  -- her her du din limit :O)

Som jeg siger så kan den ikke bare implementeres uden lidt forberedelse, men nu kender jeg ikke dit system.
Avatar billede cwboy Nybegynder
14. juli 2004 - 09:53 #23
janus_007 - jeg lægger et spørgsmål, hvor du kan få dine point.
Ret kreativ løsning, men jeg tvivler på det bliver denne, da vi har 2000+, stort set unikke, søgninger om dagen...
Men jeg kan sikkert bruge det et andet sted, og løsningen er ret kreativ, så den er alle pointene værd :)
Avatar billede runesoft Nybegynder
15. juli 2004 - 08:42 #24
Jeg vil aldrig anbefale at hente et helt recordset og sortere på klienten.

Det er et stort problem. Enten kommer du til at hente alle rækker og gemme dem, eller du kommer til at udføre samme query flere gange.  Hvad der bedst kan betale sig kommer an på behovet.

Hvis jeg var dig ville jeg søge på paging!

alternativt ville jeg jeg sortere det fra der allerede er vist (det kan du fordi det er sorteret), og så lave en "top 100" på det. Så får du kun de rækker tilbage som du vil vise.
Avatar billede runesoft Nybegynder
15. juli 2004 - 08:44 #25
ulempen ved at hente alle rækkerne af én gang og gemme det hele til du skal vise de næste sider er selvfølgelig at du får brugt en masse hukommelse.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester