MySQL - Pomoć sa upitom

poruka: 34
|
čitano: 5.797
|
moderatori: Lazarus Long, XXX-Man, vincimus
+/- sve poruke
ravni prikaz
starije poruke gore
17 godina
offline
MySQL - Pomoć sa upitom

Ovako, da pojednostavnim...

 

Imam 2 tabele (Apartman one to many Zauzetost)

 

Apartman

ApartmanID (int) (primary)

Naziv (text)

 

 

Zauzetost

ZauzetostID (int) (primary)

ApartmanID (int)

Od (DATETIME)

Do (DATETIME)

 

 

Apartman je... jel, apartman, dok se u tabeli Zauzetost nalaze vec postojece rezervacije.

 

U aplikaciji imam pretragu apartmana na nacin da korisnik unese period od kad do kad on zeli rezervirati apartman u tom hotelu i trebalo bi mu izbaciti sve apartmane koji su slobodni, odnosno, period koji je korisnik unio ne poklapa se sa nitijednim periodom koji se vec nalazi u tabeli.

 

Ovo sam rijesio na jedan glup, kompliciran i nadasve ruzan nacin i nisam zadovoljan. Trebao bih pomoc da ovo napisem po P.S.u.

 

Dakle, parametre koje SQL upit prima su pocetak i kraj nove rezervacije tipa DATETIME i treba vratiti sve apartmane koji su slobodni.

 

Unaprijed hvala!

Mentalist je moj idol...
 
0 0 hvala 0
17 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom

Ovo bi trebalo biti trivijalno, barem ja tako čitam u 7 navečer. Jednostavno preklopi periode tako da provjeriš da niti jedan dan (datum) iz perioda koji se traži, nije unutar perioda koji je već rezerviran. Možeš to optimizirati jednostavnom komparacijom da ti početni datum traženog nije veći ili jednak od niti jednog postojećeg početka i istovremeno manji od završetka. Naravno, ako pretraživač (osoba) stavlja širi raspon od potrebnog, onda mu moraš izbaciti apartmane koji imaju barem jedan minimalan iznos dana (1?) unutar tog raspona, a da nije zauzet. U prvom slučaju ja ću dobiti sve apartmane sa slobodnim rasponom koji sam tražio, a u drugom sve apartmane koji unutar mog zadanog (traženog) raspona imaju barem n dana slobodno, gdje je n>1, naravno uz neki zadani limit eventualno. Pretraživanje u tom slučaju mora imati ili skrivenu fiksnu varijablu minimuma slobodnih dana ili biti dio upita korisnika.

Poruka je uređivana zadnji put sub 7.5.2011 21:02 (naxeem).
17 godina
offline
MySQL - Pomoć sa upitom

Kako napraviti da provjerava da se NE preklapaju. Lako mi je pogledati da li "podskup" klijentov upit spada u skup "postojece rezervacije". Kako rijesiti da vrati one koji NE spadaju.

Mentalist je moj idol...
 
0 0 hvala 0
16 godina
neaktivan
offline
MySQL - Pomoć sa upitom

select ApartmanId, Naziv from apartman where ApartmanId not in (select apartmanId from Zauzetost where ReservationStartDate<=Do and ReservationEndDate>=Od)

 
1 0 hvala 1
17 godina
offline
MySQL - Pomoć sa upitom

Znaci to bi bilo jednako ovome

 

SELECT <params> FROM Apartman INNER JOIN Zauzetost ON Apartman.ApartmanID = Zauzetost.ZauzetostID WHERE NOT (Zauzetost.Od <= KorisnikOD AND Zauzetost.Do >= KorisnikDO) GroupBy Apartman

 

???

 

EDIT: Mrkač... nisam ovo pokusao, ali budem...

Mentalist je moj idol...
Poruka je uređivana zadnji put sub 7.5.2011 21:26 (tnakir).
 
0 0 hvala 0
16 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom

Nisam baš štovatelj te ANSI SQL sintakse s INNER JOIN ali mislim da smo napisali isti query samo je meni trebalo manje znakova {#}

17 godina
offline
MySQL - Pomoć sa upitom

Ja uopce nisam stovatelj SQL-a kao takvog, razmazio me LINQ i EF :))))))

 

EDIT: Dobio sam nekakav projekt za modifikaciju nekakve web stranice - ASP + mySQL... Covjeku dodje za plakat kad se vrati sa ASP.Net-a na ovo :(((((( 

Mentalist je moj idol...
Poruka je uređivana zadnji put sub 7.5.2011 21:46 (tnakir).
 
0 0 hvala 0
17 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom
tnakir kaže...

Kako napraviti da provjerava da se NE preklapaju. Lako mi je pogledati da li "podskup" klijentov upit spada u skup "postojece rezervacije". Kako rijesiti da vrati one koji NE spadaju.

Pa, upada ili ne, dođe na isto - samo imaš negaciju.

mrkač kaže...

select ApartmanId, Naziv from apartman where ApartmanId not in (select apartmanId from Zauzetost where ReservationStartDate<=Do and ReservationEndDate>=Od)

Ne valja.

tnakir kaže...

Znaci to bi bilo jednako ovome

 

SELECT <params> FROM Apartman INNER JOIN Zauzetost ON Apartman.ApartmanID = Zauzetost.ZauzetostID WHERE NOT (Zauzetost.Od <= KorisnikOD AND Zauzetost.Do >= KorisnikDO) GroupBy Apartman

...

 

Ne može imati tako stroge uvjete jer će kao slobodne dobivati apartmane koji imaju rezervacije koje se djelomično preklapaju s navedenim.

Poruka je uređivana zadnji put sub 7.5.2011 23:12 (naxeem).
17 godina
offline
MySQL - Pomoć sa upitom

Daj plz napisi upit...

Mentalist je moj idol...
 
0 0 hvala 0
17 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom
mrkač kaže...

select ApartmanId, Naziv from apartman where ApartmanId not in (select apartmanId from Zauzetost where ReservationStartDate<=Do and ReservationEndDate>=Od)

select * from apartmani where apartmanid not in (select apartmanid from rezervacije where @from <= enddate AND startdate <= @to)

 

edit 1: LOL, tek sad vidim da sam napisao istu stvar, sorry mrkač. Nešto sam krivo pročitao i iskalkulirao u glavi :D - točno je to.

Mislim da ću prestat večeras s poslom, vidim da sam premoren. {#}

 

edit 2: nego, čini mi se da i dalje nisi posve precizan - traženi datum od-do, treba li biti cjelovit? daje li pretraživanje slobodnije raspone pa ako nađe mjesta ili...? Ovaj mrkačev upit eliminira sve što se preklapa.

Poruka je uređivana zadnji put sub 7.5.2011 23:12 (naxeem).
15 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom
mrkač kaže...

select ApartmanId, Naziv from apartman where ApartmanId not in (select apartmanId from Zauzetost where ReservationStartDate<=Do and ReservationEndDate>=Od)

 

tnakir kaže...

Znaci to bi bilo jednako ovome

 

SELECT <params> FROM Apartman INNER JOIN Zauzetost ON Apartman.ApartmanID = Zauzetost.ZauzetostID WHERE NOT (Zauzetost.Od <= KorisnikOD AND Zauzetost.Do >= KorisnikDO) GroupBy Apartman

 

???

 

EDIT: Mrkač... nisam ovo pokusao, ali budem...

 

mrkač kaže...

Nisam baš štovatelj te ANSI SQL sintakse s INNER JOIN ali mislim da smo napisali isti query samo je meni trebalo manje znakova {#}

Zapravo nisu bas isti query-ji. Mrkacev query ce vratit sve apartmane koji nisu zauzeti u tom razdoblju, a tnakirov ce vratit sve apartmane koji nisu zauzeti u tom razdoblju, ali su zauzeti u nekom razdoblju (imaju barem jedan redak) u tablici zauzetost.
Da bi tnakirov query ispravno radio trebalo bi zamjenit inner join sa left joinom i dodat u uvjet da polja zauzetost.od i zauzetost.do mogu bit null ovako:
SELECT Apartman.*
 FROM Apartman
 LEFT JOIN Zauzetost ON Zauzetost.ApartmanID = Zauzetost.ApartmanID
WHERE NOT (Zauzetost.OD <= KorisnikOD AND Zauzetost.DO >= KorisnikDO)
 OR ( Zauzetost.Od is NULL AND Zauzetost.DO IS NULL)
GROUPBY Apartman.ApartmanID

Ovaj query ce vratit iste rezultate kao mrkacev, ali je potencijalno brzi jer ne koristi subselect. Ako optimizator ne primjeti da je subselect u WHERE dijelu mrkacevog querija isti za svaki redak tablice apartman izvrsit ce ga ponovno
za svaki apartman.

14 godina
protjeran
offline
Re: MySQL - Pomoć sa upitom
tnakir kaže...

Ovako, da pojednostavnim...

 

Imam 2 tabele (Apartman one to many Zauzetost)

 

Apartman

ApartmanID (int) (primary)

Naziv (text)

 

 

Zauzetost

ZauzetostID (int) (primary)

ApartmanID (int)

Od (DATETIME)

Do (DATETIME)

 

 

Apartman je... jel, apartman, dok se u tabeli Zauzetost nalaze vec postojece rezervacije.

 

U aplikaciji imam pretragu apartmana na nacin da korisnik unese period od kad do kad on zeli rezervirati apartman u tom hotelu i trebalo bi mu izbaciti sve apartmane koji su slobodni, odnosno, period koji je korisnik unio ne poklapa se sa nitijednim periodom koji se vec nalazi u tabeli.

 

Ovo sam rijesio na jedan glup, kompliciran i nadasve ruzan nacin i nisam zadovoljan. Trebao bih pomoc da ovo napisem po P.S.u.

 

Dakle, parametre koje SQL upit prima su pocetak i kraj nove rezervacije tipa DATETIME i treba vratiti sve apartmane koji su slobodni.

 

Unaprijed hvala!

Zaš nisi stavio datume zausetosti u apartman tabelu {#}

 

Dvije muhe jednim udarcem.

$this-&gt;db-&gt;where-&gt;('I don't have a clue');
17 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom

Kako bi to izveo?

14 godina
protjeran
offline
Re: MySQL - Pomoć sa upitom
naxeem kaže...

Kako bi to izveo?

Pa staviš u tabelu apartman dvije kolumne zauzetost od i zauzetost do.

 

Ne vidim u čemu je problem.

 

I onda lijepo samo tražiš po tabeli apartmani bez join-a i sličnih manevara.

$this-&gt;db-&gt;where-&gt;('I don't have a clue');
17 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom
Blakc kaže...
mrkač kaže...

select ApartmanId, Naziv from apartman where ApartmanId not in (select apartmanId from Zauzetost where ReservationStartDate<=Do and ReservationEndDate>=Od)

 

tnakir kaže...

Znaci to bi bilo jednako ovome

 

SELECT <params> FROM Apartman INNER JOIN Zauzetost ON Apartman.ApartmanID = Zauzetost.ZauzetostID WHERE NOT (Zauzetost.Od <= KorisnikOD AND Zauzetost.Do >= KorisnikDO) GroupBy Apartman

 

???

 

EDIT: Mrkač... nisam ovo pokusao, ali budem...

 

mrkač kaže...

Nisam baš štovatelj te ANSI SQL sintakse s INNER JOIN ali mislim da smo napisali isti query samo je meni trebalo manje znakova {#}

Zapravo nisu bas isti query-ji. Mrkacev query ce vratit sve apartmane koji nisu zauzeti u tom razdoblju, a tnakirov ce vratit sve apartmane koji nisu zauzeti u tom razdoblju, ali su zauzeti u nekom razdoblju (imaju barem jedan redak) u tablici zauzetost.
Da bi tnakirov query ispravno radio trebalo bi zamjenit inner join sa left joinom i dodat u uvjet da polja zauzetost.od i zauzetost.do mogu bit null ovako:
SELECT Apartman.*
 FROM Apartman
 LEFT JOIN Zauzetost ON Zauzetost.ApartmanID = Zauzetost.ApartmanID
WHERE NOT (Zauzetost.OD <= KorisnikOD AND Zauzetost.DO >= KorisnikDO)
 OR ( Zauzetost.Od is NULL AND Zauzetost.DO IS NULL)
GROUPBY Apartman.ApartmanID

Ovaj query ce vratit iste rezultate kao mrkacev, ali je potencijalno brzi jer ne koristi subselect. Ako optimizator ne primjeti da je subselect u WHERE dijelu mrkacevog querija isti za svaki redak tablice apartman izvrsit ce ga ponovno
za svaki apartman.

Taj tvoj query vratit će mu kupus tj. sve apartmane. Po kojoj logici si ti slagao i čemu LEFT JOIN? Znaš li ti što znači LEFT, a što INNER join?

 

Nema tog optimizatora koji će okrenuti subselect za svaki apartman u upitu, a subselecti su redovito u praksi brži od joina.

17 godina
offline
MySQL - Pomoć sa upitom

@Bypass... modificiram postojecu aplikaciju. Nemam puno vremena ni mjesta za velike promjene. Radim sto brze mogu sa sto manje gluposti. Ovo je najbezbolnije rijesenje.

Mentalist je moj idol...
 
0 0 hvala 0
14 godina
protjeran
offline
Re: MySQL - Pomoć sa upitom
tnakir kaže...

@Bypass... modificiram postojecu aplikaciju. Nemam puno vremena ni mjesta za velike promjene. Radim sto brze mogu sa sto manje gluposti. Ovo je najbezbolnije rijesenje.

Okey, nisam vidio da modificiraš.

 

A ništa, join i zdravo.

$this-&gt;db-&gt;where-&gt;('I don't have a clue');
16 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom
Bypass kaže...
naxeem kaže...

Kako bi to izveo?

Pa staviš u tabelu apartman dvije kolumne zauzetost od i zauzetost do.

 

Ne vidim u čemu je problem.

 

I onda lijepo samo tražiš po tabeli apartmani bez join-a i sličnih manevara.

Rekao bi da bi u tabeli Zauzetost trebale biti i rezervacije a u tom slučaju može biti zauzet(rezerviran) u više različitih termina pa mu dvije dodatne kolone nisu dovoljne.

Meni se ovo čini sasvim OK dizajn baze.

17 godina
offline
MySQL - Pomoć sa upitom

U ovoj tabeli di su zauzetosti se automatski dodaju rezervacije cim se plate, a takodjer, vlasnik moze sam dodavati nekakve custom retzervacije koje je on ostvario van ove aplikacije. Mislim da je ovo najefikasniji i najbolji nacin na koji se to moglo rijesiti.

Mentalist je moj idol...
 
0 0 hvala 0
15 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom
naxeem kaže...
Taj tvoj query vratit će mu kupus tj. sve apartmane. Po kojoj logici si ti slagao i čemu LEFT JOIN? Znaš li ti što znači LEFT, a što INNER join?

 

Nema tog optimizatora koji će okrenuti subselect za svaki apartman u upitu, a subselecti su redovito u praksi brži od joina.

 

Ha gle, apartmani koji nemaju niti jedan redak u tablici zauzetost su slobodni u svim terminima. Ako koristis inner join nece ti se pojavit apartmani koji nemaju niti jedan redak u tablici zauzetost jer ih nece moc joinat. Kad koristis left join onda se sigurno pojavljuju svi redci iz tablice apartman, a oni koji nemaju niti jedan zauzet termin ce imat za zauzetost.od i zauzetost.do vrijednost null. Zato imam ekstra dio u where-u.

 

U ovom slucaju vjerojatno ne postoji optimizator koji ce zavrtit subselect vise puta, ali to nije slucaj za svaki subselect. Bolje je pravilno nesto napisat nego se nadat da ce optimizator popravit tvoje greske.

 

A izjavu da su subselectovi brzi od joinova samo pokazuje nepoznavanje nacina na koji radi baza podataka. Evo ti primjer... recimo da radis join na tablicu preko indeksa to je neka log(n) slozenost. Ako koristis subselect nemas indeks, jer je subselect neki medjurezultat. Sad optimizator moze procjenit da mu se isplati napravit indeks nad tim medjurezultatom, ali to stvaranje indeksa i dalje kosta.

17 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom
Blakc kaže...
naxeem kaže...
Taj tvoj query vratit će mu kupus tj. sve apartmane. Po kojoj logici si ti slagao i čemu LEFT JOIN? Znaš li ti što znači LEFT, a što INNER join?

 

Nema tog optimizatora koji će okrenuti subselect za svaki apartman u upitu, a subselecti su redovito u praksi brži od joina.

 

Ha gle, apartmani koji nemaju niti jedan redak u tablici zauzetost su slobodni u svim terminima. Ako koristis inner join nece ti se pojavit apartmani koji nemaju niti jedan redak u tablici zauzetost jer ih nece moc joinat. Kad koristis left join onda se sigurno pojavljuju svi redci iz tablice apartman, a oni koji nemaju niti jedan zauzet termin ce imat za zauzetost.od i zauzetost.do vrijednost null. Zato imam ekstra dio u where-u.

 

U ovom slucaju vjerojatno ne postoji optimizator koji ce zavrtit subselect vise puta, ali to nije slucaj za svaki subselect. Bolje je pravilno nesto napisat nego se nadat da ce optimizator popravit tvoje greske.

 

A izjavu da su subselectovi brzi od joinova samo pokazuje nepoznavanje nacina na koji radi baza podataka. Evo ti primjer... recimo da radis join na tablicu preko indeksa to je neka log(n) slozenost. Ako koristis subselect nemas indeks, jer je subselect neki medjurezultat. Sad optimizator moze procjenit da mu se isplati napravit indeks nad tim medjurezultatom, ali to stvaranje indeksa i dalje kosta.

Opet ti o nekom nepoznavanju. Nije fer da tako razgovaraš i da si bezobrazan, posebno nakon ovog upita. Mislim, nije mi baš jasna tvoja logika ni odakle crpiš to?

Bazu sam kreirao tako da približava ono što je tnakir opisao.

 

Baza izgleda ovako (s mojim "malim" podacima).

 

USE [apartmanitest
GO
/****** Object:  Table [dbo].[apartman]    Script Date: 05/09/2011 13:16:08 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[apartman](
    [apartmanid] [int] IDENTITY(1,1) NOT NULL,
    [apartmanname] [nvarchar](50) NOT NULL,
 CONSTRAINT [PK_apartmani] PRIMARY KEY CLUSTERED
(
    [apartmanid] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[apartman] ON
INSERT [dbo].[apartman] ([apartmanid], [apartmanname]) VALUES (1, N'apartman001')
INSERT [dbo].[apartman] ([apartmanid], [apartmanname]) VALUES (2, N'apartman002')
INSERT [dbo].[apartman] ([apartmanid], [apartmanname]) VALUES (3, N'apartman003')
INSERT [dbo].[apartman] ([apartmanid], [apartmanname]) VALUES (4, N'apartman004')
INSERT [dbo].[apartman] ([apartmanid], [apartmanname]) VALUES (5, N'apartman005')
INSERT [dbo].[apartman] ([apartmanid], [apartmanname]) VALUES (6, N'apartman006')
INSERT [dbo].[apartman] ([apartmanid], [apartmanname]) VALUES (7, N'apartman007')
INSERT [dbo].[apartman] ([apartmanid], [apartmanname]) VALUES (8, N'apartman008')
INSERT [dbo].[apartman] ([apartmanid], [apartmanname]) VALUES (9, N'apartman009')
INSERT [dbo].[apartman] ([apartmanid], [apartmanname]) VALUES (10, N'apartman010')
SET IDENTITY_INSERT [dbo].[apartman] OFF
/****** Object:  Table [dbo].[zauzetost]    Script Date: 05/09/2011 13:16:08 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[zauzetost](
    [zauzetostid] [int] IDENTITY(1,1) NOT NULL,
    [apartmanid] [int] NOT NULL,
    [od] [date] NOT NULL,
    [do] [date] NOT NULL,
 CONSTRAINT [PK_rezervacije] PRIMARY KEY CLUSTERED
(
    [zauzetostid] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[zauzetost] ON
INSERT [dbo].[zauzetost] ([zauzetostid], [apartmanid], [od], [do]) VALUES (3, 1, CAST(0xCC330B00 AS Date), CAST(0xD1330B00 AS Date))
INSERT [dbo].[zauzetost] ([zauzetostid], [apartmanid], [od], [do]) VALUES (4, 1, CAST(0xD1330B00 AS Date), CAST(0xD6330B00 AS Date))
INSERT [dbo].[zauzetost] ([zauzetostid], [apartmanid], [od], [do]) VALUES (5, 2, CAST(0xBD330B00 AS Date), CAST(0xC0330B00 AS Date))
INSERT [dbo].[zauzetost] ([zauzetostid], [apartmanid], [od], [do]) VALUES (6, 3, CAST(0xB9330B00 AS Date), CAST(0xC7330B00 AS Date))
INSERT [dbo].[zauzetost] ([zauzetostid], [apartmanid], [od], [do]) VALUES (7, 5, CAST(0xD3330B00 AS Date), CAST(0xD6330B00 AS Date))
INSERT [dbo].[zauzetost] ([zauzetostid], [apartmanid], [od], [do]) VALUES (8, 6, CAST(0xBF330B00 AS Date), CAST(0xC4330B00 AS Date))
INSERT [dbo].[zauzetost] ([zauzetostid], [apartmanid], [od], [do]) VALUES (9, 9, CAST(0xBA330B00 AS Date), CAST(0xCE330B00 AS Date))
SET IDENTITY_INSERT [dbo].[zauzetost] OFF
/****** Object:  ForeignKey [FK_rezervacije_apartmani]    Script Date: 05/09/2011 13:16:08 ******/
ALTER TABLE [dbo].[zauzetost]  WITH CHECK ADD  CONSTRAINT [FK_rezervacije_apartmani] FOREIGN KEY([apartmanid])
REFERENCES [dbo].[apartman] ([apartmanid])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[zauzetost] CHECK CONSTRAINT [FK_rezervacije_apartmani]
GO

 

Skripte koje su nam na raspolaganju, tvoja skripta, tnakirova skripta, pa zatim moja i mrkačeva izgledaju ovako:

 

--blakcov
-- SELECT Apartman.apartmanid FROM Apartman LEFT JOIN Zauzetost ON Zauzetost.ApartmanID = Zauzetost.ApartmanID WHERE NOT (Zauzetost.OD <= '1/12/2011' AND Zauzetost.DO >= '1/22/2011') OR ( Zauzetost.Od is NULL AND Zauzetost.DO IS NULL) group by apartman.apartmanid

--tnakirov
-- SELECT apartman.apartmanid FROM Apartman INNER JOIN Zauzetost ON Apartman.ApartmanID = Zauzetost.ZauzetostID WHERE NOT (Zauzetost.Od <= '1/12/2011' AND Zauzetost.Do >= '1/22/2011') group by apartman.apartmanid

--moj
-- select apartman.apartmanid from apartman where apartmanid not in (select apartmanid from zauzetost where '1/12/2011' <= do AND od <= '1/22/2011')

--mrkačev
-- select ApartmanId from apartman where ApartmanId not in (select apartmanId from Zauzetost where od<='1/22/2011' and do>='1/12/2011')

E sad, ja sam unio ručno par termina i izvrtio skripte.

Ovako je to izgledalo u praksi za male podatke:

 

Sadržaj:

apartmanid  apartmanname
----------- --------------------------------------------------
1           apartman001
2           apartman002
3           apartman003
4           apartman004
5           apartman005
6           apartman006
7           apartman007
8           apartman008
9           apartman009
10          apartman010

(10 row(s) affected)
(1 row(s) affected)
zauzetostid apartmanid  od         do
----------- ----------- ---------- ----------
3           1           2011-01-20 2011-01-25
4           1           2011-01-25 2011-01-30
5           2           2011-01-05 2011-01-08
6           3           2011-01-01 2011-01-15
7           5           2011-01-27 2011-01-30
8           6           2011-01-07 2011-01-12
9           9           2011-01-02 2011-01-22

(7 row(s) affected)

 

A ovako to izgleda kad izvršimo upite za skripte:

 

--blakcov
 SELECT Apartman.apartmanid FROM Apartman LEFT JOIN Zauzetost ON Zauzetost.ApartmanID = Zauzetost.ApartmanID WHERE NOT (Zauzetost.OD <= '1/12/2011' AND Zauzetost.DO >= '1/22/2011') OR ( Zauzetost.Od is NULL AND Zauzetost.DO IS NULL) group by apartman.apartmanid

--tnakirov
 SELECT apartman.apartmanid FROM Apartman INNER JOIN Zauzetost ON Apartman.ApartmanID = Zauzetost.ZauzetostID WHERE NOT (Zauzetost.Od <= '1/12/2011' AND Zauzetost.Do >= '1/22/2011') group by apartman.apartmanid

--moj
 select apartman.apartmanid from apartman where apartmanid not in (select apartmanid from zauzetost where '1/12/2011' <= do AND od <= '1/22/2011')

--mrkačev
 select ApartmanId from apartman where ApartmanId not in (select apartmanId from Zauzetost where od<='1/22/2011' and do>='1/12/2011')


 

apartmanid
-----------
1
2
3
4
5
6
7
8
9
10

(10 row(s) affected)
(1 row(s) affected)


apartmanid
-----------
3
4
5
6
7
8

(6 row(s) affected)
(1 row(s) affected)


apartmanid
-----------
2
4
5
7
8
10

(6 row(s) affected)
(1 row(s) affected)


ApartmanId
-----------
2
4
5
7
8
10

(6 row(s) affected)
(1 row(s) affected)

 

Onda sam krenuo probati kako to izgleda na većem setu podataka jer mi je tvoj upit smrdio. Dakle, pomoću posebnog inhouse alata u bazu sam unio 10.000 apartmana i 120.000 rezervacija po posve slučajnom sistemu.

Izvršavanje tvoje skripte diglo je temperaturu moje radne stanice na 65°C (s alarmom o temperaturi) iako u normalnom radu ne prelazi 40°C. Izvršavanje je trajalo 88 sekundi, a vratilo je 10.000 apartmana, točno onoliko apartmana koliko se i nalazi u bazi podataka.

Tnakirov upit trajao je 48-7 milisekundi i vratio je 9691 apartman.

Moj upit je trajao 20-16 milisekundi i vratio je 4883 apartmana.

Mrkačev je trajao 21-19 milisekundu i vratio je 4883 apartmana.

 

4883 apartmana je otprilike i logičan statistički rezultat u saturiranoj bazi nakon generatora.

 

Nisam mogao vjerovati kakvo si to smeće napisao pa sam OPET pokrenuo tvoj upit i trajao je jednakih 88 sekundi. Na stranu to što ni tvoj ni tnakirov upit ne daju točne rezultate, ti si uspio što sam mislio da je nemoguće i što nije uspjela konverzija 4 FHD videa paralelno: uspio si i7-975 @4.6GHz s 4 jezgre i 4 virtualne jezgre doslovno priklati na jednu i pol minutu i dignuti mi alarm termosenzora na 65°C što nije uspio ni Crysis 2 na 2560 i max detaljima.

 

Svaka ti čast, ako nešto znaš to je db programiranje i kako rade baze. Svakako preporučam tnakiru da upotrijebi tvoju, optimiziranu verziju, jer MS SQL Server i njegov optimizator očito jako vole tvoj stil jer je tvoj execution plan na SQL Serveru uvjerljivo najkompleksniji i optimizator je sasvim prozviždao izvodeći svašta ludo nad podacima da bi izveo tvoj upit koji, da bude gore, uvijek vrati sve apartmane. Možda prođeš kao marketing Intelu i AMD-u: "trebamo snažnija računala za apartmanske trivijalnosti!".

 

Mislim, nemoj se uvrijediti, ja sam samo zdravo-seljački testirao sve navedeno s nikakvim lošim namjerama.

Poruka je uređivana zadnji put pon 9.5.2011 14:14 (naxeem).
15 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom
ups... imam bug :)
ali to je tolko jasno da je slucajno da se uopce ne broji... join treba naravno bit apartman.apartmanId = zauzetost.apartmanId
17 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom
Blakc kaže...
ups... imam bug :)
ali to je tolko jasno da je slucajno da se uopce ne broji... join treba naravno bit apartman.apartmanId = zauzetost.apartmanId

{#}

OK, imaš bug (baš ti je simpa bio), ali hoćeš reći da je ovo bolje:

 

--blakcov
 SELECT Apartman.apartmanid FROM Apartman LEFT JOIN Zauzetost ON apartman.apartmanId = zauzetost.apartmanId WHERE NOT (Zauzetost.OD <= '1/12/2011' AND Zauzetost.DO >= '1/22/2011') OR ( Zauzetost.Od is NULL AND Zauzetost.DO IS NULL) group by apartman.apartmanid

 

I dalje vraćaš:

apartmanid
-----------
1
2
3
4
5
6
7
8
10

(9 row(s) affected)

 

Kako to odgovara upit između 12. i 22. siječnja 2011 za ove podatke:

zauzetostid apartmanid  od         do
----------- ----------- ---------- ----------
3           1           2011-01-20 2011-01-25
4           1           2011-01-25 2011-01-30
5           2           2011-01-05 2011-01-08
6           3           2011-01-01 2011-01-15
7           5           2011-01-27 2011-01-30
8           6           2011-01-07 2011-01-12
9           9           2011-01-02 2011-01-22

(7 row(s) affected)

Vratio si apartmane koji su zauzeti unutar traženog raspona.

Poruka je uređivana zadnji put pon 9.5.2011 14:28 (naxeem).
17 godina
offline
MySQL - Pomoć sa upitom

Hvala Mrkač, a posebno hvala Naxeemu na podrobnoj analizi :))) Apartmana ce biti <= 100, rezervacija ce biti mozda 20x toliko :)))) Ovo bi se i na accessu vrtilo bez greske, a ne na mysqlu :)

 

Ugl... danas cu to rijesit ako uvatin vrimena :) Naxeem placam pivo na iducem ITProu ako se susretnemo, Mrkac, tebi saljem virtualnu ;)

Mentalist je moj idol...
 
0 0 hvala 0
17 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom
tnakir kaže...

Hvala Mrkač, a posebno hvala Naxeemu na podrobnoj analizi :))) Apartmana ce biti <= 100, rezervacija ce biti mozda 20x toliko :)))) Ovo bi se i na accessu vrtilo bez greske, a ne na mysqlu :)

 

Ugl... danas cu to rijesit ako uvatin vrimena :) Naxeem placam pivo na iducem ITProu ako se susretnemo, Mrkac, tebi saljem virtualnu ;)

I blakc je zaslužio pivo :) Samo da popravi ovaj rezultat. Ono u mojoj analizi je bug u njegovom uvjetu, pa ne traje toliko. Sada je bitno vidjeti kako blakc optimizira upit da daje apartmane koji nemaju rezervaciju unutar traženog raspona. Mrkačev i moj su praktički isti, a Blakcov je baziran na JOIN-u i navodno je brži.

Kad dobijemo iste rezultate, onda ću rado pokrenuti test da vidimo brzinu :)

 

Nema razlog da oblokavanje pivom ne zakači i blakca, barem će manje bugova pisati pijan. :P

---

Da dodam: Blakcova skripta se u prosjeku (nad velikim setom podataka) vrti 65ms, dok se moja vrti 16ms. Inače, Blakc je u pravu kad kaže da je u teoriji subquery može ići za svaki red outer joina, ali meni se u praksi u ovom slučaju (ne vraćamo iste rezultate, oprez) pokazuje bržim subquery, nego join. Ja subquery koristim s virtualnim tablicama, ne direktno ovako. Postoji i velika mogućnost da server u praksi interno pretvara ove subqueryje u join. U nekim slučajevima mi se pokazalo (malo sam raširio test) da je subquery brži, a u nekima obrnuto, da je brži join. Stvar ovisi o dosta toga (i kompleksnosti također). Zapravo, možda će u MySQL-u rezultat biti bitno drugačiji (ja koristim SQL Server 2008R2).

 

Svakako, mislim da je malo nezahvalno nadmetati se i svađati oko ovoga. Tema je vrlo promjenjiva.

 

Poruka je uređivana zadnji put pon 9.5.2011 15:35 (naxeem).
15 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom
naxeem kaže...
tnakir kaže...

Hvala Mrkač, a posebno hvala Naxeemu na podrobnoj analizi :))) Apartmana ce biti <= 100, rezervacija ce biti mozda 20x toliko :)))) Ovo bi se i na accessu vrtilo bez greske, a ne na mysqlu :)

 

Ugl... danas cu to rijesit ako uvatin vrimena :) Naxeem placam pivo na iducem ITProu ako se susretnemo, Mrkac, tebi saljem virtualnu ;)

I blakc je zaslužio pivo :) Samo da popravi ovaj rezultat. Ono u mojoj analizi je bug u njegovom uvjetu, pa ne traje toliko. Sada je bitno vidjeti kako blakc optimizira upit da daje apartmane koji nemaju rezervaciju unutar traženog raspona. Mrkačev i moj su praktički isti, a Blakcov je baziran na JOIN-u i navodno je brži.

Kad dobijemo iste rezultate, onda ću rado pokrenuti test da vidimo brzinu :)

 

Nema razlog da oblokavanje pivom ne zakači i blakca, barem će manje bugova pisati pijan. :P

---

Da dodam: Blakcova skripta se u prosjeku (nad velikim setom podataka) vrti 65ms, dok se moja vrti 16ms. Inače, Blakc je u pravu kad kaže da je u teoriji subquery može ići za svaki red outer joina, ali meni se u praksi u ovom slučaju (ne vraćamo iste rezultate, oprez) pokazuje bržim subquery, nego join. Ja subquery koristim s virtualnim tablicama, ne direktno ovako. Postoji i velika mogućnost da server u praksi interno pretvara ove subqueryje u join. U nekim slučajevima mi se pokazalo (malo sam raširio test) da je subquery brži, a u nekima obrnuto, da je brži join. Stvar ovisi o dosta toga (i kompleksnosti također). Zapravo, možda će u MySQL-u rezultat biti bitno drugačiji (ja koristim SQL Server 2008R2).

 

Svakako, mislim da je malo nezahvalno nadmetati se i svađati oko ovoga. Tema je vrlo promjenjiva.

 

Sry, tu se desio cijeli niz gresaka s moje strane. Prvo sam gledao dal je mrkacev uvjet dobar i vidio da je pa sam predpostavio da ga je tnakir samo negirao i koristio join. Tu sam vidio da nece dobit sve rezultate jer nece dobit apartmane koji nisu imali niti jednu rezervaciju jer se nece pojavit u joinu. To se rijesi left joinom i dodatkom or is null u where, samo sto mi se nije dalo pisat pa sam kopirao tnakirov uvjet. Dakle query bi trebao ovako izgledat (sad cu pazit sta pisem ) :)

 

select distinct apartman.apartmanId from apartman left join zauzetost on zauzetost.apartmanid = apartman.apartmanid where not('1/12/2011' <= do AND od <= '1/22/2011') or ( od is null)

 

U ovom slucaju subselect se vrlo vjerojatno desava samo jednom i razlika u brzini bi trebala bit vrlo mala, ali i dalje stojim iza toga da treba koristi join ako je moguce a ne se oslanjat na optimizator.

 

 

Isprika radi greske.

 

 

17 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom
Mislim da opet imas gresku, ali vidjet cemo kad dodem do racunala, a ne s moba :P
15 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom

bome imam, moram priznat da je tu subselect bolja opcija

17 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom
Blakc kaže...

bome imam, moram priznat da je tu subselect bolja opcija

Skužio si. Vraća i one koji barem jednom spadaju pod validne, jer nije svjestan iteracije kroz druge rezervacije. Takav upit će vratit i apartman #1 iz mog seta podataka. Zato i jest tu :)

 

E sad, probaj s joinom riješit taj problem. :)

15 godina
neaktivan
offline
Re: MySQL - Pomoć sa upitom

evo s joinom... nije bas lijepo, ali bas me zanima kako ce radit.. ako ti se da izvrtit onaj test sa puno podataka

 

 

select distinct apartman.apartmanId

from apartman left join zauzetost on zauzetost.apartmanid = apartman.apartmainid and ('1/12/2011' <= do AND od <= '1/22/2011')

where do is null

 

 

dakle malo objasnjenje kako radi bi vjerojatno bilo korisno... kaze ovako.. uzmi sve apartmane i joinaj sa nekim i zauzetosti s kojim se sijece... ako ne mozes nac takav onda radi left joina joinaj sa null

 

e sad.. svi apartmani koji su joinani sa null nemaju niti jednu rezervaciju u tom terminu inace bi se s njom joinali... pa where do is null filtrira slobodne apartmane

 

Poruka je uređivana zadnji put pon 9.5.2011 19:28 (Blakc).
Nova poruka
E-mail:
Lozinka:
 
vrh stranice