我有一个在线商店的搜索字段,该站点使用MySQL查询两个不同的表。第一个表是具有13列的 vinyls ,第二个表是具有10列的 products 。我想要的结果是,如果您输入一个关键字,它将搜索表 vinyls 中的专辑名称和 artist_name 列,以及表产品中的名称列以查找任何匹配项。
我的php代码首先计算匹配的次数,如果匹配,则再次使用查询来显示匹配,就像在线商店一样。但是,当我对其进行测试时,它仅显示 vinyls 表中的结果,而不显示 products 表中的结果。我尝试使用 UNION ,但是由于两个表的列数不同,因此会导致错误。我已经使用 NULL 来填充 union 所需的缺少的列,但是它也不起作用。联接也无济于事,因为两个表没有任何相似的列。麻烦的是在第一个查询中使用count(*)。
我的SQL查询使用UNION和COUNT:
(SELECT COUNT(*) AS numrows
FROM vinyls
WHERE ( album_name LIKE :keyword
OR artist_name LIKE :keyword)
)
union
(SELECT COUNT(*) AS numrows
FROM products
WHERE name LIKE :keyword)
我用于搜索字段的php代码:
$stmt = $conn->prepare("(SELECT COUNT(*) AS numrows
FROM vinyls
WHERE ( album_name LIKE :keyword
OR artist_name LIKE :keyword)
)
union
(SELECT COUNT(*) AS numrows
FROM products
WHERE name LIKE :keyword)");
$stmt->execute(['keyword' => '%'.$_POST['keyword'].'%']);
$row = $stmt->fetch();
if($row['numrows'] < 1){
echo '<h1 class="page-header">No results found for <i>'.$_POST['keyword'].'</i></h1>';
}else{
echo '<h1 class="page-header">Search results for <i>'.$_POST['keyword'].'</i></h1>';
try{
$inc = 3;
$stmt = $conn->prepare("(SELECT *
FROM vinyls
WHERE ( album_name LIKE :keyword
OR artist_name LIKE :keyword)
)
union
(SELECT *
FROM products
WHERE name LIKE :keyword)");
$stmt->execute(['keyword' => '%'.$_POST['keyword'].'%']);
foreach ($stmt as $row) {...
我已经很困惑如何仅从一个搜索字段中搜索2个表并显示两个表(而不只是一个表)的结果。而且,在将商品添加到购物车中时,这也是一个类似的问题,因为它们可以来自两个表,而我必须再次“联接”这两个表。
我哪里出错了?
编辑:
样本数据
Vinyls table
+----+------------------+---------------------------+-----------+
| id | album_name | artist_name | genre |
+----+------------------+---------------------------+-----------+
| 11 | Ravel Bolero | Boston Symphony Orchestra | Classical |
| 12 | TV Calendar Show | Arthur Godfrey | Orchestra |
| 13 | Flip Phillips | The Phillips Quartet | Jazz |
| 14 | The Modern Idiom | Various artists | Jazz |
+----+------------------+---------------------------+-----------+
Products table
+----+-------------+------------------------------------------------------+
| id | category_id | name |
+----+-------------+------------------------------------------------------+
| 31 | 15 | Tonka/Diecast trucks and cars |
| 32 | 21 | Plate Number Georgia PQQ 1151 |
| 33 | 6 | Walt Disney Read Along Casette Tapes |
| 34 | 7 | Herbert Von Karajan |
| 35 | 8 | BANK IT! Board Game |
| 36 | 9 | Iraqi Most Wanted Playing Cards |
| 37 | 10 | STAR TREK ( 1991,'92,'93 ) Stamp Oasis Rubber Stamps |
| 38 | 11 | Batman and Friends Action Figure Toys (4" - 5") |
| 39 | 12 | Delta Dawn Porcelain Doll |
+----+-------------+------------------------------------------------------+
预期结果类似于亚马逊的搜索栏,在其中键入关键字并在输入后显示结果。我要在网站上显示的是,如果我在搜索字段中输入管弦乐队,它将显示“波士顿交响乐团”的行。或者,如果我输入汽车,它将显示tonka行。
我得到的是,即使我键入了cars,并且product表中应该有一个匹配项,它也只显示 vinyls 表,而不显示 products 表。或者我收到一个错误,因为联合仅适用于具有相似列数的表。
答案 0 :(得分:1)
您的代码中有2个问题。
首先,您的计数查询应该可以正常工作并且不会引发任何错误,但是您只查看第一结果行(您的乙烯基之一)。但是您的查询返回两行。 (它将为您的联合中的第一个联合查询(乙烯基)返回带有numrows
字段的一行,为第二个查询(产品)返回具有numrows
字段的一行。
您可以将其包装到SUM
中,以仅返回一个结果行:
$stmt = $conn->prepare("SELECT SUM(numrows) AS numrows FROM
(SELECT COUNT(*) AS numrows
FROM vinyls
WHERE ( album_name LIKE :keyword
OR artist_name LIKE :keyword)
)
union
(SELECT COUNT(*) AS numrows
FROM products
WHERE name LIKE :keyword)) AS sumQuery");
第二个问题是查询,由于列数不匹配,该查询将加载结果并引发异常。您必须定义应返回两个联合查询中的每一个的哪些列,并且它们必须在两者上都匹配。所以做到这一点:
$stmt = $conn->prepare("(SELECT id, album_name AS name, artist_name
FROM vinyls
WHERE ( album_name LIKE :keyword
OR artist_name LIKE :keyword)
)
union
(SELECT id, name, NULL AS artist_name
FROM products
WHERE name LIKE :keyword)");