ужасный SQL запрос с множеством таблиц

Тема в разделе "Базы данных", создана пользователем phillip, 14 апр 2011.

Модераторы: latteo
  1. phillip

    phillip

    Регистр.:
    4 сен 2007
    Сообщения:
    413
    Симпатии:
    15
    делаю выборку из нескольких таблиц, допустим
    PHP:
    SELECT FROM `table1`, `table2`, `table3`  WHERE `id`=and `t`=4
    ругается что надо писать `table1`.`id` обязательно. указывать таблицу то есть.
    но фишка в том что у меня id и t есть в каждой таблице, тогда мне надо писать нечто ужасное типа

    PHP:
    SELECT FROM `table1`, `table2`, `table3`  WHERE ( `table1`.`id`=or `table2`.`id`=or `table3`.`id`=2) and ( `table1`.`t`=or `table2`.`t`=or `table3`.`t`=4)
    и таблицы у меня не 2, а 10 на самом деле. короче получается что-то ужасное! как записать красиво?
     
  2. CrashX

    CrashX В прошлом XSiteCMS

    Регистр.:
    6 июн 2008
    Сообщения:
    682
    Симпатии:
    112
    это правильно и ничего ужасного тут нет
    у меня запросы обычно вида
    я их даже не пишу они сами генерируются)))
     
    phillip нравится это.
  3. saen

    saen

    Регистр.:
    6 авг 2006
    Сообщения:
    756
    Симпатии:
    129
    выборка из нескольких таблиц делается через JOIN путем соотношения полей между таблицами
    Код:
    SELECT `table1`.*, `table2`.*, `table2`.`id` as `id2`, `table2`.`t` as `t2`, `table3`.*, `table3`.`id` as `id3`, `table3`.`t` as `t3` FROM `table1`
    LEFT JOIN `table2` ON `table1`.`id` = `table2`.`id`
    LEFT JOIN `table3` ON `table1`.`id` = `table3`.`id`
    WHERE `table1`.`id` = 2 OR `table2`.`id` = 2 OR `table3`.`id` = 2
    OR `table1`.`t` = 4 OR `table4`.`t` = 4 OR `table3`.`t` = 4  
    
    Если не хочешь, чтобы остальные поля с одинаковыми названиями не дублировались, пишешь для них алиас. Если хочешь, чтобы запрос был красивым, пиши хранимую процедуру и обращайся к ней.
     
  4. phillip

    phillip

    Регистр.:
    4 сен 2007
    Сообщения:
    413
    Симпатии:
    15
    ммм а как это они у тебя сами генерируются? фреймворк чтоли используешь, или что =)
     
  5. CrashX

    CrashX В прошлом XSiteCMS

    Регистр.:
    6 июн 2008
    Сообщения:
    682
    Симпатии:
    112
    у меня свой двиг, запросы генерируются из файлов описания свое рода схем.
    конструктор он простой, много чего нет, например не придумал как сравнивать <, >, beetween и тп
    ну это пока нужды не было
    PHP:
    <?php

    /**
     * $Revision: 502 $
     * $Author: CrashX $
     * $Date: 2010-02-02 14:27:01 +0600 (Вт, 02 фев 2010)$
     * $LastChangedDate: 2011-04-14 20:54:17 +0700 (Чт, 14 апр 2011) $
     * $Id: mysql.query.php 502 2011-04-14 13:54:17Z CrashX $
     * Copyright © CrashX <XSiteCMS@gmail.com>
     * Всі права захищено © CrashX
     */
    if (!defined('_SHELL'))
      die();

    /**
     * Построение запросов
     */
    class QueryDB {

      
    /**
       * Создание текста запроса для выборки записи
       * @param поля в виде ассоциативного массива
       * @param таблица имя
       * @param критерии в виде ассоциативного массива
       * @param доплительные части запроса или директивы
       * @return mixed
       */
      
    function select($fields=array(), $table=null$criteria=null) {
        
    $this->type 'select';
    // SELECT *ПОЛЯ* FROM *ТАБЛИЦА* WHERE *УСЛОВИЯ* *ДИРЕКТИВЫ*
        
    $wheres null;
        
    $order null;
        
    $sort null;
        
    $limit null;
        
    $join null;
        
    $fields $this->fields($fields$table);
        if (
    is_array($criteria)):
          foreach (
    $criteria as $type => $data):
            switch (
    $type):
              case 
    "join":
                
    $join = array();
                foreach (
    $data as $value):
                  
    $fields .=", " $this->fields($value['fields'], $value['table']);
                  
    $join[] = $value['type'] . ' ' $value['table'] . ' ON ' $table '.' $value['link']['a'] . ' = ' $value['table'] . '.' $value['link']['b'];
                endforeach;
                
    $join implode(" "$join);
                break;
              case 
    "order"$order ' ORDER BY ' $data;
                break;
              case 
    "sort"$sort ' ' $data;
                break;
              case 
    "limit"$limit ' LIMIT ' intval($data[0], 0) . ', ' intval($data[1], 1);
                break;
              case 
    "where":
                
    $wheres = array();
                foreach (
    $data as $column => $value):
                  
    $wheres[] = "{$column}='{$value}'";
                endforeach;
                
    $wheres implode(" AND "$wheres);
                break;
              default: break;
            endswitch;
          endforeach;
        endif;
        
    // Собираем запрос
        
    $this->query "SELECT {$fields} ";
        if (!empty(
    $table)):
          
    $this->query.=" FROM {$table}";
        endif;
        if (!empty(
    $join)):
          
    $this->query.={$join}";
        endif;
        if (!empty(
    $wheres)):
          
    $this->query.=" WHERE {$wheres}";
        endif;
        if (!empty(
    $order)):
          
    $this->query.=$order;
        endif;
        if (!empty(
    $sort)):
          
    $this->query.=$sort;
        endif;
        if (!empty(
    $limit)):
          
    $this->query.=$limit;
        endif;
        
    $this->query.=";";
        return 
    true;
      }

      
    /**
       * Создание текста запроса для добавления записи
       * @param поля в виде ассоциативного массива
       * @param таблица имя
       */
      
    function insert($fields=array(), $table=null) {
    // INSERT INTO *ТАБЛИЦА* *ПОЛЯ* VALUES *ЗНАЧЕНИЯ*
        
    $this->type 'insert';
        
    $values = array();
        foreach (
    $fields as $field):
          
    $values[] = "'{$field}'";
        endforeach;
        
    $columns array_keys($fields);
        
    $this->query "INSERT INTO {$table} (" implode(", "$columns) . ")";
        
    $this->query.=" VALUES (" implode(", "$values) . ")";
        
    $this->query.=";";
        return 
    true;
      }

      
    /**
       * Создание текста запроса для обновления записи
       * @param поля в виде ассоциативного массива
       * @param таблица имя
       * @param критерии в виде ассоциативного массива
       * @return mixed
       */
      
    function update($fields$table$criteria) {
    // UPDATE *ТАБЛИЦА* SET *ПОЛЯ* WHERE *УСЛОВИЯ*
        
    $this->type 'update';
        
    $wheres = array();
        
    $updates = array();
        foreach (
    $fields as $column => $value):
          
    $updates[] = "{$column}='{$value}'";
        endforeach;
        
    $update implode(", "$updates);
        foreach (
    $criteria as $column => $value):
          
    $wheres[] = "{$column}='{$value}'";
        endforeach;
        
    $where implode(" AND "$wheres);
        
    $this->query "UPDATE {$table}";
        
    $this->query.=" SET {$update}";
        
    $this->query.=" WHERE {$where}";
        
    $this->query.=";";
        return 
    true;
      }

      
    /**
       * Создание текста запроса для удаления записи
       * @param таблица имя
       * @param критерии в виде ассоциативного массива
       * @return mixed
       */
      
    function delete($table$criteria) {
    // DELETE *?!ПОЛЯ!?* FROM *ТАБЛИЦА* WHERE *УСЛОВИЯ*
        
    $this->type 'delete';
        
    $wheres = array();
        foreach (
    $criteria as $column => $value):
          
    $wheres[] = "{$column}='{$value}'";
        endforeach;
        
    $where implode(" AND "$wheres);
        
    $this->query.="DELETE FROM {$table}";
        
    $this->query.=" WHERE {$where}";
        
    $this->query.=";";
        return 
    true;
      }

      
    /**
       * Создание текста запроса для выборки записи
       * @param поля в виде ассоциативного массива
       * @param таблица имя
       * @param критерии в виде ассоциативного массива
       * @param доплительные части запроса или директивы
       * @return mixed
       */
      
    function count($table=null$criteria=null) {
        
    $this->type 'select';
    // SELECT *ПОЛЯ* FROM *ТАБЛИЦА* WHERE *УСЛОВИЯ* *ДИРЕКТИВЫ*
        
    $wheres null;
        
    $fields null;
        if (
    is_array($criteria)):
          
    $fields 'COUNT(' $criteria['count']['field'] . ') AS `count`';
          
    $wheres = array();
          foreach (
    $criteria['count']['where'] as $column => $value):
            
    $wheres[] = "{$column}='{$value}'";
          endforeach;
          
    $wheres implode(" AND "$wheres);
        endif;
        
    // Собираем запрос
        
    $this->query "SELECT {$fields} ";
        if (!empty(
    $table)):
          
    $this->query.=" FROM {$table}";
        endif;
        if (!empty(
    $wheres)):
          
    $this->query.=" WHERE {$wheres}";
        endif;
        
    $this->query.=";";
        return 
    true;
      }

      function 
    procedure($fields$procedure$result='@result') {
    //CALL *ИМЯ ПРОЦЕДУРЫ* (*ЗНАЧЕНИЯ*,*РЕЗУЛЬТАТ*)
        
    $values = array();
        foreach (
    $fields as $field):
          
    $values[] = "'{$field}'";
        endforeach;
        
    $columns array_keys($fields);
        if (
    $result && !empty($result))
          
    $result ',' $result;
        
    $this->query "CALL " $procedure "(" implode(", "$values) . $result ");";
      }

    }

    ?>
    пример описания полей
    PHP:
    $metadata = array(
    // TABLE
        
    'table' => 'news',
    // FIELD
        
    'field' => array(
            
    'id' => null,
            
    'cid' => null,
            
    'aid' => null,
            
    'seo' => null,
            
    'title' => null,
            
    'content' => null,
            
    'reference' => null,
            
    'hits' => null,
            
    'public' => null,
            
    'created' => null,
        ),
        
    'directive' => array(
            
    'count' => array(
                
    'field' => 'news.id',
                
    'where' => array('news.show' => 1),
            ),
            
    'join' => array(
                array(
                    
    'fields' => array(
                        
    'ulogin' => '',
                        
    'unick' => '',
                        
    'uname' => '',
                        
    'usurname' => '',),
                    
    'type' => 'LEFT OUTER JOIN',
                    
    'table' => 'users',
                    
    'link' => array(
                        
    'a' => 'aid',
                        
    'b' => 'id')
                ),
                array(
                    
    'fields' => array(
                        
    'alias' => '',
                        
    'name' => '',
                        
    'pid' => '',),
                    
    'type' => 'LEFT OUTER JOIN',
                    
    'table' => 'news_category',
                    
    'link' => array(
                        
    'a' => 'cid',
                        
    'b' => 'id')
                ),
            ),
            
    'where' => array('news.show' => '1'),
            
    'order' => 'news.public',
            
    'sort' => 'DESC',
            
    'limit' => array(010),
        ),
    Генерация
    PHP:
       $engine->db->select($this->metadata['field'], $this->metadata['table'], $this->metadata['directive']);
    так писать не стоит для удобства пишите текстом, что бы было вам и другим понятнее.

    а это пример того как можно, но возможно ненужно) просто у меня цель немного другая динамические формы поля и тп те контруктор конструктора.
     
    UnL!M!TeD и phillip нравится это.
  6. phillip

    phillip

    Регистр.:
    4 сен 2007
    Сообщения:
    413
    Симпатии:
    15
    ок, спасибо! я вот чего понять не могу... условно говоря, мне надо сделать чтобы в одной из таблиц и id и t был нужный, и тогда мы берем строку из этой таблицы целиком. Нельзя чтобы случайно сделалась такая выборка что id возмет из первой таблицы, а t из второй

    ААааа не знаю как выразиться понятнее :-]
     
  7. chang

    chang

    Регистр.:
    20 ноя 2009
    Сообщения:
    364
    Симпатии:
    117
    phillip
    он же saen написал как это делается ... просто конкретизирую "переменную" названием таблицы
    `table2`.`id` as `id2`, `table2`.`t` as `t2`,

    ну и выбирай не через "звездочку" а конкретные данные ... или с присвоением псевдонима

    типа
    PHP:

    SELECT  t1
    .id  as id_t1,  t2.id as id_t2
    FROM  table1  
    as t1
    LEFT JOIN   table2 
    as t2  ON  t1.id t2.to_id

    таким макаром данные никогда не будут пересекаться или взаимозаменяются
     
    phillip нравится это.
  8. phillip

    phillip

    Регистр.:
    4 сен 2007
    Сообщения:
    413
    Симпатии:
    15
    Блин все равно туплю, не понимаю я с этими джойнами. Помогите плиз разобраться раз и навсегда, чето я все медлил с этим, надоело!

    Допустим так... Есть таблица users в ней
    1 Маша
    2 Петя
    3 Света
    _______

    есть таблицы potato (картошка) tomato (помидоры) bananos (бананы)

    При этом, у картошки, томатов, бананов разные характеристики совершенно: допустим у картошки это цена и сорт. У помидоры- размер и цвет, у банана сколько часов пролежал на складе. НО одно поле у всех совпадает, это поле ownerid (владелец данной картошки или помидорки или банана) и поле exist (наличие на складе).

    Зная что у Маши айди=1, как собрать воедино все все фрукты и овощи из всех таблиц, у которых ownerid=1 и exist=Y?

    Я счас делаю тупо три разных запроса. Сперва ковыряю таблицу помидор, и достаю все ownerid=1 c exist=Y, затем то же проделываю с бананами и картошкой

    Попробовал составить как вы научили, возвращает пустой массив
    нид хелп! надоело тупить :tut:
     
  9. CrashX

    CrashX В прошлом XSiteCMS

    Регистр.:
    6 июн 2008
    Сообщения:
    682
    Симпатии:
    112
    phillip нравится это.