我正在扩展 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')
)
Wich 会返回类似这样的内容(我只发布一行):
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";}"
问题是我从未见过以这种格式存储的数据。
假设我想知道所有未预订的公寓:
两个日期:
$start_date = '05/16/2013';
$end_date = '09/16/2013';
mysql 中是否有任何函数可以帮助我将日期与 meta_value 的字段值相匹配?
这或多或少是我需要的:
$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 准备数据?
最佳答案
meta_value
看起来像一个序列化数组。
试试unserialize
var_dump( unserialize( $row->meta_value ) );
编辑
好的,所以您要查找两个日期之间的行。 这里的问题是:我们没有 MySQL 可以处理的规范化数据。
这会很慢(随着行数的增加而减慢),因为 MySQL 将不得不查看所有行
现在,第一步让我们尝试提取日期.. 不幸的是,MySQL 不提供任何正则表达式替换,因此我们必须使用字符串函数:
第 1 步:尝试提取日期
MySQL 有一组有用的字符串函数,如 LOCATE , SUBSTRING和 CHAR_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)
哇哦,看起来已经很棒了。
第二步:日期比较
现在我们要比较日期,就试试字符串
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 步:包装到函数中
完美..现在让我们把所有的东西打包成两个函数
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)
工作起来很有魅力,但是!!它会很慢!
第四步:规范化数据(建议)
如果您不想在您的应用程序中更改太多,所以开始日期和结束日期实际上存储在单独的日期字段中,您可以使用我们刚刚构建的两个函数和一个很酷的称为触发器的 MySQL 功能来管理这些字段静静地在后台,您可以将它们用于您的选择查询。
让我们首先将这两个字段添加到您的表中(确保替换表名)
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
现在让我们关心这些字段在将来自动维护: 我们需要在插入和更新之前执行此操作,因此有两个触发器:
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'
)
" );
希望这有帮助:)玩得开心
关于mysql - 如何将日期与此数据结构匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16754698/