1

wpテーマの機能を少し拡張していますが、

アパートの予約についてです。

予約は次のテーブルに保存されます: $wpdb->postmeta

SELECT meta_value,meta_key,post_id as start_date
FROM $wpdb->postmeta 
WHERE
    meta_key = 'stay_interval' AND
    post_id IN (SELECT ID FROM $wpdb->posts WHERE
            post_type = 'tvr_booking' AND
            post_status IN ('publish', 'draft') 
    )

次のようなものが返されます(1行だけ投稿します):

    array(8) {
  [0]=>
  object(stdClass)#348 (4) {
    ["meta_value"]=>
    string(75) "a:2:{s:10:"start_date";s:10:"05/16/2013";s:8:"end_date";s:10:"05/18/2013";}"
    ["meta_key"]=>
    string(13) "stay_interval"
    ["post_id"]=>
    string(4) "4059"
    ["start_date"]=>
    string(1) "0"
  }
  [1]=>
  object(stdClass)#349 (4) {
    ["meta_value"]=>
    string(75) "a:2:{s:10:"start_date";s:10:"12/14/2012";s:8:"end_date";s:10:"12/19/2012";}"
    ["meta_key"]=>
    string(13) "stay_interval"
    ["post_id"]=>
    string(4) "3897"
    ["start_date"]=>
    string(1) "0"
  }
  [2]=>
  object(stdClass)#350 (4) {
    ["meta_value"]=>
    string(75) "a:2:{s:10:"start_date";s:10:"12/13/2012";s:8:"end_date";s:10:"12/21/2012";}"
    ["meta_key"]=>
    string(13) "stay_interval"
    ["post_id"]=>
    string(4) "3942"
    ["start_date"]=>
    string(1) "0"
  }
  [3]=>
  object(stdClass)#346 (4) {
    ["meta_value"]=>
    string(75) "a:2:{s:10:"start_date";s:10:"12/13/2012";s:8:"end_date";s:10:"12/19/2012";}"
    ["meta_key"]=>
    string(13) "stay_interval"
    ["post_id"]=>
    string(4) "3943"
    ["start_date"]=>
    string(1) "0"
  }
  [4]=>
  object(stdClass)#344 (4) {
    ["meta_value"]=>
    string(75) "a:2:{s:10:"start_date";s:10:"12/21/2012";s:8:"end_date";s:10:"12/24/2012";}"
    ["meta_key"]=>
    string(13) "stay_interval"
    ["post_id"]=>
    string(4) "3944"
    ["start_date"]=>
    string(1) "0"
  }
  [5]=>
  object(stdClass)#343 (4) {
    ["meta_value"]=>
    string(75) "a:2:{s:10:"start_date";s:10:"12/26/2012";s:8:"end_date";s:10:"12/31/2012";}"
    ["meta_key"]=>
    string(13) "stay_interval"
    ["post_id"]=>
    string(4) "3945"
    ["start_date"]=>
    string(1) "0"
  }
  [6]=>
  object(stdClass)#292 (4) {
    ["meta_value"]=>
    string(75) "a:2:{s:10:"start_date";s:10:"12/24/2012";s:8:"end_date";s:10:"12/25/2012";}"
    ["meta_key"]=>
    string(13) "stay_interval"
    ["post_id"]=>
    string(4) "3946"
    ["start_date"]=>
    string(1) "0"
  }
  [7]=>
  object(stdClass)#338 (4) {
    ["meta_value"]=>
    string(75) "a:2:{s:10:"start_date";s:10:"05/30/2013";s:8:"end_date";s:10:"05/31/2013";}"
    ["meta_key"]=>
    string(13) "stay_interval"
    ["post_id"]=>
    string(4) "4021"
    ["start_date"]=>
    string(1) "0"
  }
}

したがって、メタ値を探しているフィールドは次のとおりです。

["meta_value"]=>
        string(75) "a:2:{s:10:"start_date";s:10:"05/16/2013";s:8:"end_date";s:10:"05/18/2013";}"

問題は、この形式で保存されたデータを見たことがないということです。

次の期間に予約されていないすべてのアパートを知りたいとしましょう。

2 つの日付:

$start_date = '05/16/2013';
$end_date = '09/16/2013';

日付をmeta_valueのフィールド値と一致させるのに役立つ関数がmysqlにありますか?

これは多かれ少なかれ私が必要とするものです:

$bookings = $wpdb->get_results( "
    SELECT ID FROM $wpdb->posts WHERE
        post_type = 'tvr_booking' AND
        post_status IN ('publish', 'draft') 
        AND ID not IN (
            SELECT post_id
            FROM $wpdb->postmeta 
            WHERE
                meta_key = 'stay_interval' AND
                somefunction(meta_value) >= '$start_date' AND
                somefunction(meta_value) <= '$end_date'
        )
" );

それはmysqlでできますか?そうでない場合、PHP でデータを準備するにはどうすればよいですか?

4

1 に答える 1

2

meta_valueシリアル化された配列のように見えます。アンシリアライズしてみる

var_dump( unserialize( $row->meta_value ) );

編集

では、2 つの日付の間にある行を見つけたいとします。ここでの問題: MySQL が処理できる正規化されたデータがありません。

MySQL はすべての行を調べる必要があるため、これは SLOW になります (行数が増えると遅くなります)。

それでは、最初のステップとして、日付を抽出してみましょう。 残念ながら、MySQL は正規表現の置換を提供していないため、文字列関数を使用する必要があります。

ステップ 1: 日付の抽出を試みる

MySQL には、ここで使用できるLOCATESUBSTRINGCHAR_LENGTHなどの一連の便利な文字列関数があります。

SET @meta_value := 'a:2:{s:10:"start_date";s:10:"05/16/2013";s:8:"end_date";s:10:"05/18/2013";}';

SET @pattern := 'start_date";s:10:"';    
SELECT SUBSTRING( @meta_value, LOCATE( @pattern, @meta_value ) + CHAR_LENGTH( @pattern ), 10 ) AS `start_date`;

+------------+
| start_date |
+------------+
| 05/16/2013 |
+------------+
1 row in set (0.00 sec)

SET @pattern := 'end_date";s:10:"';    
SELECT SUBSTRING( @meta_value, LOCATE( @pattern, @meta_value ) + CHAR_LENGTH( @pattern ), 10 ) AS `end_date`;

+------------+
| end_date   |
+------------+
| 05/18/2013 |
+------------+
1 row in set (0.00 sec)

うわー、それはもう素晴らしいですね。

Step2: 日付比較

ここで、文字列を試して、日付を比較したいと思います

mysql> SELECT '05/16/2013' > CURRENT_DATE;
ERROR 1267 (HY000): Illegal mix of collations (utf8_general_ci,COERCIBLE) and (latin1_swedish_ci,NUMERIC) for operation '>'

ダン、失敗します-なぜですか?文字列を抽出したので、MySQL は整数を比較します。日付を作成しましょう。MySQL には派手な関数STR_TO_DATEがあります。

mysql> SELECT STR_TO_DATE( '05/16/2013', '%m/%d/%Y');
+----------------------------------------+
| STR_TO_DATE( '05/16/2013', '%m/%d/%Y') |
+----------------------------------------+
| 2013-05-16                             |
+----------------------------------------+
1 row in set (0.00 sec)

いいね、そして比較?

mysql> SELECT STR_TO_DATE( '05/16/2013', '%m/%d/%Y') > CURRENT_DATE;
+-------------------------------------------------------+
| STR_TO_DATE( '05/16/2013', '%m/%d/%Y') > CURRENT_DATE |
+-------------------------------------------------------+
|                                                     0 |
+-------------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT STR_TO_DATE( '05/16/2013', '%m/%d/%Y') < CURRENT_DATE;
+-------------------------------------------------------+
| STR_TO_DATE( '05/16/2013', '%m/%d/%Y') < CURRENT_DATE |
+-------------------------------------------------------+
|                                                     1 |
+-------------------------------------------------------+
1 row in set (0.00 sec)

ステップ 3: 関数へのラップ

パーフェクト..すべてのものを2つの関数にまとめましょう

DELIMITER $$
CREATE FUNCTION `getStartDate`( metaValue TEXT ) RETURNS DATE
    READS SQL DATA
    DETERMINISTIC
    SQL SECURITY INVOKER
BEGIN
    DECLARE startDate DATE;
    DECLARE pattern TEXT DEFAULT 'start_date";s:10:"';

    SELECT STR_TO_DATE( SUBSTRING( metaValue, LOCATE( pattern, metaValue ) + CHAR_LENGTH( pattern ), 10 ), '%m/%d/%Y' ) INTO startDate; 
    RETURN startDate;
END$$

CREATE FUNCTION `getEndDate`( metaValue TEXT ) RETURNS DATE
    READS SQL DATA
    DETERMINISTIC
    SQL SECURITY INVOKER
BEGIN
    DECLARE endDate DATE;
    DECLARE pattern TEXT DEFAULT 'end_date";s:10:"';

    SELECT STR_TO_DATE( SUBSTRING( metaValue, LOCATE( pattern, metaValue ) + CHAR_LENGTH( pattern ), 10 ), '%m/%d/%Y' ) INTO endDate; 
    RETURN endDate;
END$$


DELIMITER ;

テスト:

mysql> SELECT getStartDate( @meta_value );
+-----------------------------+
| getStartDate( @meta_value ) |
+-----------------------------+
| 2013-05-16                  |
+-----------------------------+
1 row in set (0.00 sec)

mysql> SELECT getEndDate( @meta_value );
+---------------------------+
| getEndDate( @meta_value ) |
+---------------------------+
| 2013-05-18                |
+---------------------------+
1 row in set (0.00 sec)


mysql> SELECT getEndDate( @meta_value ) > '2013-05-12';
+------------------------------------------+
| getEndDate( @meta_value ) > '2013-05-12' |
+------------------------------------------+
|                                        1 |
+------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT getStartDate( @meta_value ) > '2013-05-12';
+--------------------------------------------+
| getStartDate( @meta_value ) > '2013-05-12' |
+--------------------------------------------+
|                                          1 |
+--------------------------------------------+
1 row in set (0.00 sec)


mysql> SELECT * FROM wpTest WHERE getStartDate( meta_value ) >= '2013-05-16' AND getEndDate( meta_value ) <= '2013-05-18';
+-----------------------------------------------------------------------------+
| meta_value                                                                  |
+-----------------------------------------------------------------------------+
| a:2:{s:10:"start_date";s:10:"05/16/2013";s:8:"end_date";s:10:"05/18/2013";} |
+-----------------------------------------------------------------------------+
1 row in set (0.00 sec)

魅力のように機能しますが、!! 遅くなります!

ステップ 4: データの正規化 (提案)

開始日と終了日が実際には別々の日付フィールドに格納されるように、アプリケーションをあまり変更したくない場合は、作成したばかりの 2 つの関数と、トリガーと呼ばれるクールな MySQL 機能を使用して、これらのフィールドをサイレント モードで管理できます。バックグラウンドであり、選択クエリにのみ使用できます。

まず、これら 2 つのフィールドをテーブルに追加しましょう (テーブル名を必ず置き換えてください)。

ALTER TABLE `wpTest` 
     ADD `end_date` DATE NOT NULL DEFAULT '0000-00-00' AFTER `meta_value`,
     ADD `start_date` DATE NOT NULL DEFAULT '0000-00-00' AFTER `meta_value`;

将来のクエリに使用するフィールドを取得したので、それらに素敵な関数を入力しましょう。

mysql> UPDATE wpTest SET start_date = getStartDate( meta_value ), end_date = getEndDate( meta_value );
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

これらのフィールドが将来自動的に維持されるように注意しましょう: これを BEFORE INSERT と BEFORE UPDATE で行う必要があるため、2 つのトリガー:

DELIMITER $$
CREATE TRIGGER `wpTest_trg_BI` BEFORE INSERT ON `wpTest` FOR EACH ROW
BEGIN
    SET NEW.`start_date` = `getStartDate`( NEW.`meta_value` );
    SET NEW.`end_date` = `getEndDate`( NEW.`meta_value` );
END$$

CREATE TRIGGER `wpTest_trg_BU` BEFORE UPDATE ON `wpTest` FOR EACH ROW
BEGIN
    SET NEW.`start_date` = `getStartDate`( NEW.`meta_value` );
    SET NEW.`end_date` = `getEndDate`( NEW.`meta_value` );
END$$

DELIMITER ;

トリガーのテスト:

mysql> INSERT INTO wpTest (meta_value) SELECT 'a:2:{s:10:"start_date";s:10:"05/12/2013";s:8:"end_date";s:10:"05/20/2013";}';
Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> INSERT INTO wpTest (meta_value) SELECT 'a:2:{s:10:"start_date";s:10:"05/10/2013";s:8:"end_date";s:10:"05/23/2013";}';
Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM wpTest;
+-----------------------------------------------------------------------------+------------+------------+
| meta_value                                                                  | start_date | end_date   |
+-----------------------------------------------------------------------------+------------+------------+
| a:2:{s:10:"start_date";s:10:"05/16/2013";s:8:"end_date";s:10:"05/18/2013";} | 2013-05-16 | 2013-05-18 |
| a:2:{s:10:"start_date";s:10:"05/12/2013";s:8:"end_date";s:10:"05/20/2013";} | 2013-05-12 | 2013-05-20 |
| a:2:{s:10:"start_date";s:10:"05/10/2013";s:8:"end_date";s:10:"05/23/2013";} | 2013-05-10 | 2013-05-23 |
+-----------------------------------------------------------------------------+------------+------------+
3 rows in set (0.00 sec)

完璧な、挿入作業、現在更新をテストしています:

mysql> UPDATE wpTest SET meta_value = 'a:2:{s:10:"start_date";s:10:"05/16/2014";s:8:"end_date";s:10:"05/18/2014";}';
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3  Changed: 3  Warnings: 0

mysql> SELECTS * FROM wpTest;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELECTS * FROM wpTest' at line 1
mysql> SELECT * FROM wpTest;
+-----------------------------------------------------------------------------+------------+------------+
| meta_value                                                                  | start_date | end_date   |
+-----------------------------------------------------------------------------+------------+------------+
| a:2:{s:10:"start_date";s:10:"05/16/2014";s:8:"end_date";s:10:"05/18/2014";} | 2014-05-16 | 2014-05-18 |
| a:2:{s:10:"start_date";s:10:"05/16/2014";s:8:"end_date";s:10:"05/18/2014";} | 2014-05-16 | 2014-05-18 |
| a:2:{s:10:"start_date";s:10:"05/16/2014";s:8:"end_date";s:10:"05/18/2014";} | 2014-05-16 | 2014-05-18 |
+-----------------------------------------------------------------------------+------------+------------+
3 rows in set (0.00 sec)

パーフェクト、更新も同様に機能します..これで、高速である必要がある SELECT クエリで関数を使用する必要がなくなりました。

$bookings = $wpdb->get_results( "
    SELECT ID FROM $wpdb->posts WHERE
        post_type = 'tvr_booking' AND
        post_status IN ('publish', 'draft') 
        AND ID not IN (
            SELECT post_id
            FROM $wpdb->postmeta 
            WHERE
                meta_key = 'stay_interval' AND
                start_date >= '$start_date' AND
                end_date <= '$end_date'
        )
" );

これが役立つことを願っています:)楽しんでください

于 2013-05-25T23:17:30.567 に答える