Men n r jeg s inde i den l kke det giver vil tilgribe en anden tabel, g r det galt. Den ser ud til helt at ignorere at den skal kigge i denne anden tabel.
Det g r fint med at hente variablerne fra den f rste tabel: $pid, $overskrift, $tekst og $dato.
Men n r jeg s skal ind i tabellen "brugere" (for at se hvilket brugernavn der h rer til det p g ldende bruger-id), henter den ingenting.
Den echo "<p>---</p>"; som jeg har indsat i den l kke echoes slet ikke, hvilket for mig tyder p at den slet ikke kommer ind i det if-statement.
Philip Nunnegaard wrote:
> Den 22-07-2012 22:33, Philip Nunnegaard skrev:
> [snip noget om prepared statements]
> Det h rer muligvis hjemme i databasegruppen, men jeg tror mere at det er
> noget php-kode jeg ikke forst r ordentligt.
Det er det ogs .
Parametre angives med ? som du ogs kan se i din henvisning.
Denne s tning:
if ($stmt1 = $mysqli->prepare('select navn from brugere where id=pid')) {
s ger p id=pid, hvilket egentlig burde give en fejl fra databasen, da pid
ikke er en parameter, ej eller et tal.
Skulle nok hedde:
if ($stmt1 = $mysqli->prepare('select navn from brugere where id=?')) {
> Det h rer muligvis hjemme i databasegruppen, men jeg tror mere at det er > noget php-kode jeg ikke forst r ordentligt.
> Jeg ved fx heller ikke hvad "->" betyder.
//Henter brugernavn
if ($stmt1 = $mysqli->prepare('select navn from brugere where id=pid'))
$stmt1->bind_param('i', $id);
$id = $pid;
$stmt1->execute();
$stmt1->bind_result($navn);
Som Stig siger, skal det formentlig v re
if ($stmt1 = $mysqli->prepare('select navn from brugere where id=?'))
og b r svjks derefter virke efter hensigten.
$mysqli og $stmt er objekter. De har b de v rdier og funktioner "indbygget".
Man bruger notationen -> til at kalde objekters funktioner/l se v rdier. F.eks. kalder $stmt->fetch() $stmt objektets fetch() funktion, og $stmt->errno l ser fejlkode og $stmt->num_rows giver antallet af r kker i sidste foresp gsel.
> Som Stig siger, skal det formentlig v re
> if ($stmt1 = $mysqli->prepare('select navn from brugere where id=?'))
> og b r svjks derefter virke efter hensigten.
Det g r det s ikke.
Har rettet kodesnippen mellem //Henter brugernavn og //Slut p brugernavn til:
if ($stmt1 = $mysqli->prepare('select navn from profil where id=?')) {
$stmt1->bind_param('i', $id);
$id = $pid;
$stmt1->execute();
$stmt1->bind_result($navn);
while ($stmt1->fetch()) {
$pnavn = $navn;
}
$stmt1->close();
echo "---";
}
Jeg har ogs fors gt at ndre
while ($stmt1->fetch()) {
$pnavn = $navn;
}
til
$pnavn = $navn;
Begge dele uden held.
> sqli og $stmt er objekter. De har b de v rdier og funktioner
> "indbygget".
Det er nok det der med objekter der er problemet. Jeg forst r ikke konceptet. Jeg har fx sv rt ved at forst hvordan en variabel pludselig kan blive lig med en funktion, s dan som man ser det i denne linje:
if ($stmt1 = $mysqli->prepare('select navn from profil where id=?'))
> Man bruger notationen -> til at kalde objekters funktioner/l se v rdier.
> F.eks. kalder $stmt->fetch() $stmt objektets fetch() funktion, og
> $stmt->errno l ser fejlkode og $stmt->num_rows giver antallet af r kker
> i sidste foresp gsel.
>> Som Stig siger, skal det formentlig v re
>> if ($stmt1 = $mysqli->prepare('select navn from brugere where id=?'))
>> og b r svjks derefter virke efter hensigten.
> Det g r det s ikke.
> Har rettet kodesnippen mellem //Henter brugernavn og //Slut p brugernavn > til:
> if ($stmt1 = $mysqli->prepare('select navn from profil where id=?')) {
> $stmt1->bind_param('i', $id);
> $id = $pid;
> $stmt1->execute();
> $stmt1->bind_result($navn);
> while ($stmt1->fetch()) {
> $pnavn = $navn;
> }
> $stmt1->close();
> echo "---";
> }
Pr v evt
$id = $pid;
$query1 = "SELECT navn FROM profil WHERE id=?";
if (($stmt1 = $mysqli->prepare($query1)) &&
$stmt1->bind_param('i', $id) &&
$stmt1->execute() &&
$stmt1->bind_result($navn) {
while ($stmt1->fetch()) {
$pnavn = $navn;
}
$stmt1->close();
echo "---";
...
}
else {
echo $mysqli->error;
}
Det burde vist nok fort lle hvorfor det g r galt...
> Jeg har ogs fors gt at ndre
> while ($stmt1->fetch()) {
> $pnavn = $navn;
> }
> til
> $pnavn = $navn;
> Begge dele uden held.
Det f rste er rigtigt.
execute() udf rer prepare funktionen, men leverer ikke noget resultat (ud over sand hvis OK og falsk hvis der optr der fejl): resultatet skal hentes med fetch()
>> sqli og $stmt er objekter. De har b de v rdier og funktioner
>> "indbygget".
> Det er nok det der med objekter der er problemet. Jeg forst r ikke konceptet. > Jeg har fx sv rt ved at forst hvordan en variabel pludselig kan blive lig > med en funktion, s dan som man ser det i denne linje:
> if ($stmt1 = $mysqli->prepare('select navn from profil where id=?'))
prepare funktionen returnerer et object. S $stmt1 er et object - ikke en funktion.
>> Man bruger notationen -> til at kalde objekters funktioner/l se v rdier.
>> F.eks. kalder $stmt->fetch() $stmt objektets fetch() funktion, og
>> $stmt->errno l ser fejlkode og $stmt->num_rows giver antallet af r kker
>> i sidste foresp gsel.
Inden nedenstående kode, og pak den inde i en try-catch, hvor du
fanger mysqli_sql_exception. Hvis du får for meget brok over indexer,
kan du ændre konstanten til MYSQLI_REPORT_ERROR i stedet.
>> "Commands out of sync; you can't run this command now"
> Det ser ud til at problemet er l st.
> Pr ver jeg at ndre $mysqli til $mysqli1, f r jeg at vide at funktionen ikke > kan k res p et non-object.
> Jeg t nkte om l sningen er at oprette objektet $mysqli1.
> S l sningen var at inds tte nedenst ende linje lige f r
> if ($stmt1 = $mysqli1->prepare... (bem rk $mysqli er ndret til $mysqli1).
> Lige over dette if-statement oprettes objektet $mysqli1:
> $mysqli1 = new mysqli("servernavn", "databasebruger", "kode", > "databasenavn");
> S virker det som nsket.
Du arbejder s med 2 forbindelser til databasen. Og det er vel ogs godt nok ;>)
Problemet er, at mysqli ikke kan arbejde med mere end een prepared statement, s det g r galt n r du bruger fetch() i begge l kker.
Eftersom du bruger pid fra det f rste udtr k, kan du i anden l kke n jes med en almindelig query - under foruds tning af det pid du bruger er et id genereret af programmet eller databasen (antager at du bruger databasens indbyggede auto-nummerering). S er dit input ikke fra brugeren, og der er ingen risiko ved en almindelig query, og den indre l kke kan bruge $mysqli->query($query).
Der er andre m der at omg problemet - dine data kan hentes med en join - og jeg mener ogs der er mulighed for at store data, s der faktisk kan arbejdes med 2 prepared statements.
Men det er nok lidt langh ret for dig, endnu... ;>)
> Du arbejder s med 2 forbindelser til databasen. Og det er vel ogs godt
> nok ;>)
Det slog mig ogs , og helt tilfredsstillende synes jeg ikke at det er, men et gennembrud er det i det mindste for mig.
P et tidspunkt ryger jeg op p 3 forbindelser. Senere i "yderl kken" henter jeg f rst tilknyttede tag-id'er og ud fra den id henter jeg s det ord der h rer til tag-id'en (alts for at hente de tags der er knyttet til indl gget/artiklen). Samme sag med kategorier.
> Problemet er, at mysqli ikke kan arbejde med mere end een prepared
> statement, s det g r galt n r du bruger fetch() i begge l kker.
Jeg forst r det s dan at man kun kan k re n foresp rgsel pr. forbindelse n r man arbejder med prepared statements?
Man kan selvf lgelig sige at i langt de fleste tilf lde vil jeg kun skulle basere n af l kkerne p input fra brugeren, men s ryger jeg vel alligevel op i 2 forbindelser: En med prepared statements plus en "almindelig" gammeldags mysql-forbindelse.
En anden m de jeg overvejede at l se det p , f r jeg kom p nuv rende l sning, var at smide alle data fra yderl kken ind i et almindeligt array og s derefter l be de efterf lgende tabeller igennem.
M ske er det (af flere onder) bedre end at k re med flere forbindelser p en gang?
Philip Nunnegaard <nunnenos...@hitsurf.dk> writes:
> Birger Sørensen skrev:
> > Du arbejder så med 2 forbindelser til databasen. Og det er vel også godt
> > nok ;>)
> Det slog mig også, og helt tilfredsstillende synes jeg ikke at det er,
> men et gennembrud er det i det mindste for mig.
Du har ret i at det ikke er godt, og strengt taget er det heller ikke
nødvendigt.
Du kan omskrive dit SQL statement, så du kan nøjes med en forespørgsel:
SELECT pid, overskrift, tekst, dato, navn FROM indlaeg LEFT JOIN brugere on indlaeg.pid = brugere.id
ORDER BY id DESC LIMIT 0,5
(Med forbehold for at der er en stavebøf et sted)
> På et tidspunkt ryger jeg op på 3 forbindelser. Senere i
> "yderløkken" henter jeg først tilknyttede tag-id'er og ud fra den id
> henter jeg så det ord der hører til tag-id'en (altså for at hente de
> tags der er knyttet til indlægget/artiklen). Samme sag med
> kategorier.
Det bliver et lidt mere langhåret query, men ellers er princippet det
samme som ovenfor. Som udgangspunkt vil jeg forvente at du får bedre
performance ud af at lade databasen gøre så meget arbejde for dig som
muligt.
>> Problemet er, at mysqli ikke kan arbejde med mere end een prepared
>> statement, så det går galt når du bruger fetch() i begge løkker.
> Jeg forstår det sådan at man kun kan køre én forespørgsel
> pr. forbindelse når man arbejder med prepared statements?
Som udgangspunkt, ja. Men du kan bruge mysqli::store_result() til at
gemme et tidligere resultat i en buffer. Jeg har ikke selv brugt den
metode, så jeg ved ikke hvordan det performer, eller hvor let det er
at gå til, men du kan da tage et kig på manualen.
> Man kan selvfølgelig sige at i langt de fleste tilfælde vil jeg kun
> skulle basere én af løkkerne på input fra brugeren, men så ryger jeg
> vel alligevel op i 2 forbindelser: En med prepared statements plus en
> "almindelig" gammeldags mysql-forbindelse.
> En anden måde jeg overvejede at løse det på, før jeg kom på nuværende
> løsning, var at smide alle data fra yderløkken ind i et almindeligt
> array og så derefter løbe de efterfølgende tabeller igennem.
> Måske er det (af flere onder) bedre end at køre med flere forbindelser
> på en gang?
Jeg ville prøve at lave nogle queries, der bruger JOIN og/eller
subselects til at få slutresultatet hevet ud af databasen i en omgang.
-- /Wegge
Leder efter redundant peering af dk.*,linux.debian.*
>> Du arbejder s med 2 forbindelser til databasen. Og det er vel ogs godt
>> nok ;>)
> Det slog mig ogs , og helt tilfredsstillende synes jeg ikke at det er,
> men et gennembrud er det i det mindste for mig.
> P et tidspunkt ryger jeg op p 3 forbindelser. Senere i "yderl kken"
> henter jeg f rst tilknyttede tag-id'er og ud fra den id henter jeg s
> det ord der h rer til tag-id'en (alts for at hente de tags der er
> knyttet til indl gget/artiklen). Samme sag med kategorier.
Til den slags skal du bruge (INNER/LEFT OUTER) JOIN, som Birger skriver.
I den aktuelle 'sag' fra dit indl g kunne du lave et statement som:
SELECT overskrift,tekst,dato FROM indlaeg i
INNER JOIN brugere b ON b.id=i.pid
order by id desc limit 0,5
S har du alle data i et enkelt rowset.
>> Problemet er, at mysqli ikke kan arbejde med mere end een prepared
>> statement, s det g r galt n r du bruger fetch() i begge l kker.
> Jeg forst r det s dan at man kun kan k re n foresp rgsel pr.
> forbindelse n r man arbejder med prepared statements?
Det har ikke rigtig noget med prepared eller ej, men om databasen kan
h ndtere mere end 1 query pr. connection.
'Rigtige' databaser kan h ndtere meget store antal, men f.eks. MS SQLServer
kan kun h ntere 1.
MS SQLServer kloner dog yderligere forbindelser, s omkostningen er ikke s
stor igen.
> En anden m de jeg overvejede at l se det p , f r jeg kom p nuv rende
> l sning, var at smide alle data fra yderl kken ind i et almindeligt
> array og s derefter l be de efterf lgende tabeller igennem.
> M ske er det (af flere onder) bedre end at k re med flere forbindelser
> p en gang?
Nej den bedste l sning er _altid_ at bruge JOIN's til den slags.
P den m de sker arbejdet i databaseserveren og ikke i klienten, med un dig
trafik.
Og lige for en god ordens skyld:
En server og klient er et program, og ikke en maskine, s i dette spil er
dit PHP program klient, og databasen er server.
Anders Wegge Keller wrote:
> Som udgangspunkt vil jeg forvente at du får bedre
> performance ud af at lade databasen gøre så meget arbejde for dig som
> muligt.
Jeg kan se vore indlæg har krydset hinanden.
Indlægget her er blot for at bekræfte dine forventninger, fo man skal
_altid_ lade databasen lave arbejdet i det omfang det er muligt.
Dog skal man være lidt varsom med at lægge forretningslogik i databasen hvis
man samtidig har forretningslogik i programmet.
Den slags giver et vedligeholdelses helvede.
Taler af mere en 32 års erfaring med den slags ;-)
PS: Måske skal vi forklare Phillipo hvad forskeller er på INNER/LEFT
OUTER/RIGHT OUTER - JOIN er - når/hvis han kommer så langt.
Stig Johansen <wopr...@gmail.com> writes:
> Anders Wegge Keller wrote:
> > Som udgangspunkt vil jeg forvente at du får bedre
> > performance ud af at lade databasen gøre så meget arbejde for dig som
> > muligt.
> Jeg kan se vore indlæg har krydset hinanden.
Ja, og heldigvis var vi enige om hvordan de to opslag skulle
kombineres.
> Indlægget her er blot for at bekræfte dine forventninger, fo man
> skal _altid_ lade databasen lave arbejdet i det omfang det er
> muligt.
Erfaringen har lært mig at der ikke går ret lang tid fra man
fremsætter et absolut udsagn onkring performance, før der opstår et
tilfælde der modbeviser udsagnet :/ Som udganspunkt er jeg ganske enig
med dig.
> Dog skal man være lidt varsom med at lægge forretningslogik i
> databasen hvis man samtidig har forretningslogik i programmet.
> Den slags giver et vedligeholdelses helvede.
> Taler af mere en 32 års erfaring med den slags ;-)
Jeg kender det fra den anden side: Forretningslogik i GUI. Det er
nøjagtig lige så slemt.
> PS: Måske skal vi forklare Phillipo hvad forskeller er på INNER/LEFT
> OUTER/RIGHT OUTER - JOIN er - når/hvis han kommer så langt.
Jeg tror du har serveretten der. Jeg kan ihvertfald ikke gøre det
bedre end denne (desværre engelske) wikipedia-artikel om emnet:
<http://en.wikipedia.org/wiki/Join_(SQL)>
-- /Wegge
Leder efter redundant peering af dk.*,linux.debian.*
Birger Sørensen wrote:
> Stig Johansen frembragte:
> 8X
>> PS: Måske skal vi forklare Phillipo hvad forskeller er på INNER/LEFT
>> OUTER/RIGHT OUTER - JOIN er - når/hvis han kommer så langt.
> Det kunne da godt være, at der var nogen af os andre, der kunne have
> glæde af en såden forklaring...?
Selvfølgelig Birger, men den slags er typisk afhængig af den aktuelle
opgave.
Men jeg kan godt lave en kort 'forklaring':
Antag vi har to tabeller A og B.
A indeholder:
id
----
1
2
3
B indeholder
id
----
2
3
4
Nu er jeg gået et (lille) skridt videre i forhold til Philips indlæg, hvor
han har id og pid (så vidt jeg kan se).
Så går vi i gang med nogle forespørgsler.
1) Vi vil gerne have alle id'er fra tabel A - SELECT id FROM A.
Databaser indeholder ikke nogen 'naturlig' rækkefølge, så for at garantere
rækkefølgen skal man have en SORT BY, så 2) SELECT id FROM A ORDER BY id (evt desc for faldende orden).
Nu vil vi gerne sammenkoble de to tabeller og se
3) Hvad er fælles forekomster i de 2 tabeller - SELECT t1.id FROM A t1 INNER
JOIN B t2 ON t2.id=t1.id
Resultatet bliver:
id
-----
2
3
Her fortæller vi databasen hvilke felter der skal matche, id i begge
tilfælde.
Men når man bruger samme feltnavn skal databasen skelne mellem 'ambiguity',
så derfor bruges alias, så A -> t1 og B -> t2.
INNER JOIN giver med andre ord 'fællesmængeden' mellem de to tabeller.
Vi kan også stille et andet spørgsmål:
"Giv mig alle data fra A med tilhørende data fra B uanset om der er et
'tilhørsforhold'.
Det giver dette SQL:
4) SELECT t1.id AS f1, t2.id AS f2 FROM A t1 LEFT OUTER JOIN B t2 on
t2.id=t1.id
og resultatet:
f1 f2
---- -----
1 null
2 2
3 3
Denne SQL kan også bruges til at finde ikke sammenhængende entries i tabel B
ved at udvide den med en where klausul:
5) SELECT t1.id AS f1, t2.id AS f2 FROM A t1 LEFT OUTER JOIN B t2 on
t2.id=t1.id WHERE t2.id IS NULL, så får man kun første række i forhold til
ovenstående.
Så er der RIGHT OUTER JOIN, som jeg aldrig bruger, men det går ud på at se
på tabellerne fra højre mod venster i stedet for venstre mod højre.
I ovenstående eksempel skal man blot bytte om på A og B, og bruge RIGHT i
stedet for LEFT, og resultatet vil være det samme.
Phillip var lidt inde på 3 (eller flere) tabeller, og princippet er det
samme.
F.eks.
SELECT A.id,B.noget,C.noget_mere FROM A t1
(INNER/LEFT OUTER) JOIN B t2 ON t1.noget=t2.noget
(INNER/LEFT OUTER) JOIN C t3 ON t2.noget=t3.noget
......
WHERE 'noget'
ORDER BY 'noget'
....
evt
GROUP BY 'noget' hvis man vil have aggrerede data.
I princippet er vi ovre i .database gruppen, men den er lige så død som alle
de andre, so what....
PS: vær opmærksom på de forskellige afvigelser fra standarden, herunder
Phillips brug af ' som _kun_ virker i mySQL, og vil skabe problemer ved
skift af database.
MS SQLServer indsætter 'automagisk' [ og ], ved brug af deres værktøjer til
SQL generering.
Fjerne alt hvad der ikke er standard, eller helst:
SKRIV DIT SQL SELV!
> Phillip var lidt inde på 3 (eller flere) tabeller, og princippet er det
> samme.
Jeps. På denne måde:
Der findes kun én forfatter (bruger/profil) til hver artikel, så her ville jeg kunne klare den med en simpel sql-sætning der omfatter begge tabeller.
Men der findes flere tags og ligeledes flere kategorier til hver artikel.
> PS: vær opmærksom på de forskellige afvigelser fra standarden, herunder
> Phillips brug af ' som _kun_ virker i mySQL, og vil skabe problemer ved
> skift af database.
Syntaksen til almindelig MySQL minder utroligt meget om syntaksen til en Access-database. I begge tilfælde har jeg normalt brugt " til at afgrænse sql-sætningen og ' inde i sætningen. Fx:
$sql = "insert into tabel (pid,navn) values (1,'Philip')";
I asp med acces skrev jeg "strSQL" i stedet for "$sql" og ingen semikolon i slutningen. Det var eneste forskel.
Tak for din forklaring omkring de forskellige joins.
> Jeg tror du har serveretten der. Jeg kan ihvertfald ikke gøre det
> bedre end denne (desværre engelske) wikipedia-artikel om emnet:
> <http://en.wikipedia.org/wiki/Join_(SQL)>
Philip Nunnegaard <nunnenos...@hitsurf.dk> writes:
> Stig Johansen skrev:
> > Phillip var lidt inde på 3 (eller flere) tabeller, og princippet er det
> > samme.
> Jeps. På denne måde:
> Der findes kun én forfatter (bruger/profil) til hver artikel, så her
> ville jeg kunne klare den med en simpel sql-sætning der omfatter begge
> tabeller.
> Men der findes flere tags og ligeledes flere kategorier til hver artikel.
Hvad er det du har brug for med hensyn til tags og kategorier?
- Finde alle artikler med en bestemt kombination af {tag, kategori}?
- Finde de nyeste artikler, og liste samtlige tags og kategorier?
Og kan du lige give et eksempel på tabelstruktur for hhv. tag og
kategori?
-- /Wegge
Leder efter redundant peering af dk.*,linux.debian.*
Anders Wegge Keller wrote:
> Jeg kender det fra den anden side: Forretningslogik i GUI. Det er
> n jagtig lige s slemt.
Ja, det er ogs grimt, og desv rre ogs brugt.
Det v rste eksempel jeg nogensinde har set er Navision (Stat), som nok er
lavet n sten _perfekt_ forkert, med forretningslogik i SP's, Triggers samit
i klienten (GUI'en).
> Jeg tror du har serveretten der. Jeg kan ihvertfald ikke g re det
> bedre end denne (desv rre engelske) wikipedia-artikel om emnet:
> <http://en.wikipedia.org/wiki/Join_(SQL)>
Den giver en rimelig god forklaring, men jeg er ikke tilfreds med man bruger
SELECT *... i de f rste eksempler.
Man burde fort lle det n rmest er en d dssynd (med mindre man vitterlig skal
bruge _alle_ elementerne).
L ngere nede kommer man ind p implicitte JOINS, som bla. Oracle kun
underst ttede indtil 9i, men jeg vil foresl man altid skriver eksplicitte
JOIN's s optimizeren ikke skal bruge tid p at 'g tte' sig frem.
Men alle har vel deres holdninger - nogle tror det er bedre at lave 'korte'
programmer/SQL, bruger * fordi de er for dovne til at skrive et par
feltnavne osv.