jointure complexe

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : jointure complexe

Re: jointure complexe

par Cyrano » 09 oct. 2011, 17:10

En déplaçant la clause de tri de la clause WHERE vers la clause JOIN, et si il s'agit d'une jointure externe (LEFT OUTER JOIN), il y aura davantage de ligne même s'il n'y a pas de correspondance dans la table jointe.

La clause WHERE va s'appliquer sur les lignes retournées par les conditions de la jointure.

Donc en conservant la clause de tri dans la clause WHERE, on limite les retours non désirés pour ce cas là. L'alternative consisterait à laisser cette clause de tri dans la jointure mais avec une jointure interne et non externe, donc INNER JOIN au lieu de LEFT OUTER JOIN et dans ce cas ne seront retournées que les lignes qui ont une correspondance dans la table jointe. Ça donnerait donc :
SELECT
  nd.title,
  fma.fid AS fida,
  fma.filename,
  fma.uri,
  fma.filemime,
  fma.filesize,
  fmb.fid AS fidb
FROM file_usage                fua
  LEFT JOIN file_usage         fub ON fua.id = fub.id
                                  AND fua.fid <> fub.fid
                                  AND fua.fid < fub.fid
  LEFT JOIN node                nd ON nd.nid = fua.id
  INNER JOIN file_managed fma ON fua.fid = fma.fid
                                  AND fma.filemime <> 'application/x-shockwave-flash'
  LEFT OUTER JOIN file_managed fmb ON fub.fid = fmb.fid
WHERE nd.type = 'contact'
ORDER BY nd.created DESC

Re: jointure complexe

par Spols » 09 oct. 2011, 16:50

J'ai malgré tout encore une question, j'ai tenté de déplacé une condition de la clause WHERE vers ma jointure et j'ai obtenu un résultat avec des lignes non désiré

requéte qui fonctionne
SELECT nd.title, fma.fid AS fida, fma.filename, fma.uri, fma.filemime, fma.filesize, fmb.fid AS fidb
FROM file_usage fua
LEFT JOIN file_usage fub ON fua.id = fub.id
AND fua.fid <> fub.fid
AND fua.fid < fub.fid
LEFT JOIN node nd ON nd.nid = fua.id
LEFT OUTER JOIN file_managed fma ON fua.fid = fma.fid
LEFT OUTER JOIN file_managed fmb ON fub.fid = fmb.fid
WHERE nd.type = 'contact'
AND fma.filemime <> 'application/x-shockwave-flash'
ORDER BY nd.created DESC
Requète qui fonctionne mal
SELECT nd.title, fma.fid AS fida, fma.filename, fma.uri, fma.filemime, fma.filesize, fmb.fid AS fidb
FROM file_usage fua
LEFT JOIN file_usage fub ON fua.id = fub.id
AND fua.fid <> fub.fid
AND fua.fid < fub.fid
LEFT JOIN node nd ON nd.nid = fua.id
LEFT OUTER JOIN file_managed fma ON fua.fid = fma.fid
AND fma.filemime <> 'application/x-shockwave-flash'
LEFT OUTER JOIN file_managed fmb ON fub.fid = fmb.fid
WHERE nd.type = 'contact'
ORDER BY nd.created DESC
pourquoi est-ce que la deuxième requète me renvoit également des lignes ou tout est NULL sauf le titre ?

Re: jointure complexe

par Spols » 09 oct. 2011, 16:00

Merci de ton aide, en effet ta nouvelle requète fonctionne beaucoup mieux. J'ai quelque peu modifier mes exigences depuis la création de ce post (un projet ca évolue tout le temps) et donc ma requète correspond au résultat que je cherche je vais donc l'utiliser en la gardant à l'oeil quand les tables seront plus complète.

Re: jointure complexe

par Cyrano » 09 oct. 2011, 15:19

Ok, effectivement, c'est ma requête qui était erronée.
En la modifiant, j'obtiens la première recherche, ça donne ceci :
SELECT
  nd.nid,
  fp.fid                              AS pdf_fid,
  DATE_FORMAT(
    FROM_UNIXTIME(fp.timestamp),
    '%d/%m/%y'
  )                                   AS pdf_title,
  fp.filename                         AS pdf_filename,
  fp.uri                              AS pdf_uri,
  fp.filemime                         AS pdf_filemime,
  fp.filesize                         AS pdf_filesize,
  fs.fid                              AS swf_fid,
  DATE_FORMAT(
    FROM_UNIXTIME(fs.timestamp),
    '%d/%m/%y'
  )                                   AS swf_title,
  fs.filename                         AS swf_filename,
  fs.uri                              AS swf_uri,
  fs.filemime                         AS swf_filemime,
  fs.filesize                         AS swf_filesize
FROM node                 nd
  INNER JOIN file_usage   up ON nd.nid = up.id
  INNER JOIN file_managed fp ON up.fid = fp.fid
                            AND fp.filemime = 'application/pdf'
  INNER JOIN file_usage   us ON nd.nid = us.id
  INNER JOIN file_managed fs ON us.fid = fs.fid
                            AND fs.filemime = 'application/x-shockwave-flash'
WHERE nd.type='contact'
ORDER BY nd.nid;
Ce qui m'affiche comme résultat :

Code : Tout sélectionner

+-----+---------+-----------+--------------------------+-------------------------------------------+-----------------+--------------+---------+-----------+--------------+---------------------------+-------------------------------+--------------+ | nid | pdf_fid | pdf_title | pdf_filename | pdf_uri | pdf_filemime | pdf_filesize | swf_fid | swf_title | swf_filename | swf_uri | swf_filemime | swf_filesize | +-----+---------+-----------+--------------------------+-------------------------------------------+-----------------+--------------+---------+-----------+--------------+---------------------------+-------------------------------+--------------+ | 6 | 4 | 05/10/11 | programme-ISQ-110627.pdf | public://contact/programme-ISQ-110627.pdf | application/pdf | 94967 | 5 | 08/10/11 | test.swf | public://contact/test.swf | application/x-shockwave-flash | 691653 | +-----+---------+-----------+--------------------------+-------------------------------------------+-----------------+--------------+---------+-----------+--------------+---------------------------+-------------------------------+--------------+
À copier/coller dans Notepad++ pour voir sans les retour de chariots intempestifs.

Et si tu remplaces les INNER JOIN par des LEFT OUTER JOIN, tu auras davantage de résultats mais moins pertinents à mon avis, mais je peux me tromper sur ce point à toi de voir.

Re: jointure complexe

par Spols » 09 oct. 2011, 14:54

Salut,

Je comprends tes modifications, mais je garderais malgré tout le type = contact dans la clause where car j'envisage de faire la même requète avec une autre clause, et ainsi la sortir de la jointure permet d'etre plus clair. Est-ce que cela change quelque chose niveau traitement ?

Je fait l'autojointure sur file_usage afin d'avoir une ligne par node du bon type et les fid des deux fichiers (swf et pdf). j'avais commencé par essayer de récupérer les doublonsmais cela ne me semblait pas être une bonne piste.

je te colle les create table et les lignes que j'ai actuellement ci-dessous

Code : Tout sélectionner

-- phpMyAdmin SQL Dump -- version 3.3.2deb1 -- http://www.phpmyadmin.net -- -- Serveur: localhost -- Généré le : Dim 09 Octobre 2011 à 14:26 -- Version du serveur: 5.1.41 -- Version de PHP: 5.3.2-1ubuntu4.9 SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; -- -- Base de données: `aiif` -- -- -------------------------------------------------------- -- -- Structure de la table `file_managed` -- CREATE TABLE IF NOT EXISTS `file_managed` ( `fid` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'File ID.', `uid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'The users.uid of the user who is associated with the file.', `filename` varchar(255) NOT NULL DEFAULT '' COMMENT 'Name of the file with no path components. This may differ from the basename of the URI if the file is renamed to avoid overwriting an existing file.', `uri` varchar(255) NOT NULL DEFAULT '' COMMENT 'The URI to access the file (either local or remote).', `filemime` varchar(255) NOT NULL DEFAULT '' COMMENT 'The file’s MIME type.', `filesize` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'The size of the file in bytes.', `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'A field indicating the status of the file. Two status are defined in core: temporary (0) and permanent (1). Temporary files older than DRUPAL_MAXIMUM_TEMP_FILE_AGE will be removed during a cron run.', `timestamp` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'UNIX timestamp for when the file was added.', PRIMARY KEY (`fid`), UNIQUE KEY `uri` (`uri`), KEY `uid` (`uid`), KEY `status` (`status`), KEY `timestamp` (`timestamp`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Stores information for uploaded files.' AUTO_INCREMENT=6 ; -- -- Contenu de la table `file_managed` -- INSERT INTO `file_managed` (`fid`, `uid`, `filename`, `uri`, `filemime`, `filesize`, `status`, `timestamp`) VALUES (1, 1, 'Immoweb_Info_3297871.pdf', 'public://contact/Immoweb_Info_3297871.pdf', 'application/pdf', 204029, 1, 1316119282), (3, 1, 'php_info_esco.pdf', 'public://contact/php_info_esco.pdf', 'application/pdf', 91967, 1, 1317840181), (4, 1, 'programme-ISQ-110627.pdf', 'public://contact/programme-ISQ-110627.pdf', 'application/pdf', 94967, 1, 1317843205), (5, 1, 'test.swf', 'public://contact/test.swf', 'application/x-shockwave-flash', 691653, 1, 1318084021); -- -------------------------------------------------------- -- -- Structure de la table `file_usage` -- CREATE TABLE IF NOT EXISTS `file_usage` ( `fid` int(10) unsigned NOT NULL COMMENT 'File ID.', `module` varchar(255) NOT NULL DEFAULT '' COMMENT 'The name of the module that is using the file.', `type` varchar(64) NOT NULL DEFAULT '' COMMENT 'The name of the object type in which the file is used.', `id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'The primary key of the object using the file.', `count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'The number of times this file is used by this object.', PRIMARY KEY (`fid`,`type`,`id`,`module`), KEY `type_id` (`type`,`id`), KEY `fid_count` (`fid`,`count`), KEY `fid_module` (`fid`,`module`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Track where a file is used.'; -- -- Contenu de la table `file_usage` -- INSERT INTO `file_usage` (`fid`, `module`, `type`, `id`, `count`) VALUES (1, 'file', 'node', 5, 1), (3, 'file', 'node', 7, 1), (4, 'file', 'node', 6, 1), (5, 'file', 'node', 6, 1); -- -------------------------------------------------------- -- -- Structure de la table `node` -- CREATE TABLE IF NOT EXISTS `node` ( `nid` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'The primary identifier for a node.', `vid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'The current node_revision.vid version identifier.', `type` varchar(32) NOT NULL DEFAULT '' COMMENT 'The node_type.type of this node.', `language` varchar(12) NOT NULL DEFAULT '' COMMENT 'The languages.language of this node.', `title` varchar(255) NOT NULL DEFAULT '' COMMENT 'The title of this node, always treated as non-markup plain text.', `uid` int(11) NOT NULL DEFAULT '0' COMMENT 'The users.uid that owns this node; initially, this is the user that created it.', `status` int(11) NOT NULL DEFAULT '1' COMMENT 'Boolean indicating whether the node is published (visible to non-administrators).', `created` int(11) NOT NULL DEFAULT '0' COMMENT 'The Unix timestamp when the node was created.', `changed` int(11) NOT NULL DEFAULT '0' COMMENT 'The Unix timestamp when the node was most recently saved.', `comment` int(11) NOT NULL DEFAULT '0' COMMENT 'Whether comments are allowed on this node: 0 = no, 1 = closed (read only), 2 = open (read/write).', `promote` int(11) NOT NULL DEFAULT '0' COMMENT 'Boolean indicating whether the node should be displayed on the front page.', `sticky` int(11) NOT NULL DEFAULT '0' COMMENT 'Boolean indicating whether the node should be displayed at the top of lists in which it appears.', `tnid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'The translation set id for this node, which equals the node id of the source post in each set.', `translate` int(11) NOT NULL DEFAULT '0' COMMENT 'A boolean indicating whether this translation page needs to be updated.', PRIMARY KEY (`nid`), UNIQUE KEY `vid` (`vid`), KEY `node_changed` (`changed`), KEY `node_created` (`created`), KEY `node_frontpage` (`promote`,`status`,`sticky`,`created`), KEY `node_status_type` (`status`,`type`,`nid`), KEY `node_title_type` (`title`,`type`(4)), KEY `node_type` (`type`(4)), KEY `uid` (`uid`), KEY `tnid` (`tnid`), KEY `translate` (`translate`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='The base table for nodes.' AUTO_INCREMENT=10 ; -- -- Contenu de la table `node` -- INSERT INTO `node` (`nid`, `vid`, `type`, `language`, `title`, `uid`, `status`, `created`, `changed`, `comment`, `promote`, `sticky`, `tnid`, `translate`) VALUES (1, 1, 'page', 'fr', 'Site web de l''AIIF - IMC', 1, 1, 1310159761, 1312743877, 1, 1, 0, 0, 0), (2, 2, 'page', 'fr', 'STATUTS DE L''A.I.I.F.-I.M.C. ASBL', 1, 1, 1313520108, 1317843954, 1, 0, 0, 0, 0), (3, 3, 'page', 'fr', 'COMPOSITION DU CONSEIL D''ADMINISTRATION DE L''ASSOCIATION', 1, 1, 1313520739, 1317843648, 1, 0, 0, 0, 0), (4, 4, 'page', 'fr', 'Contact', 1, 1, 1316118872, 1318152479, 1, 0, 0, 0, 0), (5, 5, 'contact', 'fr', '27/08/11', 1, 1, 1316119282, 1316119282, 1, 0, 0, 0, 0), (6, 6, 'contact', 'fr', '22/09/11', 1, 1, 1316119473, 1318084021, 1, 0, 0, 0, 0), (7, 7, 'contact', 'fr', '05/10/11', 1, 1, 1317840181, 1317840181, 1, 0, 0, 0, 0), (9, 9, 'page', 'fr', 'Contact', 1, 1, 1318090188, 1318106022, 1, 0, 0, 0, 0);

Re: jointure complexe

par Cyrano » 09 oct. 2011, 12:12

Je ne peux pas en penser grand chose, je n'ai aucune idée du résultat des requêtes, que ce soit celle que j'ai proposé comme celle que tu indiques. J'ai juste un peu de mal à saisir l'intérêt de l'auto-jointure sur la table file_usage. Il faudrait que je puisse tester, donc reconstruire les tables telles qu'elle sont dans l'application, il me faudrait les CREATE TABLE des trois tables et quelques lignes à insérer dans chaque table.

J'ajoute quand même que j'aurais modifié la requête comme ceci :
SELECT *
FROM file_usage                fua
  LEFT JOIN file_usage         fub ON fua.id = fub.id
                                  AND fua.fid <> fub.fid
                                  AND fua.fid < fub.fid
  LEFT JOIN node                nd ON nd.nid = fua.id
                                  AND nd.type = 'contact'
  LEFT OUTER JOIN file_managed fma ON fua.fid = fma.fid
                                  AND fma.filemime <> 'application/x-shockwave-flash'
  LEFT OUTER JOIN file_managed fmb ON fub.fid = fmb.fid;

Re: jointure complexe

par Spols » 09 oct. 2011, 11:59

Merci beaucoup pour ton aide, la requète que tu m'as passé ne fonctionnait pas toujours ni comme je le désirais.

Mais elle m'as permis de me replonger dans les jointures et j'ai donc pondu cette requète
SELECT *
FROM file_usage fua
LEFT JOIN file_usage fub ON fua.id = fub.id
AND fua.fid <> fub.fid
AND fua.fid < fub.fid
LEFT JOIN node nd ON nd.nid = fua.id
LEFT OUTER JOIN file_managed fma ON fua.fid = fma.fid
LEFT OUTER JOIN file_managed fmb ON fub.fid = fmb.fid
WHERE nd.type = 'contact'
AND fma.filemime <> 'application/x-shockwave-flash'
Elle me donne le résultat voulu, mais je ne suis pas certain qu'elle ne me donne pas de résultat incertain par la suite. Qu'en pensez vous ?
(Je dois encore limiter l'affichage des champs utiles, mais c'est secondaire)

La structure des tables ne peut être changé car je suis dans un CMS, mais sinon je les aurais conçu autrement vu l'utilisation que j'en ai.

Re: jointure complexe

par Cyrano » 09 oct. 2011, 09:51

Salut,
pas très évident et peut-être pas optimal parce que pour les types MIME, une table indépendante et une clé étrangère dans la table file_managed aurait été plus appropriée. Donc il faut passer par la valeur du type mime pour distinguer les types et ne ramener qu'une seule ligne.

Essaye comme ceci, sans garantie, j'ai pas reconstruit les tables pour tester :
SELECT
  nd.nid,
  fp.fid                              AS pdf_fid,
  DATE_FORMAT(fp.timestamp, 'd/m/y')  AS pdf_title,
  fp.filename                         AS pdf_filename,
  fp.uri                              AS pdf_uri,
  fp.filemime                         AS pdf_filemime,
  fp.filesize                         AS pdf_filesize,
  fs.fid                              AS swf_fid,
  DATE_FORMAT(fs.timestamp, 'd/m/y')  AS swf_title,
  fs.filename                         AS swf_filename,
  fs.uri                              AS swf_uri,
  fs.filemime                         AS swf_filemime,
  fs.filesize                         AS swf_filesize
FROM node                 nd
  INNER JOIN file_usage   fu ON nd.nid = fu.id
  INNER JOIN file_managed fp ON fu.fid = fp.fid
                            AND fp.filemime = 'application/pdf'
  INNER JOIN file_managed fs ON fu.fid = fs.fid
                            AND fs.filemime = 'application/x-shockwave-flash'
WHERE nd.type='contact'
ORDER BY nd.nid
Note que j'ai ajouté des alias sur les colonnes pour distinguer selon le type de fichier. Tu noteras également une jointure sur deux instances différentes de la table file_managed. Enfin, l'emploi de la fonction native dans MySQL de DATE_FORMAT pour récupérer le format de date lisible à partir d'un timestamp.

Attention à un détail : pour le cas où certains fichiers n'existeraient qu'au format pdf ou qu'au format swf pour un nid donné, il faudrait remplacer le INNER JOIN sur la table file_managed par un LEFT OUTER JOIN et dans ce cas, les information sur le type de fichier existant seront bien là, mais pour l'autre les valeurs retournées seront toutes NULL.

jointure complexe

par Spols » 08 oct. 2011, 20:43

Hello,

J'ai une question plutot thèorique, la requète que je cherche me simplifierais la tache, mais je peux trier en post traitement par php.

voici un apercu de mes tables

Code : Tout sélectionner

Table node : nid vid type created 1 1 page 1310159761 2 2 page 1313520108 3 3 page 1313520739 4 4 page 1316118872 5 5 contact 1316119282 6 6 contact 1316119473 7 7 contact 1317840181 8 8 page 1318078180 9 9 page 1318090188 Table file_managed : fid uid filename uri filemime filesize status timestamp 1 1 Immoweb_Info_3297871.pdf public://contact/Immoweb_Info_3297871.pdf application/pdf 204029 1 1316119282 3 1 php_info_esco.pdf public://contact/php_info_esco.pdf application/pdf 91967 1 1317840181 4 1 programme-ISQ-110627.pdf public://contact/programme-ISQ-110627.pdf application/pdf 94967 1 1317843205 5 1 test.swf public://contact/test.swf application/x-shockwave-flash 691653 1 1318084021 Table file_usage : fid module type id count 1 file node 5 1 3 file node 7 1 4 file node 6 1 5 file node 6 1
J'ai supprimé quelques champs inutile

le nid de la table node correspond au id de la table file_usage, le champs fid des 2 tables file_* correspondent entre eux

J'utilise actuellement la requète

Code : Tout sélectionner

SELECT `M`.`fid`, `N`.`title`, `M`.`filename`, `M`.`uri`, `M`.`filemime`, `M`.`filesize` FROM node N, file_usage U, file_managed M WHERE N.nid = U.id AND U.fid = M.fid ORDER BY `N`.`created` DESC
et j'obtient

Code : Tout sélectionner

fid title filename uri filemime filesize 3 05/10/11 php_info_esco.pdf public://contact/php_info_esco.pdf application/pdf 91967 4 22/09/11 programme-ISQ-110627.pdf public://contact/programme-ISQ-110627.pdf application/pdf 94967 5 22/09/11 test.swf public://contact/test.swf application/x-shockwave-flash 691653 1 27/08/11 Immoweb_Info_3297871.pdf public://contact/Immoweb_Info_3297871.pdf application/pdf 204029
Quelle requète devrait-je utiliser pour obtenir

Code : Tout sélectionner

nid fid title filename uri filemime filesize fid title filename uri filemime filesize 6 4 22/09/11 programme-ISQ-110627.pdf public://contact/programme-ISQ-110627.pdf application/pdf 94967 5 22/09/11 test.swf public://contact/test.swf application/x-shockwave-flash 691653
Je voudrais donc que pour tout nid correspondant à un type = contact, je puisse récupéré les 2 fichiers (un pdf et un swf) dans la même requète.