Quick links: Content - sections - sub sections
EN FR
Quick Search Advanced search
 
Page

  [Opened] Mssql & Limit

Posted by LouisS on 08/09/2010 11:20

Bonjour, travaillant sur un projet utilisant comme BDD MSSQL j'ai dus implémenter une fonction _doLimitQuery afin de pouvoir paginer les résultats d'une requête.

Je pose donc ici le code afin d'en faire profiter les personnes étant sur MSSQL mais aussi pour avoir des propositions d'améliorations.

Cette méthode marchent pour la plupart des cas mais pas la totalité (un "SELECT * " ne passe pas, le FROM doit être en maj...) , et me parait tout de même un peu 'bidouille' (surtout la partie pour récupérer le premier champ qui servira de clef pour les ORDER BY). Je demande donc un peu d'aide afin de rendre ceci plus élégant.

Merci d'avance :)

<code>
    /**
     * (non-PHPdoc)
     * @see lib/jelix/db/jDbConnection#_doLimitQuery()
     */
    protected function _doLimitQuery ($queryString, $offset, $number) {

        if(!mssql_select_db ($this->profile['database'], $this->_connection)) {
            if(mssql_get_last_message()) {
                throw new jException('jelix~db.error.database.unknow',$this->profile['database']);
            } else {
                throw new jException('jelix~db.error.connection.closed',$this->profile['name']);
            }
        }

        // on supprime le plausible premier 'TOP XX' 
        $queryString = preg_replace('/^SELECT TOP[ ]\d*\s*/i', 'SELECT ', $queryString);

        $distinct = false;

        // On récupère la partie de la requete entre les SELECT et le FROM
        $tmp = explode('FROM', $queryString);
        preg_match_all('/' . preg_quote('SELECT', '/') . '([^\)]+)'. preg_quote('FROM', '/').'/i', $tmp[0]." FROM", $matches['fields']);        

        // On coupe les champs par la virgule
        $res = explode(',', $matches['fields'][1][0]);

        // Si il y a une alias de champs
        if (stristr($res[0], ' as ') != false) {
            $res = explode(' as ', $res[0]);
            $key = $res[1]; // on récupère cette alias
        } else { // sinon on récupère le champs
            if (stristr($res[0], 'DISTINCT') != false) {
                $res[0] = $key = preg_replace('/DISTINCT/i', '', $res[0]);
                $distinct = true; // variable permettant de savoir si un distinct est présent dans la requete de base
            }
            if (stristr($res[0], '.')) { // après le '.' pour court circuiter l'explicitation de la table
                $res = explode('.', $res[0]);
                $key = $res[1];
            } else {
                $key = $res[0];
            }
        }
        //jLog::log($key);

        $orderby = stristr($queryString, 'ORDER BY');
        // Si il y a un ORDER BY dans la requete
        if ($orderby !== false) {
            // on récupère '[champ] ASC' ou '[champ] DESC'
            $order = str_ireplace('ORDER BY', '', $orderby);
        } else {
            $order = $key.' ASC';
            $queryString .= ' ORDER BY '.$order;
        }

        // Si la requete de base ne comportait pas de DISTINCT
        if(!$distinct)
            $queryString = preg_replace('/^SELECT\s/i', 'SELECT TOP ' . ($number+$offset) . ' ', $queryString);
        else
            $queryString = preg_replace('/^SELECT DISTINCT\s/i', 'SELECT DISTINCT TOP ' . ($number+$offset) . ' ', $queryString);

        $queryString = 'SELECT TOP '.$number.' * FROM (SELECT TOP ' . $number . ' * FROM (' . $queryString . ') AS inner_tbl';
        $queryString .= ' ORDER BY ';

        $outer_order = preg_replace(array('/\bASC\b/i', '/\bDESC\b/i'), array('_DESC', '_ASC'), $order);
        $outer_order = str_replace(array('_DESC', '_ASC'), array('DESC', 'ASC'), $outer_order);

        $queryString .= $outer_order . ' ) AS outer_tbl ORDER BY ' . $order;

        // Requete de sortie
        //jLog::log($queryString);

        if(!mssql_select_db ($this->profile['database'], $this->_connection))
            throw new jException('jelix~db.error.database.unknow',$this->profile['database']);

        if ($qI = mssql_query($queryString, $this->_connection)) {
            return new mssqlDbResultSet ($qI);
        } else {
            throw new jException('jelix~db.error.query.bad',  mssql_get_last_message());
        }
    }
</code>

  [Opened] Mssql & Limit

Reply #1 Posted by laurentj on 08/23/2010 10:52

Merci pour l'info.

Cependant:

  1. tu t'es trompé de forum ;)
  2. c'est mieux de proposer ça directement sur developer.jelix.org

  [Opened] Mssql & Limit

Reply #2 Posted by laurentj on 08/23/2010 11:00

j'ai crée le ticket : http://developer.jelix.org/ticket/1160

 
Page
  1. Mssql & Limit