2つのカスタムフィールドがあります。
meta_key1
はブール値です(0
または1
)。meta_key2
は日付値です。例えば20150623
。すべてのmeta_key2
フィールドに明示的な値があるわけではありません。空の文字列''
として扱われているようです。
今日よりも大きいmeta_key2
(date)値を持つすべての投稿、またはtrueであるmeta_key1
値を持つすべての投稿を探したい.
これは私が彼らに表示して欲しい順番です。
key2.meta_value >= today ASC
key1.meta_value = TRUE ordered by date ASC
(最初に日付が与えられたもの).
問題の一部は、空の日付パラメータを持つフィールドは0
として扱われるため、ASC
の順序で最初に来るということです。私はこれを説明するためにCOALESCE
を使おうとしました、そして、いくらかの成功を収めました、しかし、私は片側でハングアップしました。 key1.meta_value = FALSE
とkey2.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
ステートメントが何かをしているかどうか私はわかりません。これについて何か洞察をありがとう。
クエリの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 );
最初の解決策を渡します。これは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の複数のカスタムフィールドでソートするための新しい構文をチェックアウトできます。
なぜ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; ?>