Mi a probléma ezzel az sql lekérdezéssel?
Készítek egy cms rendszert, ami max 3 szintű megnüvel dolgozik majd, azokat elkészíti, és feltölti tartalommal.
A menüpontok táblái így néznek ki:
első tábla:
id->menuname->url
a többi:
id->menuname->url->relation
A menuname az az ékezetes menünév, az url az nyilván az ékezet nélküli, a relation pedig a szülőmenühöz való kapcsolódás.
Tehát ha van egy olyan menürendszerünk, hogy:
szolgáltatások->weboldal->céges weboldal
akkor az első tábla értékei a következők lesznek:
menuname = szolgáltatások
url = szolgaltatasok
második tábla:
menuname = honlapkészítés
url = honlapkeszites
relation = szolgaltatasok
stb...
Törléskor szeretnék inner joint használni, hogy lehúzzam a kapcsolódások url-jét, és aszerint töröljem ki az almenüket is, ha a főmenüt kitörlöm.
Ez lenne az sql kód:
SELECT 'menu_level1.url' AS 'url1', 'menu_level2.url' AS 'url2' FROM `menu_level1` INNER JOIN `menu_level2` ON 'menu_level1.url' = 'menu_level2.relation'
mondjuk két szintű menü esetében.
A gond csak az, hogy hiába van a menu_level1-ben is szolgaltatasok url és a menu_level2-ben is szolgaltatasok relation, üres értéket ad vissza az sql query.
Mit nem értek? A számításaim szerint ennek ebben a formában jónak kéne lennie. Valami ötlet?
A probléma az szimpla idézőjel és a backtick/backquote karakterek keveredéséből van.
` ≠ '
Vagy nem használsz backtick karaktereket, és akkor így néz ki helyesen:
SELECT menu_level1.url AS url1, menu_level2.url AS url2 FROM menu_level1 INNER JOIN menu_level2 ON menu_level1.url = menu_level2.relation
(Persze ebben az esetben nem használhatsz táblanévnek, mezőnévnek foglalt kulcsszót, nem lehet benne szóköz, stb…)
Vagy a backtick/backquote karaktert használod a tábla és mezőneveknél, és akkor így néz ki a dolog:
SELECT `menu_level1`.`url` AS `url1`, `menu_level2`.`url` AS `url2` FROM `menu_level1` INNER JOIN `menu_level2` ON `menu_level1`.`url` = `menu_level2`.`relation`
(Itt a tábla és mezőneveket külön-külön kell backquote jelekkel határolni.)
A szimpla idézőjel szöveghatároló karakter. Mit csinál a te lekérésed? Végigveszi a menu_level1 és a menu_level2 tábla összes sorának kombinációját, és az eredmény sok menüpont esetén egy sok soros tábla lesz, ahol minden sorban az url1 értéke egy szöveg, méghozzá a „menu_level1.url” szöveg. Ezekből a sorokból csak azt tartja meg, ahol a „menu_level1.url” – mint string – egyenlő a „menu_level2.relation”-nal – mint stringgel – de mivel a két string nem lesz azonos soha, egyetlen sor esetén sem, ezért kapsz vissza egy üres táblát.
Hogy jobban megértsd, mi a gond, próbáld ki ezt:
SELECT 'menu_level1.url' AS 'url1' FROM menu_level1
~ ~ ~
De ahogy az első utalt rá, maga az adatbázis felépítése nem éppen „elegáns”, nem felel meg az adatbázisok felépítésétől általában elvárt szabályoknak. Mert hiszen a menu_level1 és a menu_level2 ugyanolyan jellegű adatokat tartalmaz. Ha most kitalálja valaki, hogy legyen egy tooltip szöveg minden fő- és almenüponthoz, akkor két táblát is kell módosítanod. Az egész megoldható egyetlen táblával:
CREATE TABLE menu (
id INT NOT NULL AUTO_INCREMENT,
url VARCHAR(255) NOT NULL,
menuname VARCHAR(255) NOT NULL,
parent INT NULL DEFAULT NULL,
PRIMARY KEY (id));
Vagy ha nem akarod, hogy egy fő- és egy almenünek, vagy két fő-, vagy két almenünek ugyanaz legyen véletlenül az url-je, akkor:
CREATE TABLE menu (
id INT NOT NULL AUTO_INCREMENT,
url VARCHAR(255) NOT NULL,
menuname VARCHAR(255) NOT NULL,
parent INT NULL DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE INDEX url_idx (url ASC));
Ebben az esetben a példád így néz ki:
id ; url ; menuname ; parent
1 ; szolgaltatasok ; Szolgáltatások ; NULL
2 ; honlapkeszites ; Honlapkészítés ; 1
A GYK menüje meg így:
26 ; allatok ; Állatok ; NULL
27 ; allatok_allatvedelem ; Állatvédelem ; 26
28 ; allatok__halak-akvarisztika ; Halak, akvarisztika ; 26
…
328; szamitastechnika ; Számítástechnika ; NULL
329; szamitastechnika__biztonsag ; Biztonság ; 328
330 ; szamitastechnika__hardverek ; Hardverek ; 328
…
További előnye a dolognak, hogy az adatbázis átalakítása nélkül lehet egy harmadik, negyedik, akárhányadik szintet is tárolni így.
~ ~ ~
Le akarod kérni a főmenü elemeit?
SELECT * FROM menu WHERE parent IS NULL;
Le akarod a 328-as azonosítójú (Számítástechnika) menü összes almenüpontját?
SELECT * FROM menu WHERE parent=328;
Törölni akarod a Hardverek menüpontot?
DELETE FROM menu WHERE url='szamitastechnika_hardverek';
vagy
DELETE FROM menu WHERE id=330;
Törölni akarod a Számítástechnika menüt az összes almenüpontjával együtt?
DELETE FROM menu WHERE (id=328) OR (parent=328);
~ ~ ~
Metakritika: Nyugtass meg, hogy nem akarsz így kezdő SQL ismeretekkel és gyakorlattal honlaptervezésbe fogni.
Tényleg nem kötekedni akarok, de ezt őszintén szólva nem értem:
„menu_level1.url” – mint string – egyenlő a „menu_level2.relation”-nal
de mivel a két string nem lesz azonos soha, egyetlen sor esetén sem, ezért kapsz vissza egy üres táblát. "
Miért nem lesz egyenlő soha a két string? Biztos így van, mert nulla sort kapok vissza, de amennyiben a relation is 'szolgaltatasok' valamint az url is 'szolgaltatasok' akkor mi az oka annak, hogy ez a kettő sosem lesz egyenlő?
Azért, mert ez:
menu_level1.url = menu_level2.relation
vagy ez:
`menu_level1`.`url` = `menu_level2`.`relation`
ezek a menu_level1 tábla adott sorának url mezőjét hasonlítják össze a menu_level2 tábla relation mezőjével, és itt mindegy is, hogy ezek a mezők most stringet, számot, dátumot, vagy mit tartalmaznak. Ha történetesen mindkét tábla adott sorának adott mezeje az, hogy 'szolgaltatasok', akkor a kifejezés igaz lesz.
Míg ez:
'menu_level1.url' = 'menu_level2.relation'
(így idézőjelek közé téve) semmiféle tábla semmiféle mezőjét nem veszi, hanem ez két string, mindkét string 'm' karakterrel kezdődik, 'e' karakterrel folytatódik, viszont a bal oldali egy 'l' karakterre, a jobb oldali egy 'n' karakterre végződik. Tulajdonképpen ezt jelenti:
'menu_'+'level'+'1.ur'+'l' = 'me'+'nu_le'+'ve'+'l2.re'+'lati'+'on'
Ez meg soha az életben nem lesz igaz, a 'menu_level1.url' egy 15 karakterből álló string, míg a 'menu_level2.relation' egy 20 karakterbő álló string.
Tulajdonképpen olyan, mintha azt írtad volna, hogy:
… INNER JOIN menu_level2 ON 'alma' = 'körte'
vagy:
… INNER JOIN menu_level2 ON 4 = 5
Ja így már értem, köszönöm szépen! :)
Az a helyzet, hogy pont ezért kezdtem el fejleszteni az sql tudásomat, de kettő, elvileg felsőoktatási célra szánt könyvben nem volt leírva a backquote és a single quote közötti különbség. A w3school vonatkozó oldalán pedig quotation markok nélkül vannak a példák. Amúgy valszeg php-val működött volna a kód, de a phpmyadmin felületén próbáltam így lekérdezni.
De végülis egy netes tutoriálban megtaláltam a választ.
Kapcsolódó kérdések:
Minden jog fenntartva © 2024, www.gyakorikerdesek.hu
GYIK | Szabályzat | Jogi nyilatkozat | Adatvédelem | Cookie beállítások | WebMinute Kft. | Facebook | Kapcsolat: info(kukac)gyakorikerdesek.hu
Ha kifogással szeretne élni valamely tartalommal kapcsolatban, kérjük jelezze e-mailes elérhetőségünkön!