sql >> データベース >  >> RDS >> Mysql

Wordpressの結合クエリ

    これは回答の更新バージョンであり、以前のものよりも柔軟性があります。

    SQL UNIONを使用する1つのアイデアを次に示します。 :

    • posts_clausesのデータを使用できます posts_requestからSQLクエリを書き換えるためのフィルタ フィルター。

    • WP_Queryを拡張します 私たちの目標を達成するためのクラス。実際には2回行います:

      • WP_Query_Empty :データベースクエリを実行せずに、各サブクエリの生成されたSQLクエリを取得します。
      • WP_Query_Combine :投稿を取得します。
    • 次の実装は、Nの組み合わせをサポートしています サブクエリ。

    2つのデモがあります:

    デモ#1:

    日付順に並べられた6つの投稿があると仮定します(DESC):

    CCC
    AAA
    BBB
    CCC
    YYY
    ZZZ
    XXX 
    

    ここで、XXXYYY およびZZZ DT=2013-12-14 13:03:40よりも古い 。

    DTの後に投稿が公開されるように投稿を並べ替えましょう タイトル(ASC)で並べ替えられ、DTの前にpublisehdを投稿します タイトル順(DESC):

    AAA
    BBB
    CCC
    ZZZ
    YYY
    XXX 
    

    次に、以下を使用できます:

    /**
     * Demo #1 - Combine two sub queries:
     */
    
    $args1 = array(
        'post_type'  => 'post',
        'orderby'    => 'title',
        'order'      => 'ASC',
        'date_query' => array(
            array( 'after' => '2013-12-14 13:03:40' ),
        ),
    );
    
    $args2 = array(
        'post_type'  => 'post',
        'orderby'    => 'title',
        'order'      => 'DESC',
        'date_query' => array(
            array( 'before' => '2013-12-14 13:03:40', 'inclusive' => TRUE ),    
        ),
    );
    
    $args = array( 
       'posts_per_page' => 1,
       'paged'          => 1,
       'sublimit'       => 1000,
       'args'           => array( $args1, $args2 ),
    );
    
    $results = new WP_Combine_Queries( $args );
    

    これにより、次のSQLクエリが生成されます。

    SELECT SQL_CALC_FOUND_ROWS * FROM ( 
        ( SELECT wp_posts.* 
            FROM wp_posts 
            WHERE 1=1 
                AND ( ( post_date > '2013-12-14 13:03:40' ) ) 
                AND wp_posts.post_type = 'post' 
                AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') 
                ORDER BY wp_posts.post_title ASC 
                LIMIT 1000
        ) 
        UNION 
        ( SELECT wp_posts.* 
            FROM wp_posts 
            WHERE 1=1 
            AND ( ( post_date <= '2013-12-14 13:03:40' ) ) 
            AND wp_posts.post_type = 'post' 
            AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') 
            ORDER BY wp_posts.post_title DESC 
            LIMIT 1000
        ) 
    ) as combined LIMIT 0, 10 
    

    デモ#2:

    これがあなたの例です:

    /**
     * Demo #2 - Combine two sub queries:
     */
    
    $today = date( 'm/d/Y', strtotime( 'today' ) );
    
    $args1 = array(
        'post_type'      => 'workshops',
        'meta_key'       => 'select_dates_0_workshop_date',
        'orderby'        => 'meta_value',
        'order'          => 'ASC',
        'meta_query'     => array(
            array(
                'key'         => 'select_dates_0_workshop_date',
                'value'       => $today,
                'compare'     => '>=',
                'type'        => 'CHAR',
            ),
        )
    );
    
    $args2 = array(
        'post_type'      => 'workshops',
        'meta_key'       => 'select_dates_0_workshop_date',
        'orderby'        => 'meta_value',
        'order'          => 'DESC',
        'meta_query'     => array(
            array(
                'key'         => 'select_dates_0_workshop_date',
                'value'       => $today,
                'compare'     => '<',
                'type'        => 'CHAR',
            ),
        )
    );
    
    $args = array( 
       'posts_per_page' => 5,
       'paged'          => 4,
       'sublimit'       => 1000,
       'args'           => array( $args1, $args2 ),
    );
    
    $results = new WP_Combine_Queries( $args );
    

    これにより、次のようなクエリが表示されます。

    SELECT SQL_CALC_FOUND_ROWS * FROM ( 
        ( SELECT wp_posts.* 
            FROM wp_posts 
            INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id) 
            INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id) 
            WHERE 1=1 
                AND wp_posts.post_type = 'workshops' 
                AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 1 AND wp_posts.post_status = 'private') 
                AND (wp_postmeta.meta_key = 'select_dates_0_workshop_date' AND (mt1.meta_key = 'select_dates_0_workshop_date' AND CAST(mt1.meta_value AS CHAR) >= '05/16/2014') ) 
                GROUP BY wp_posts.ID 
                ORDER BY wp_postmeta.meta_value ASC
                LIMIT 1000 
            ) 
        UNION 
        ( SELECT wp_posts.* 
            FROM wp_posts 
            INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id) 
            INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id) 
            WHERE 1=1 
                AND wp_posts.post_type = 'workshops' 
                AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 1 AND wp_posts.post_status = 'private') 
                AND (wp_postmeta.meta_key = 'select_dates_0_workshop_date' AND (mt1.meta_key = 'select_dates_0_workshop_date' AND CAST(mt1.meta_value AS CHAR) < '05/16/2014') ) 
                GROUP BY wp_posts.ID 
                ORDER BY wp_postmeta.meta_value DESC 
                LIMIT 1000 
            ) 
    ) as combined LIMIT 15, 5
    

    デモ#3:

    3つ以上のサブクエリを組み合わせることもできます:

    /**
     * Demo #3 - Combine four sub queries:
     */
    
    $args = array( 
       'posts_per_page' => 10,
       'paged'          => 1,
       'sublimit'       => 1000,
       'args'           => array( $args1, $args2, $args3, $args4 ),
    );
    
    $results = new WP_Combine_Queries( $args );
    

    クラス:

    デモクラスは次のとおりです。

    /**
     * Class WP_Combine_Queries
     * 
     * @uses WP_Query_Empty
     * @link https://stackoverflow.com/a/23704088/2078474
     *
     */
    
    class WP_Combine_Queries extends WP_Query 
    {
        protected $args    = array();
        protected $sub_sql = array();
        protected $sql     = '';
    
        public function __construct( $args = array() )
        {
            $defaults = array(
                'sublimit'       => 1000,
                'posts_per_page' => 10,
                'paged'          => 1,
                'args'           => array(),
            );
    
            $this->args = wp_parse_args( $args, $defaults );
    
            add_filter( 'posts_request',  array( $this, 'posts_request' ), PHP_INT_MAX  );
    
            parent::__construct( array( 'post_type' => 'post' ) );
        }
    
        public function posts_request( $request )
        {
            remove_filter( current_filter(), array( $this, __FUNCTION__ ), PHP_INT_MAX  );
    
            // Collect the generated SQL for each sub-query:
            foreach( (array) $this->args['args'] as $a )
            {
                $q = new WP_Query_Empty( $a, $this->args['sublimit'] );
                $this->sub_sql[] = $q->get_sql();
                unset( $q );
            }
    
            // Combine all the sub-queries into a single SQL query.
            // We must have at least two subqueries:
            if ( count( $this->sub_sql ) > 1 )
            {
                $s = '(' . join( ') UNION (', $this->sub_sql ) . ' ) ';
    
                $request = sprintf( "SELECT SQL_CALC_FOUND_ROWS * FROM ( $s ) as combined LIMIT %s,%s",
                    $this->args['posts_per_page'] * ( $this->args['paged']-1 ),
                    $this->args['posts_per_page']
                );          
            }
            return $request;
        }
    
    } // end class
    
    /**
     * Class WP_Query_Empty
     *
     * @link https://stackoverflow.com/a/23704088/2078474
     */
    
    class WP_Query_Empty extends WP_Query 
    {
        protected $args      = array();
        protected $sql       = '';
        protected $limits    = '';
        protected $sublimit  = 0;
    
        public function __construct( $args = array(), $sublimit = 1000 )
        {
            $this->args     = $args;
            $this->sublimit = $sublimit;
    
            add_filter( 'posts_clauses',  array( $this, 'posts_clauses' ), PHP_INT_MAX  );
            add_filter( 'posts_request',  array( $this, 'posts_request' ), PHP_INT_MAX  );
    
            parent::__construct( $args );
        }
    
        public function posts_request( $request )
        {
            remove_filter( current_filter(), array( $this, __FUNCTION__ ), PHP_INT_MAX );
            $this->sql = $this->modify( $request );             
            return '';
        }
    
        public function posts_clauses( $clauses )
        {
            remove_filter( current_filter(), array( $this, __FUNCTION__ ), PHP_INT_MAX  );
            $this->limits = $clauses['limits'];
            return $clauses;
        }
    
        protected function modify( $request )
        {
            $request = str_ireplace( 'SQL_CALC_FOUND_ROWS', '', $request );
    
            if( $this->sublimit > 0 )
                return str_ireplace( $this->limits, sprintf( 'LIMIT %d', $this->sublimit ), $request );
            else
                return $request;
        }
    
       public function get_sql( )
        {
            return $this->sql;
        }
    
    } // end class
    

    その後、必要に応じてクラスを調整できます。

    ここで説明したトリックを使用します UNIONの順序を維持するため サブクエリ。sublimitを使用して適宜変更できます。 パラメータ。

    これは、メインクエリでも機能するはずです。 、posts_requestを使用して たとえば、フィルタ。

    これがお役に立てば幸いです。



    1. MySQLコマンドラインを使用したファイルからのインポートとファイルへのエクスポート

    2. Entity FrameworkがネストされたSQLクエリを生成するのはなぜですか?

    3. MySQL .frmからデータを復元する方法は?

    4. `INSERT ... ON DUPLICATE KEY UPDATE`で2行が影響を受けるのはなぜですか?