web-dev-qa-db-ja.com

複数のメタフィールド順

2つのカスタムフィールドがあります。

  • meta_key1はブール値です(0または1)。
  • meta_key2は日付値です。例えば20150623

すべてのmeta_key2フィールドに明示的な値があるわけではありません。空の文字列''として扱われているようです。

今日よりも大きいmeta_key2(date)値を持つすべての投稿、またはtrueであるmeta_key1値を持つすべての投稿を探したい.

これは私が彼らに表示して欲しい順番です。

  1. key2.meta_value >= today ASC
  2. key1.meta_value = TRUE ordered by date ASC(最初に日付が与えられたもの).

問題の一部は、空の日付パラメータを持つフィールドは0として扱われるため、ASCの順序で最初に来るということです。私はこれを説明するためにCOALESCEを使おうとしました、そして、いくらかの成功を収めました、しかし、私は片側でハングアップしました。 key1.meta_value = FALSEkey2.meta_value is >= todayという投稿をASCの順序で表示することができません。

これが私の質問です:

$meta_key1 = 'prog_ongoing';
$meta_key2 = 'prog_date_start';
$start_date = date('Ymd');

$postids = $wpdb->get_col( $wpdb->prepare( 
"
SELECT      DISTINCT key1.post_id
FROM        $wpdb->postmeta key1
INNER JOIN  $wpdb->postmeta key2
            ON key2.post_id = key1.post_id
            AND key2.meta_key = %s
WHERE       key1.meta_key = %s
            AND key1.meta_value is TRUE
            OR key2.meta_value >= %d
ORDER BY    COALESCE(NULLIF(key1.meta_value, 0), 0) DESC, COALESCE(NULLIF(key2.meta_value, ''), $start_date) ASC, key2.meta_value ASC 
",
$meta_key2,
$meta_key1,
$start_date
) );

key1.meta_valueに対する私のCOALESCEステートメントが何かをしているかどうか私はわかりません。これについて何か洞察をありがとう。

2
eleclair

クエリの1つの問題は、あいまいなWHEREを使った自己結合が(DISTINCTでマスクされている)交差データセットを提供することです。したがって、キーに正確に一致する結合をアタッチするベースとしてwp_postを使用する方が簡単です例えば

    SELECT      p.ID, key1.meta_value as prog_ongoing, key2.meta_value as prog_date_start
    FROM        $wpdb->posts p
    INNER JOIN  $wpdb->postmeta key1
                ON key1.post_id = p.ID
                AND key1.meta_key = %s
    INNER JOIN  $wpdb->postmeta key2
                ON key2.post_id = p.ID
                AND key2.meta_key = %s

これは線形データセットを与えます。その後、データを制限するためにWHERE句を追加してもしなくてもかまいません。

    WHERE       key1.meta_value IS TRUE OR key2.meta_value >= %d

ORDER BYには、CASEステートメントの単一フィールドソートを使用します。

    ORDER BY    CASE
                    WHEN key2.meta_value >= %d THEN CONCAT('A', key2.meta_value)
                    WHEN key1.meta_value AND key2.meta_value THEN CONCAT('B', key2.meta_value)
                    WHEN key1.meta_value THEN 'C'
                    ELSE 'D'
                END ASC

上記のものはprepare引数が必要です:

    $meta_key1,
    $meta_key2,
    $start_date, $start_date

posts_orderbyフィルタを使用して、WP_Queryを使用して同様のことを実行できます(ただし、クロスデータセットを生成するメソッドを使用しているため、GROUP BYを使用する必要があり、作業が複雑になる可能性があります)。例えば

$args = array(
    'posts_per_page' => -1,
    'post_type' => 'cpt_program',
    'meta_query' => array(
        'ongoing' => array(
            'key' => 'prog_ongoing',
        ),
        'start_date' => array(
            'key' => 'prog_date_start',
        )
    ),
);

add_filter( 'posts_orderby', $func = function ( $orderby, $query ) {
    $start_date = date('Ymd');
    global $wpdb;
    $orderby = $wpdb->prepare(
        "
        CASE
            WHEN mt1.meta_value >= %d THEN CONCAT('A', mt1.meta_value)
            WHEN {$wpdb->postmeta}.meta_value AND mt1.meta_value THEN CONCAT('B', mt1.meta_value)
            WHEN {$wpdb->postmeta}.meta_value THEN 'C'
            ELSE 'D'
        END ASC
        "
        , $start_date
    );
    return $orderby;
}, 10, 2 );
$query = new WP_Query( $args );
remove_filter( 'posts_orderby', $func, 10, 2 );
2
bonger

最初の解決策を渡します。これは4.2で導入された新しいメタソートを使用します。

 <?php
    $args = array(
        'posts_per_page' => -1,
        'meta_query' => array(
            'relation' => 'OR',
            'ongoing' => array(
                'key'     => 'prog_ongoing',
                'value'   => 1
            ),
            'start_date' => array(
                array(
                    'key' => 'prog_date_start',
                    'value'   => date('Ymd'),
                    'type'    => 'numeric',
                    'compare' => '>='
                )
            )
        ),
        'orderby' => 'start_date ongoing',
        'order'   => 'ASC',
    );

    $programs = new WP_Query($args);
    ?>
    <?php while($programs->have_posts()): $programs->the_post(); ?>
        <h1><?php the_title(); ?></h1>
    <?php endwhile; ?>

論理は正しいと思いますが、それ以外の場合はお知らせください。

編集

次のmakeで、Wordpress 4.2の複数のカスタムフィールドでソートするための新しい構文をチェックアウトできます。

3
Manny Fleurmond

なぜWP_Query()を使わないのですか?この方法はもっと簡単です。

    <?php
    $args = array(
        'posts_per_page' => -1,
        'meta_query' => array(
            'relation' => 'OR',
            array(
                'key'     => 'prog_ongoing',
                'value'   => 1
            ),
            array(
                'relation' => 'AND',
                array(
                    'key' => 'prog_date_start',
                    'value'   => date('Ymd'),
                    'type'    => 'numeric',
                    'compare' => '<='
                ),
                array(
                   'key' => 'prog_date_start',
                    'value'   => 1,
                    'type'    => 'numeric',
                    'compare' => '>'
                )
            )
        ),
        'orderby' => 'meta_value_num date',
        'order'   => 'ASC',
        'meta_key' => 'prog_date_start'
    );

    $programs = new WP_Query($args);
    ?>
    <?php while($programs->have_posts()): $programs->the_post(); ?>
        <h1><?php the_title(); ?></h1>
    <?php endwhile; ?>
0
passatgt