Pogčedajte punu verziju : Explain Query
webarto
24. 06. 2011., 05:24
Please :)
Ovako imam pitanje u vezi querya, radi se o pretrazi atributa, pretražuju se atributi sa id brojem 6 i 8, queryi rade ali ne kako očekujem...
1.
SELECT * FROM resource_attributes
WHERE
(attribute_value LIKE '%La%' AND attribute_id = 6) AND
(attribute_value LIKE '%Ho%' AND attribute_id = 8)
GROUP BY resource_id
Ovo radi kada se umjesto AND stavi OR, ali onda dobijam djelomičnu pretragu, jer oba uslova (zagrade) moraju biti zadovoljena u slučaju da je OR onda je dovoljno samo jedan. U slučaju da je AND explain vraća Impossible WHERE...
2.
SELECT * FROM resource_attributes
WHERE
(attribute_value LIKE '%La%' OR attribute_value LIKE '%Ho%')
AND attribute_id IN(6,8)
GROUP BY resource_id
Ovo radi OK, ali "La" može biti atribut 8 a mora biti atribut 6 i obrnuto.
Pitanje je kako da atribut 6 bude "La" i atribut 8 bude "Ho" i oba uslova budu zadovoljena inače da ne vrati ništa :)
Riješio sam ovo na drugi način jer ima još komplikacija ali me čisto zanima gdje griješim. Hvala.
Tabela:
http://pokit.etf.ba/get/ba21cbe1b4cd176d61aa7269d6a33862.png
jablan
24. 06. 2011., 08:06
oba uslova (zagrade) moraju biti zadovoljena u slučaju da je OR onda je dovoljno samo jedan.
Kako mogu oba da ti budu zadovoljena? Polje attribute_id može biti ili 6 ili 8, ne može biti i 6 i 8 u isto vreme.
Šta ustvari želiš da dobiješ kao rezultat? Po meni, čini se da ti upravo treba ova prva varijanta sa ((AND) OR (AND)).
webarto
24. 06. 2011., 11:58
Ma ne, znam da ne može i treba da ne može, već ovakva je situacija...
resource_id attribute_id attribute_value
1 6 La Iruela
1 8 Hotel
2 8 Hotel
Potreban mi je query, da mi vrati ovaj resource_id da je 1 ako i samo ako atribut 6 sadrži "La" a atribut 8 sadrži "Ho"... ako recimo postoji atribut 8 sa "Ho" a ne postoji atribut 6 sa "La", query bi trebao da vrati ništa. Nadam se da me razumiješ. Hvala.
jablan
24. 06. 2011., 12:07
A pa ne može to tako onda.
Uradi inner join tabele na samu sebe preko resource_id, gde ćeš u where da staviš da leva strana joina ima 6-La, a desna 8-Ho.
Btw, LIKE 'Ho%' je mnogo brže od LIKE '%Ho%', imaj to u vidu.
webarto
24. 06. 2011., 12:23
:)
Ja sam to ovako bio ali mi "ružno" izgleda pogotovo što se pretražuju još par atributa osim ova 2...
SELECT t1.resource_id FROM resource_attributes AS t1
LEFT JOIN resource_attributes AS t2 ON t1.resource_id = t2.resource_id
LEFT JOIN resource_attributes AS t3 ON t1.resource_id = t3.resource_id
WHERE
(t2.attribute_value LIKE '%La%' AND t2.attribute_id = 6) AND
(t3.attribute_value LIKE '%Ho%' AND t3.attribute_id = 8)
GROUP BY t1.resource_id
Znam za Indexe to sam stavio samo reda radi, napravit ću autocomplete iz postojećih vrijednosti u bazi tako da može biti i = umjesto bilo kakvog LIKE, hvala. Ovaj query sa JOIN + LIKE se izvršava za 0.0002s...
jablan
24. 06. 2011., 13:47
Imaš tu jedan join viška. U suštini, treba ti ovo (pretpostavljam):
SELECT *
FROM resources r
LEFT JOIN resource_attributes a_6 ON r.id = r.resource_id AND a_6.attribute_id = 6
LEFT JOIN resource_attributes a_8 ON r.id = r.resource_id AND a_8.attribute_id = 8
WHERE
a_6.attribute_value LIKE 'La%'
AND a_8.attribute_value LIKE 'Ho%'
Nema potrebe za GROUP BY.
webarto
24. 06. 2011., 14:09
Kako si znao da je tabela resources :D
Malo sam prepravio, to je to, svaka čast.
SELECT r.id
FROM resources r
LEFT JOIN resource_attributes a_6 ON r.id = a_6.resource_id AND a_6.attribute_id = 6
LEFT JOIN resource_attributes a_8 ON r.id = a_8.resource_id AND a_8.attribute_id = 8
WHERE
a_6.attribute_value LIKE 'La%'
AND a_8.attribute_value LIKE 'Ho%'
jablan
24. 06. 2011., 14:25
To je konvencija koju uostalom fura i ActiveRecord (http://guides.rubyonrails.org/association_basics.html) (ORM za Rails). BTW, ako ti zaista treba samo id tog resursa (a ne i ostala polja), nema potrebe da se joinuje sa tom tabelom, nego samo:
SELECT a_6.resource_id
FROM resource_attributes a_6
INNER JOIN resource_attributes a_8 ON a_6.resource_id = a_8.resource_id
WHERE
a_6.attribute_id = 6
AND a_8.attribute_id = 8
AND a_6.attribute_value LIKE 'La%'
AND a_8.attribute_value LIKE 'Ho%'
dacha
24. 06. 2011., 16:49
Please :)
1.
SELECT * FROM resource_attributes
WHERE
(attribute_value LIKE '%La%' AND attribute_id = 6) AND
(attribute_value LIKE '%Ho%' AND attribute_id = 8)
GROUP BY resource_id
Ovo tvoje može da radi, bez višestrukih JOIN-a, baš sa OR, ali da izdvojiš samo one zapise koji imaju obadva uslova zadovoljena.
SELECT *, COUNT(*) as broj_atributa FROM resource_attributes
WHERE
(attribute_value LIKE '%La%' AND attribute_id = 6)
OR
(attribute_value LIKE '%Ho%' AND attribute_id = 8)
GROUP BY resource_id
HAVING broj_atributa = 2
webarto
24. 06. 2011., 19:54
@jablan, dobar taj RoR :D Treba mi još kolona to sam ja stavio ID da ne komplikujem, hvala ti i na drugoj soluciji.
@dacha, dobar fazon, nikad mi ne bi palo na pamet :)
dacha
25. 06. 2011., 03:18
SELECT r.id
FROM resources r
LEFT JOIN resource_attributes a_6 ON r.id = a_6.resource_id AND a_6.attribute_id = 6
LEFT JOIN resource_attributes a_8 ON r.id = a_8.resource_id AND a_8.attribute_id = 8
WHERE
a_6.attribute_value LIKE 'La%'
AND a_8.attribute_value LIKE 'Ho%'
Ako je ovo u pitanju - da su ti potrebni podaci iz tabele resources, a podaci iz tabele resource_attributes služe samo za uslov, onda ovoj tabeli nije mesto u FROM već u WHERE. Ovako bih ja uradio ovo što si ti iznad:
SELECT r.id
FROM resources r
WHERE
2 = ( SELECT COUNT(*) FROM resource_attributes ra
WHERE
ra.resource_id = r.id
AND
( attribute_value LIKE '%La%' AND attribute_id = 6
OR
attribute_value LIKE '%Ho%' AND attribute_id = 8))
Ako tabela resource_attributes nije velika i uslov sadrži samo nekoliko atributa, onda je svejedno kako ćeš uraditi (sa JOIN ili ovako). Ali, junction tabele uglavnom sadrže stotine hiljada zapisa (resources x atributes), pa ako se pretraga vrši po malo više atributa, onda će JOIN napraviti set sa milionima zapisa i performanse će biti lošije.
jablan
25. 06. 2011., 08:03
^ Gornji LEFT JOIN će imati tačno onoliko zapisa koliko postoji u resources tabeli. Plus je potpuno logično rešenje pošto simulira proširenje tabele resources custom atributima.
dacha
25. 06. 2011., 18:36
Ne, nisam mislio u konkretnom slučaju, naveo sam ovo baš zbog logike koju pominješ. Meni je logično (i semantički ispravno) da u FROM idu one tabele iz kojih se uzimaju podaci za konačni set zapisa (i naravno one koje su neophodne za njihovo povezivanje), a onim tabelama čiji podaci služe samo kao uslov logično mesto je u WHERE. Gore sam hteo da kažem da se, stavljanjem ovih tabela u FROM ponekad pravi ogroman set zapisa bez potrebe.
Naravno, meni je ovo logično, ne znači da je tako. :)
webarto
26. 06. 2011., 12:56
Da, LEFT JOIN kako ga je jablan napisao vraća tačno resurse recimo 10 i 12, znači 2 reda, bez GROUP BY, isto kao i ovaj drugi tvoj (bez GROUP BY), za isto vremena jer je tabela mala. Hvala ;)
vBulletin® v3.6.8, Copyright ©2000-2024, Jelsoft Enterprises Ltd.