Кохана: как заключить запрос в скобки? - PullRequest
1 голос
/ 19 октября 2011

Мне нужно создать запрос (я использую PostgreSQL):

(SELECT * FROM t1 WHERE a>b ORDER BY a DESC)  
UNION ALL  
(SELECT * FROM t1 WHERE a<b ORDER BY a DESC)  

Итак, я пытаюсь использовать построитель запросов

$query1 = DB::select('*')  
->from('t1')->where('a', '>', 'b')->order_by('a', 'desc');    

$query2 = DB::select('*')  
->from('t1')->where('a', '<', 'b')->order_by('a', 'desc');    

$result = $query1->union($query2, TRUE);  

Но в результате у меня есть SQL-запрос, где выбирает без скобок. Как это:

SELECT * FROM t1 WHERE a>b ORDER BY a DESC  
UNION ALL  
SELECT * FROM t1 WHERE a<b ORDER BY a DESC  

И получить синтаксическую ошибку SQL ... Извините за мой английский

Ответы [ 2 ]

1 голос
/ 20 октября 2011

Еще один способ решить эту проблему - изменить class Database_Query_Builder_Select. Таким образом, создайте запрос союзов в квадратных скобках: (select_1) union (select_2) union (select_n). И вы можете использовать ORDER BY и LIMIT в каждом SELECT выражении

1) Создать папку application / classes / database / query / builder /
2) Создать файл select.php
3) Вставьте в созданный файл этот код:

<?php defined('SYSPATH') or die('No direct script access.');

class Database_Query_Builder_Select extends Kohana_Database_Query_Builder_Select {

protected $_union_limit = NULL;

/**
 * Insert LIMIT statement after all unions
 * 
 * @param integer $number
 */
public function union_limit($number)
{
    $this->_union_limit = (int) $number;

    return $this;
}

/**
 * Compile the SQL query and return it.
 *
 * @param   object  Database instance
 * @return  string
 */
public function compile(Database $db)
{
    // Callback to quote columns
    $quote_column = array($db, 'quote_column');

    // Callback to quote tables
    $quote_table = array($db, 'quote_table');

    // Start a selection query
    $query = 'SELECT ';
    if ( ! empty($this->_union)) $query = DB::expr('(SELECT ');

    if ($this->_distinct === TRUE)
    {
        // Select only unique results
        $query .= 'DISTINCT ';
    }

    if (empty($this->_select))
    {
        // Select all columns
        $query .= '*';
    }
    else
    {
        // Select all columns
        $query .= implode(', ', array_unique(array_map($quote_column, $this->_select)));
    }

    if ( ! empty($this->_from))
    {
        // Set tables to select from
        $query .= ' FROM '.implode(', ', array_unique(array_map($quote_table, $this->_from)));
    }

    if ( ! empty($this->_join))
    {
        // Add tables to join
        $query .= ' '.$this->_compile_join($db, $this->_join);
    }

    if ( ! empty($this->_where))
    {
        // Add selection conditions
        $query .= ' WHERE '.$this->_compile_conditions($db, $this->_where);
    }

    if ( ! empty($this->_group_by))
    {
        // Add sorting
        $query .= ' GROUP BY '.implode(', ', array_map($quote_column, $this->_group_by));
    }

    if ( ! empty($this->_having))
    {
        // Add filtering conditions
        $query .= ' HAVING '.$this->_compile_conditions($db, $this->_having);
    }

    if ( ! empty($this->_order_by))
    {
        // Add sorting
        $query .= ' '.$this->_compile_order_by($db, $this->_order_by);
    }

    if ($this->_limit !== NULL)
    {
        // Add limiting
        $query .= ' LIMIT '.$this->_limit;
    }

    if ($this->_offset !== NULL)
    {
        // Add offsets
        $query .= ' OFFSET '.$this->_offset;
    }

    if ( ! empty($this->_union))
    {
        $iteration = 1;
        foreach ($this->_union as $u) {
            if ($iteration == 1) $query .= ')';
            $query .= ' UNION ';
            if ($u['all'] === TRUE)
            {
                $query .= 'ALL ';
            }
            $query .= '('.$u['select']->compile($db).')';

            $iteration++;
        }
    }

    if ( ! empty($this->_union_limit))
    {
        $query .= ' LIMIT '.$this->_union_limit;
    }
    $this->_sql = $query;

    return $query;
}

}

1 голос
/ 19 октября 2011

Почему бы не SELECT * FROM t1 WHERE a != b ORDER BY a DESC?

EDIT
Для более сложного запроса, когда вам действительно нужно два или более ORDER BY, я вижу только это решение:

$query1 = DB::select()
        ->from('t1')
        ->where('a', '>', 'b')
        ->order_by('a', 'DESC')
        ->__toString();


$query2 = DB::select()
        ->from('t1')
        ->where('a', '<', 'b')
        ->order_by('a', 'DESC')
        ->__toString();

$query3 = '(' . $query1 . ') UNION ALL (' . $query2 . ')';
$result = DB::query(Database::SELECT, $query3)->execute();
...