Mots-clé : SQL

Les requêtes « à la » Django : howto / principes

Voici une requête « à la Django ».
« objects » est un objet statique destiné à faire les requêtes
p = un objet du modèle « Person » = un modèle base de données que j’ai fait
g = un objet du modèle « Game » = un modèle base de données que j’ai fait

J’ai crée un modèle intermédiaire « PersonGame » qui lie les deux tables en n/n. Pour comprendre l’idée :
Q(person=p) signifie « dont la personne == p »
~Q(person=p) signifie « dont la personne != p »

Si on met deux « __ » cela signifie « faire une jointure entre les deux modèles », par exemple « person__user » signifie « LEFT JOIN PERSON p ON p.id_user = user.id »

Donc pour tout reprendre :
« Aller chercher dans PersonGame toutes les personnes qui ne sont pas le joueur p »
PersonGame.objects.filter(~Q(person=p), game=g)

…et dont le username vaut « u »
.get(person__user__username=u)

Ce qui donne au final :
PersonGame.objects.filter(
    ~Q(person=p),
    game=g).get(person__user__username=u)

Et voici la requête qu’il aurait fallu écrire « à la main » :

SELECT * FROM PersonGame pg
WHERE pg.id_person != p.id
AND pg.id_game = g.id
LEFT JOIN Person pe on pe.id = p.id
LEFT JOIN User us on us.id = pe.id_user
WHERE us.username = u
LIMIT 1;

En fait ça peut paraître rébarbatif, ou surprenant, mais :
– ça tient en une ligne ;
– quand on a fait 3-4 requêtes comme ça :
  – on arrive à faire n’importe quelle requête un peu complexe très très vite ;
  – on arrive à lire très facilement n’importe quelle requête ;
  – le générateur de requêtes est incroyablement mieux optimisé que celui de Symfony (en fait, techniquement, il est parfait, il génère les LEFT JOIN exactement comme il faut et dans l’ordre le plus efficace en fonction des clés qu’on a précisées dans le modèle, voire il fait des requêtes plus efficaces que ce qu’on aurait éventuellement fait à la main (cela m’est arrivé par deux fois)).

Conclusion : ici aussi, en termes de maintenance = ce qui coûte le plus cher, c’est exceptionnellement rentable.

PostgreSQL

PostGreSQL hints / aide

Premiers pas

– Première connexion
– Création de base
N’oubliez pas les ";" à la fin des ordres SQL !
(Pris ici)
sudo su
# su - postgres
postgres $ psql
psql (9.x.x)
Type "help" for help.
postgres=#
postgres=# create database <db>;
CREATE DATABASE
postgres=# grant all privileges on database <db> to <user>;
GRANT
postgres=# ALTER ROLE <user> SUPERUSER;
postgres=#

Supprimer puis refaire une base de données

Se connecter en étant le user "postgres" pour être root et éviter les problèmes de droits.
(!) J’ai tout mis en une ligne comme cela il suffit de copier-coller.
sudo su
# su - postgres
# \c <db>
$ DROP SCHEMA public CASCADE; CREATE SCHEMA public; GRANT ALL ON SCHEMA public TO public; GRANT ALL ON SCHEMA public TO interro;
postgres=#

Faire un dump

Se connecter en étant le user "postgres" pour être root et éviter les problèmes de droits. sudo su
# su - postgres
postgres $ pg_dump interro > output.sql
postgres=#

Opérations de base

Show databases \l
Oui il n’a bien que ça à mettre : antislash « l » !
Switch databases \c <db>
Show tables \dt
Show users \du
Créer un utilisateur CREATE USER <user>;
Changer le mot de passe ALTER USER <user> PASSWORD 'mon-mot-de-passe';
Changer les permissions ALTER USER olivier WITH SUPERUSER;
ALTER USER olivier WITH CREATEDB;
ALTER USER olivier WITH CREATEROLE;
ALTER USER olivier WITH CREATEUSER;
ALTER USER olivier WITH REPLICATION;
ALTER USER olivier WITH BYPASSRLS;
Se connecter en tant que user psql -U olivier -d postgres -h localhost
Déplacer les fichiers data sudo -u postgres psql
# SHOW data_directory;

Puis continuer le tuto ici

Commentaires fermés sur PostgreSQL Publié dans Mots-clé ,

Symfony 2 et Doctrine et repository : faire un leftJoin avec createQueryBuilder

Comment utiliser createQueryBuilder() ?

La documentation n’est pas très claire sur le sujet. Enfin, disons que si vous êtes comme moi, il va vous manquer des exemples pour mieux comprendre. Je vais essayer de vous faire gagner du temps.

Voilà le problème : j’ai crée un repository pour mes partenaires, que j’ai appelé PartenaireRepository.php.

Dans la plupart des exemples, ils utilisent createQueryBuilder('p'), qui semble pratique (puisqu’il référence immédiatement la table et en fait un alias (dans mon exemple c’est p)

J’ai donc voulu utiliser createQueryBuilder() mais j’ai eu besoin deux jointures d’affilée : les partenaires avaient une ou plusieurs adresses, et ces adresses étaient réliées à des villes. La solution est en fait simple, à partir du moment où on a compris le principe :

    class PartenaireRepository extends EntityRepository
    {
        /**
         * Récupération de tous les partenaires donnés pour un
         * code postal donné.
         */
        public function findAllActiveByCp($cp)
        {
            return $this->createQueryBuilder('p')
                ->leftJoin('p.adresses', 'a')
                ->leftJoin('a.ville', 'v')
                ->where('v.cp=:cp')
                ->setParameter('cp', $cp);
        ... blabla
        }
    }

Ici, le leftJoin('p.adresses', 'a') signifie : dans la classe Partenaire que j’ai déclarée dans le fichier Entity\Partenaire.php, il y a la propriété adresses et tu vas faire une jointure dessus, et cette jointure, tu vas l’aliaser "a". On aura donc, à partir de cette jointure, une référence à une table adresse qu’on pourra utiliser via le "a".

Il est possible de refaire une jointure avec cet alias !

La preuve : la jointure juste après : ->leftJoin('a.ville', 'v') qui signifie, exactement sur le même principe : dans le fichier Entity\Adresse.php, il y a la propriété "ville" et tu vas faire une jointure dessus, et cette jointure, tu vas l’aliaser "v".

Enfin, je termine sur le "where" classique :

->where('v.cp=:cp').

D’après ce que j’ai compris, on ne peut faire des jointures que sur des propriétés qui sont elles même déclarées en tant que jointures. Donc, sur mon fichier « entité » Partenaire, ma jointure est déclarée ainsi :

/**
 * @ORM\ManyToMany(targetEntity="Adresse")
 * @ORM\JoinTable(name="partenaire_adresse",
 *      joinColumns={@ORM\JoinColumn(name="id_partenaire", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="id_adresse", referencedColumnName="id")}
 *      )
 */
private $adresses;

Et de la même façon, sur mon fichier « entité » Ville, ma jointure est déclarée ainsi :

/**
 * @var string
 *
 * @ORM\ManyToOne(targetEntity="Ville")
 * @ORM\JoinColumn(name="id_ville", referencedColumnName="id")
 */
private $ville;

J’espère vous avoir fait gagner du temps, parce que pour moi, la syntaxe n’était pas évidente à trouver.

MySQL : astuces pour quelques ordres de base

Voici quelques astuces dont je me sers souvent, pour ne pas avoir à systématiquement les rechercher, je m’en suis fait une copie dans un petit champ texte :

  1. Création d’une base de données
    CREATE DATABASE z DEFAULT CHARACTER SET utf8;
  2. Initialisation d’une variable via une requête :
    SELECT @MON_ID:= ID FROM matable WHERE CHAMP='champ_recherche';
    puis on se ressert de cette variable pour faire une insertion en base de données :
    INSERT INTO autre_table (ID_CLE_EXTERNE, DESCRIPTION, DOCUMENT) VALUES
    (@MON_ID, 'valeur1', './valeur2');
  3. Relancer le service MySQL
    1. service mysqld stop
    2. attendre une trentaine de secondes afin que le cache soit vidé et que toutes les allocations mémoires soient correctement libérées
    3. service mysqld start
  4. Convertir une table en utf8 :
    Très important : si vous tapez ce qui suit avec pour objectif de convertir la table et les données cela ne fonctionnera pas :
    ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;
    Ce n’est qu’en utilisant les ordres suivants que la conversion sera faite par MySQL !
    ALTER TABLE t1 CHANGE c1 c1 BLOB;
    ALTER TABLE t1 CHANGE c1 c1 TEXT CHARACTER SET utf8;
  5. Renommer un champ :
    Ici, je renomme la clé primaire « ID » et je la passe en minuscules (« id« ) :
    ALTER TABLE ville CHANGE ID id int(11) NOT NULL auto_increment;
  6. Modification des AUTO_INC
    Pour changer la valeur d’un auto_inc (‘réinitialiser la valeur’, comme on le dit dans MySQL ici) :
    ALTER TABLE tbl_name AUTO_INCREMENT = N
  7. Créer un utilisateur pour une base de données (la manière sale)
    Important : d’abord sans le ‘.*’ sinon ça ne fonctionne pas, et puis refaire avec le '.*'.
    Très important : ici on autorise tout à l’utilisateur qui va être crée. C’est donc une méthode rapide mais de bourrin et ce n’est pas la bonne méthode si vous voulez faire un utilisateur proprement, destiné à exister pour longtemps. Dans ce cas il faut faire quelque chose de plus précis afin de ne pas tout lui autoriser.
    GRANT ALL PRIVILEGES ON basededonnees
    TO ‘nomutilisateur’@’192.168.2.16’
    IDENTIFIED BY ‘motdepasse’;
    GRANT ALL PRIVILEGES ON basededonnees.*
    TO ‘nomutilisateur’@’192.168.2.16’
    IDENTIFIED BY ‘motdepasse’;

MySQL : mémo perso : Requête qui sélectionne tous les clients ayant choisi une formule surprimée

SELECT IP.ID AS IDPROPOSANT,
IP.NOM AS NOM,IP.PRENOM AS PRENOM,
IE.ID AS IDEMPRUNT,
IEFG.SURMORTALITE AS SURMORTALITE,
SP.DESCRIPTION AS PRODUIT,SF.DESCRIPTION AS FORMULE
FROM INTERNETPROPOSANT IP
JOIN INTERNETEMPRUNT IE
ON IE.IDINTERNETPROPOSANT=IP.ID
JOIN INTERNETEMPRUNTDECISIONMEDICALE IED
ON IE.ID=IED.IDINTERNETEMPRUNT
JOIN INTERNETEMPRUNTFORMULE IEF
ON IEF.IDINTERNETEMPRUNTDECISIONMEDICALE=IED.ID
JOIN INTERNETEMPRUNTFORMULEGARANTIE IEFG
ON IEFG.IDINTERNETEMPRUNTFORMULE=IEF.ID
JOIN SRCPRODUIT SP
ON SP.ID=IE.IDSRCPRODUITCHOISI
JOIN SRCFORMULE SF
ON SF.ID=IE.IDSRCFORMULECHOISIE
WHERE IEFG.SURMORTALITE>0
AND IE.NO_CONTRAT IS NOT NULL
AND IE.NO_CONTRAT<>""
AND IP.IDPARTENAIRE=578
AND IE.IDSRCFORMULECHOISIE=IEF.IDSRCFORMULE
GROUP BY IP.ID, IP.NOM, IP.PRENOM, IE.ID,
IEFG.SURMORTALITE, SP.DESCRIPTION, SF.DESCRIPTION;

MySQL : mémo perso : Nettoyage en pré-production

DELETE FROM INTERNETPROPOSANT WHERE IDPARTENAIRE<>578;
DELETE FROM INTERNETEMPRUNT WHERE IDINTERNETPROPOSANT
NOT IN (SELECT ID FROM INTERNETPROPOSANT);
DELETE FROM INTERNETEMPRUNTDECISIONMEDICALE WHERE
IDINTERNETEMPRUNT NOT IN (SELECT ID FROM INTERNETEMPRUNT);

UPDATE `INTERNETPROPOSANT`,`INTERNETEMPRUNT`
SET `INTERNETPROPOSANT`.`NOM`=
CONCAT_WS(",","NOM",
`INTERNETPROPOSANT`.`REFERENCEEXTERNE`,
`INTERNETEMPRUNT`.`NO_CONTRAT`),
`INTERNETPROPOSANT`.`PRENOM`=NULL,
`INTERNETPROPOSANT`.`NOTELEPHONE1`=NULL,
`INTERNETPROPOSANT`.`NOTELEPHONE2`=NULL,
`INTERNETPROPOSANT`.`NOTELEPHONE3`=NULL,
`INTERNETPROPOSANT`.`ADRESSE1`=NULL,
`INTERNETPROPOSANT`.`ADRESSE1`=NULL,
`INTERNETPROPOSANT`.`ADRESSE2`=NULL,
`INTERNETPROPOSANT`.`MOTDEPASSE`=NULL,
`INTERNETPROPOSANT`.`EMAIL`="monemailperso@gmail.com"
WHERE (`INTERNETPROPOSANT`.`ID` = `INTERNETEMPRUNT`.`IDINTERNETPROPOSANT`);