我有一个数据库,里面装满了很多"空"记录,我想去掉那些孤立的记录。
数据库的结构是这样的
- 包含实际条目(meta_value)的子行
- "链接"到其子行(通过其meta_key)的父行
| meta_id post_id meta_key meta_value |
| |
| 011 301 ACF__P_01_01 Foo |
| 012 309 _ACF__P_01_01 field_5874d5 |
| 013 321 ACF__P_01_02 |
| 014 316 _ACF__P_01_02 field_54290a |
| 015 119 ACF__P_01_03 Bar |
| 016 101 _ACF__P_01_03 field_a04a88 |
| 017 119 ACF__P_01_03 |
| 018 101 _ACF__P_01_03 field_a04a88 |
| 019 149 ACF__P_01_03 |
| 020 111 _ACF__P_01_03 field_a04a88 |
| 021 169 ACF__P_01_03 Foo Bar |
| 022 171 _ACF__P_01_03 field_a04a88 |
使用这样的查询可以很容易地选择所有(空的)"子"行;
SELECT
*
FROM
wp_postmeta
WHERE
wp_postmeta.meta_key LIKE '%ACF__%'
AND
wp_postmeta.meta_value LIKE ''
但是这个查询只获取(空的)"子"行,而不是它们的"父"行。
有两个逻辑条件将父对象绑定到子对象;
- 第一行始终是子行,紧接着是其父行
- 父行具有与其子行相同的">meta_key"值,但由下划线预先固定
有没有办法创建一个SQL查询来选择空的子记录(就像我上面做的那样)和它的父记录?
我更喜欢用一个查询来同时获取它们,但当这不可能时,我也可以运行两个查询(第一个用于获取父查询,第二个用于获取空的子查询,我想)。
我使用Navicat进行数据库管理,所以它必须是纯SQL,而不是PHP。
查询应该像这样吐出结果
| meta_id post_id meta_key meta_value |
| |
| 013 321 ACF__P_01_02 |
| 014 316 _ACF__P_01_02 field_54290a |
| 017 119 ACF__P_01_03 |
| 018 101 _ACF__P_01_03 field_a04a88 |
| 019 149 ACF__P_01_03 |
| 020 111 _ACF__P_01_03 field_a04a88 |
所以空的子项("meta_value"中没有值)和它的父项(都有相同的"meta_key",其中父项有下划线。
使用自加入
Select *
from wp_postmeta c
join wp_postmeta p
on p.meta_key = '_' + c.meta_key
以上操作将仅获取父子记录的"对"。如果父母没有孩子是可能的(我认为没有父母是不可能的),并且你希望所有的父母,包括没有孩子的父母,都使用外部连接
Select *
from wp_postmeta p
left join wp_postmeta c
on '_' + c.meta_key = p.meta_key
在关系数据库中,没有"after"或"before"这样的概念,除非你自己定义它,并将数据添加到实现该概念的表中(如日期时间戳或按顺序递增的数字键,或其他什么)。如果没有这样的工件,关系数据库表中的记录就不会有任何隐含的顺序。
使用PHP我解决了这个问题。我迭代查询的第一个结果(获取所有空的子项),并在循环中获取该子项之后的每一行。
但那是PHP——我想要纯SQL:)
<?php
$connection = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
if ($connection -> connect_errno > 0) {
die ("Unable to connect to database [" . $connection->connect_error . "]");
}
$query_1 = "SELECT * FROM `wp_postmeta` WHERE `meta_key` LIKE '%ACF%__' AND `meta_value` LIKE ''";
if (!$result_1 = $connection -> query($query_1)) {
die ("There was an error running query[" . $connection -> error . "]");
}
if ($result_1) {
$i = 0;
echo "<h2>ACF - empty fields</h2>";
echo "<table border=1 cellpadding=4 cellspacing=0 width=800>";
echo "<tr style='background:#eee;font-weight:bold;'><td>row</td><td>meta_id</td><td>post_id</td><td>meta_key</td><td>meta_value</td></tr>";
while ($row_1 = $result_1 -> fetch_assoc()) {
$i++;
echo "<tr>";
echo "<td width=100>" . sprintf('%03d', $i) . "</td>";
echo "<td width=100 style='background:#aaa;color:#fff;font-weight:bold;'>" . $row_1["meta_id"] . "</td>";
echo "<td width=100>" . $row_1["post_id"] . "</td>";
echo "<td width=100>" . $row_1["meta_key"] . "</td>";
echo "<td width=500>" . $row_1["meta_value"] . "</td>";
echo "</tr>";
$query_2 = "SELECT * FROM `wp_postmeta` WHERE `meta_id` = " . ($row_1["meta_id"] + 1);
if (!$result_2 = $connection -> query($query_2)) {
die ("There was an error running query[" . $connection -> error . "]");
}
while ($row_2 = $result_2 -> fetch_assoc()) {
$i++;
echo "<tr>";
echo "<td width=100>" . sprintf('%03d', $i) . "</td>";
echo "<td width=100 style='background:#aaa;color:#fff;font-weight:bold;'>" . $row_2["meta_id"] . "</td>";
echo "<td width=100>" . $row_2["post_id"] . "</td>";
echo "<td width=100>" . $row_2["meta_key"] . "</td>";
echo "<td width=500>" . $row_2["meta_value"] . "</td>";
echo "</tr>";
}
mysqli_free_result($result_2);
}
mysqli_free_result($result_1);
echo "</table>";
} else {
echo "No entries found.";
}
?>
-编辑-
这个PHP代码更好,我想。。。它只使用了两个查询,并对第一个查询进行迭代。。。
它工作得很好,但仍然不是纯SQL——我想去掉PHP。。。
<?php
/* --------------------------------------------------- */
$connection = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
if ($connection -> connect_errno > 0) {
die ("Unable to connect to database [" . $connection->connect_error . "]");
}
/* --------------------------------------------------- */
$query = "SELECT `meta_id` FROM `wp_postmeta` WHERE `meta_key` LIKE '%ACF%__' AND `meta_value` LIKE ''";
if (!$result = $connection -> query($query)) {
die ("There was an error running query[" . $connection -> error . "]");
}
if ($result) {
$array = array();
while ($row = $result -> fetch_assoc()) {
$array[] = $row["meta_id"];
$array[] = $row["meta_id"] + 1;
}
mysqli_free_result($result);
/* --------------------------------------------------- */
$query = "SELECT * FROM `wp_postmeta` WHERE `meta_id` IN (" . implode(",", array_map("intval", $array)) . ")";
if (!$result = $connection -> query($query)) {
die ("There was an error running query[" . $connection -> error . "]");
}
if ($result) {
$i = 0;
echo "<h2>ACF - empty fields</h2>";
echo "<table>";
echo "<tr><td>record</td><td>meta_id</td><td>post_id</td><td>meta_key</td><td>meta_value</td></tr>";
while ($row = $result -> fetch_assoc()) {
$i++;
echo "<tr>";
echo "<td>" . sprintf('%03d', $i) . "</td>";
echo "<td>" . $row["meta_id"] . "</td>";
echo "<td>" . $row["post_id"] . "</td>";
echo "<td>" . $row["meta_key"] . "</td>";
echo "<td>" . $row["meta_value"] . "</td>";
echo "</tr>";
}
mysqli_free_result($result);
echo "</table>";
if (isset($_GET["delete"])) {
echo "<span>all records deleted</span>";
} else {
echo "<a href='?delete'>delete empty records</a>";
}
}
/* --------------------------------------------------- */
} else {
echo "No entries found.";
}
?>