berlinsurfer: ORDER BY Variablenfrage

Hallo, liebe Experten,
meine Frage: kann ich in den ORDER BY-Teil eine Mysql-Variable packen ?
Sprich:

SELECT @myOrder := `orderstring` FROM tabelle WHERE id=1;  
SELECT * FROM tabelle ORDER BY @myOrder;

Ausgeführt wird es (ohne Fehler), nur das Ergebnis stimmt leider nicht...
Hintergrund ist die Speicherung von einer Hierarchie, in der die Kategorien nach verschiedenen Gesichtspunkten (Hits, Daum, Alphabetisch) sortiert werden können sollen.
Vielen Dank schon mal !
Gruß,
berlinsurfer

  1. Hello,

    meine Frage: kann ich in den ORDER BY-Teil eine Mysql-Variable packen ?
    Sprich:

    SELECT @myOrder := orderstring FROM tabelle WHERE id=1;

    SELECT * FROM tabelle ORDER BY @myOrder;

    
    > Ausgeführt wird es (ohne Fehler), nur das Ergebnis stimmt leider nicht...  
    > Hintergrund ist die Speicherung von einer Hierarchie, in der die Kategorien nach verschiedenen Gesichtspunkten (Hits, Daum, Alphabetisch) sortiert werden können sollen.  
      
    Was meinst Du mit "das Ergebnis stimmt leider nicht"?  
      
    Hast Du eventuell zwischen dem Setzen der Variable und dem SELECT einen Roundturn liegen? Wie sprichst Du die Datenbank an? Über die Shell, einen Requester oder per Script und HTTP?  
      
      
      
      
      
    Liebe Grüße aus dem schönen Oberharz  
      
      
    Tom vom Berg  
    ![](http://selfhtml.bitworks.de/Virencheck.gif)  
      
    
    -- 
     ☻\_  
    /▌  
    / \ Nur selber lernen macht schlau  
    <http://bergpost.annerschbarrich.de>
    
    1. Hallo, Tom,
      danke für die schnelle Antwort. Ich habe mir mit phpmyadmin eine Tabelle erstellt:
      id|orderstring|town

      Und ein paar Werte reingepackt (als Städte Berlin, Aachen, Krefeld, Düsseldorf). Wenn ich nun auf der Konsole die o.g. Statements ausführe, kommt als Ergebnis immer nur die Originalsortierung (sprich nach der id  sortiert). Das meinte ich mit "das Ergebnis stimmt leider nicht".
      Danke für deine Bemühungen,
      Jan

      Hello,

      meine Frage: kann ich in den ORDER BY-Teil eine Mysql-Variable packen ?
      Sprich:

      SELECT @myOrder := orderstring FROM tabelle WHERE id=1;

      SELECT * FROM tabelle ORDER BY @myOrder;

      
      > > Ausgeführt wird es (ohne Fehler), nur das Ergebnis stimmt leider nicht...  
      > > Hintergrund ist die Speicherung von einer Hierarchie, in der die Kategorien nach verschiedenen Gesichtspunkten (Hits, Daum, Alphabetisch) sortiert werden können sollen.  
      >   
      > Was meinst Du mit "das Ergebnis stimmt leider nicht"?  
      >   
      > Hast Du eventuell zwischen dem Setzen der Variable und dem SELECT einen Roundturn liegen? Wie sprichst Du die Datenbank an? Über die Shell, einen Requester oder per Script und HTTP?  
      >   
      >   
      >   
      >   
      >   
      > Liebe Grüße aus dem schönen Oberharz  
      >   
      >   
      > Tom vom Berg  
      > ![](http://selfhtml.bitworks.de/Virencheck.gif)  
      >   
      > 
      
      1. Hello,

        Ich habe mir mit phpmyadmin eine Tabelle erstellt:
        id|orderstring|town

        Hast Du eventuell zwischen dem Setzen der Variable und dem SELECT einen Roundturn liegen? Wie sprichst Du die Datenbank an? Über die Shell, einen Requester oder per Script und HTTP?

        Also so, wie ich es vermutet habe. Jedes Statement im PHPmyAdmin wird einzeln abgesetzt, benutzt also immer eine neue Verbindung.

        Daher weiß die DB beim nächsten Statement nicht mehr, was Du beim letzten festgelegt hast.

        Liebe Grüße aus dem schönen Oberharz

        Tom vom Berg

        --
         ☻_
        /▌
        / \ Nur selber lernen macht schlau
        http://bergpost.annerschbarrich.de
        1. Hi!

          Also so, wie ich es vermutet habe. Jedes Statement im PHPmyAdmin wird einzeln abgesetzt, benutzt also immer eine neue Verbindung.

          Diese Schlussfolgerung ist falsch. Der PMA verwendet auch bei Verwendung der PHP-Extension mysql statt mysqli nur eine Verbindung bei mehreren Statements. Man kann das ja ganz einfach nachprüfen, indem man folgendes probiert:

          SET @foo := 42;
            SELECT @foo;

          Ergibt eine Ergebniszeile mit einem Wert 42. In der Hinsicht ist also alles bestens. Die Nicht-Sortierung[*] hat eine andere Ursache: https://forum.selfhtml.org/?t=199341&m=1340970

          [*] Ja, Nicht-Sortierung. Die beobachtete Sortierung nach der ID ist nur scheinbar eine solche und kommt daher, dass zufällig die Datensätze in der Reihenfolge der IDs in der Tabelle liegen und in der Reihenfolge ausgegeben werden.

          Lo!

          1. Hallo, dedlfix,
            danke für die detailierten Ausführungen, in der Tat funktioniert es mit dem pma. Ich hatte auch schon an die prepared statements gedacht, allerdings keine Information darüber gefunden, ob man auch den ORDER BY-Zweig ersetzen kann. Wäre es denn so richtig:

            PREPARE stmt_name FROM "SELECT * FROM testtabelle ORDER BY ?";  
            SET @tparm = "town";  
            EXECUTE stmt_name USING @tparm;  
            
            

            Eine Alternative wäre natürlich, das ORDER-Kriterium vorher in eine php-Variable einzulesen und dann den SQL-Query neu zusammenzusetzen. Ich würde aber eine reine SQL-Lösung bevorzugen (aus Interesse :-)).
            Gruß,
            Jan

            Hi!

            Also so, wie ich es vermutet habe. Jedes Statement im PHPmyAdmin wird einzeln abgesetzt, benutzt also immer eine neue Verbindung.

            Diese Schlussfolgerung ist falsch. Der PMA verwendet auch bei Verwendung der PHP-Extension mysql statt mysqli nur eine Verbindung bei mehreren Statements. Man kann das ja ganz einfach nachprüfen, indem man folgendes probiert:

            SET @foo := 42;
              SELECT @foo;

            Ergibt eine Ergebniszeile mit einem Wert 42. In der Hinsicht ist also alles bestens. Die Nicht-Sortierung[*] hat eine andere Ursache: https://forum.selfhtml.org/?t=199341&m=1340970

            [*] Ja, Nicht-Sortierung. Die beobachtete Sortierung nach der ID ist nur scheinbar eine solche und kommt daher, dass zufällig die Datensätze in der Reihenfolge der IDs in der Tabelle liegen und in der Reihenfolge ausgegeben werden.

            Lo!

            1. Hello,

              danke für die detailierten Ausführungen, in der Tat funktioniert es mit dem pma. Ich hatte auch schon an die prepared statements gedacht, allerdings keine Information darüber gefunden, ob man auch den ORDER BY-Zweig ersetzen kann. Wäre es denn so richtig:

              PREPARE stmt_name FROM "SELECT * FROM testtabelle ORDER BY ?";

              SET @tparm = "town";
              EXECUTE stmt_name USING @tparm;

                
              Ein Beispiel steht im MySQL-Manual  
                
              <http://dev.mysql.com/doc/refman/5.1/en/user-variables.html>  
                
              \--Zitat--:  
              An exception to this principle that user variables cannot be used to provide identifiers is that if you are constructing a string for use as a prepared statement to be executed later. In this case, user variables can be used to provide any part of the statement. The following example illustrates how this can be done:  
                
              mysql> SET @c = "c1";  
              Query OK, 0 rows affected (0.00 sec)  
                
              mysql> SET @s = CONCAT("SELECT ", @c, " FROM t");  
              Query OK, 0 rows affected (0.00 sec)  
                
              mysql> PREPARE stmt FROM @s;  
              Query OK, 0 rows affected (0.04 sec)  
              Statement prepared  
                
              mysql> EXECUTE stmt;  
              +----+  
              | c1 |  
              +----+  
              |  0 |  
              +----+  
              |  1 |  
              +----+  
              2 rows in set (0.00 sec)  
                
              mysql> DEALLOCATE PREPARE stmt;  
              Query OK, 0 rows affected (0.00 sec)  
              \--Zitat Ende--  
                
                
                
                
              Liebe Grüße aus dem schönen Oberharz  
                
                
              Tom vom Berg  
              ![](http://selfhtml.bitworks.de/Virencheck.gif)  
                
              
              -- 
               ☻\_  
              /▌  
              / \ Nur selber lernen macht schlau  
              <http://bergpost.annerschbarrich.de>
              
              1. Zurück aus dem Urlaub einen lieben Dank an alle Helfenden und eine Zusammenfassung der Lösung (für alle, die auf diesen Thread stoßen sollten):

                SELECT @myOrder:= `orderstring` FROM tabelle WHERE ID=1;  
                SET @s = CONCAT("SELECT * FROM tabelle ORDER BY ",@myOrder, " LIMIT 0,10");  
                PREPARE q FROM @s;  
                EXECUTE q;  
                
                

                Gruß aus Berlin,
                Jan

            2. Hi!

              Bitte zitiere nicht im TOFU-Stil, sondern wie hier üblich, nur das worauf du dich konkret beziehen möchtest, dann die Antwort darunter und weiter mit dem nächsten Zitat. Danke.

              Wäre es denn so richtig:

              PREPARE stmt_name FROM "SELECT * FROM testtabelle ORDER BY ?";

              SET @tparm = "town";
              EXECUTE stmt_name USING @tparm;

                
              Nein. Wie auf der verlinkten Seite beschrieben und wie bei P.S. üblich, können Platzhalter nur für Daten-Werte verwendet werden, nicht jedoch für syntaktische Bestandteile des SQL-Statements. Du musst demzufolge den Spaltennamen direkt in den Statement-String bringen, ihn also mit CONCAT() zusammenbauen.  
                
                
              Lo!
              
              1. Was ist denn der TOFU-Stil ? Inkl. Soja-Zitaten ? Ansonsten danke für die CONCAT-Hinweise :-)

                1. Hi,

                  Was ist denn der TOFU-Stil ?

                  http://de.wikipedia.org/wiki/TOFU

                  Und btw. auch noch als Lektüre empfehlenswert: http://de.wikipedia.org/wiki/Plenken

                  MfG ChrisB

                  --
                  The most exciting phrase to hear in science, the one that heralds new discoveries, is not “Eureka!” but “That's funny...” [Isaac Asimov]
  2. Hi!

    meine Frage: kann ich in den ORDER BY-Teil eine Mysql-Variable packen ?

    SELECT @myOrder := orderstring FROM tabelle WHERE id=1;

    SELECT * FROM tabelle ORDER BY @myOrder;

    
    > Ausgeführt wird es (ohne Fehler), nur das Ergebnis stimmt leider nicht...  
      
    Die Antwort auf die obige Frage lautet also: ja. Allein, es erfüllt nicht den von dir vorgesehenen Zweck. Ausgewertet wird der Variableninhalt, welcher einen String oder eine Zahl ergibt. Bei einem ORDER BY 'string' ist 'string' das Sortierkriterium und dieser String ist ein fester Wert, also bei allen Datensätzen gleich. Einen Feldnamen mit `` als solchen gekennzeichnet in die Variable zu packen bringt es auch nicht, weil dann der Wert '`feld`' immer noch ein String ist, und die beiden `` ein Bestandteil davon sind.  
      
    Außer Feldnamen kann man einem ORDER BY auch noch die Position in der Ergebnismenge als Integerwert übergeben.  
      
      SELECT a, b, c FROM foo ORDER BY 2  
      
    sortiert nach b. Aber abgesehen davon, dass du keine Zahlen in deiner `tabelle` stehen haben wirst und also den Wert erst in eine Spaltenposition umformen müsstest, mag MySQL (5.0) das auch nicht.  
      
      SET @test := 1;  
      SELECT \* FROM tabelle ORDER BY @test;  
      
    Auch hier wird wohl der Inhalt von test als Sortierkriterium, nicht aber als Positionsnummer angesehen.  
      
    Wenn sich das Konzept nicht insgesamt ändern lässt, sehe ich als mögliche Lösung nur ein [Prepared Statement](http://dev.mysql.com/doc/refman/5.1/en/prepare.html). Dem PREPARE-Statement kann man einen (zusammengesetzten) String übergeben, den es als Statement interpretiert, das dann ausgeführt werden kann. Diesen Vorgang kann man in einer Stored Procedure kapseln, denn es sind ja eine Handvoll Statements, die dabei insgesamt auszuführen sind. Außerdem ist das auch anfällig gegen SQL-Injection, weil ja ein variabler, eventuell nicht vertrauenswürdiger beziehungsweise kompromittierbarer Wert eingefügt. Da muss also eine Überprüfung auf erlaubte Werte stattfinden. Alternativ kann der ermittelte Spaltenname in `` eingeschlossen werden und im innern befindliche ` durch `` ausgetauscht werden (Notationsregeln siehe: [Schema Object Names](http://dev.mysql.com/doc/refman/5.1/en/identifiers.html)). Das ergibt dann bei einem Missbrauchsversuch entweder einen gültigen aber nicht vorgesehenen Feldnamen oder einen Syntaxfehler (Spalte nicht gefunden). Den Test auf erlaubte Werte kann man so auslegen, dass er im Zweifelsfall auf einen Default-Wert zurückfällt und damit ungefährlich und syntaktisch einwandfrei bleibt.  
      
      
    Lo!