我正在使用GEO Location变量,我认为这应该比我做的要简单得多。
我想返回一行,并将其他三个“选项”作为其他值保留在该行上,这是通过使用用户的地理位置来完成的,其中一些选项会有所不同。所有选项都有默认值,因此,如果我与地理位置匹配,我只想覆盖默认值
表1中将包含汉堡,热狗等物品,而表2中将具有浇头之类的东西,并且每个表项最多具有三层浇头,其中一些会根据地理位置而改变。
表一
|id | name |
______________
|0 | burger |
|1 | hotdog |
表二
|topid | topping | layer | location
___________________________________
| 0 | catsup | 1 |
| 1 | mustard | 2 |
| 2 | onion | 3 |
| 3 | lettuce | 3 | US
| 4 | bacon | 3 | CA
$geo = 'CA';
mySql
SELECT item.name, layer1.topping as `layer1`, layer2.topping as `layer2`, layer3.topping as `layer3`
FROM `one` item
LEFT JOIN `two` layer1
ON layer1.layer = 1
AND layer1.location IS NULL OR layer1.location = $geo
LEFT JOIN `two` layer2
ON layer2.layer = 2
AND layer2.location IS NULL OR layer2.location = $geo
LEFT JOIN `two` layer3
ON layer3.layer = 3
AND layer3.location IS NULL OR layer3.location = $geo
WHERE item.id = 0
我的结果将是只返回一个带有catsup,芥末酱和培根的汉堡,因此我需要一个如果有NULL值和字母值的字母值作为图层,否则取NULL。我希望做到这一点而不必在查询中嵌套选择以加快返回500条以上记录的速度
答案 0 :(得分:1)
查询中存在一个问题,其中OR
条件的JOIN
版部分应放在括号中以获得所需的结果,即条件应如下所示:
ON layer1.layer = 1
AND (layer1.location IS NULL OR layer1.location = $geo)
此问题解决后,您的查询将产生多行,具体取决于two
中与$geo
匹配的行的存在。您可以根据每一层的位置是否为NULL
来对这些行进行排序,从而使匹配最多位置的行成为第一行。然后,您可以使用LIMIT 1
仅选择该行:
SELECT item.name, layer1.topping as `layer1`, layer2.topping as `layer2`, layer3.topping as `layer3`
FROM `one` item
LEFT JOIN `two` layer1
ON layer1.layer = 1
AND (layer1.location IS NULL OR layer1.location = '$geo')
LEFT JOIN `two` layer2
ON layer2.layer = 2
AND (layer2.location IS NULL OR layer2.location = '$geo')
LEFT JOIN `two` layer3
ON layer3.layer = 3
AND (layer3.location IS NULL OR layer3.location = '$geo')
WHERE item.id = 0
ORDER BY layer1.location IS NULL,
layer2.location IS NULL,
layer3.location IS NULL
LIMIT 1
输出(对于您的示例数据,假设$geo = 'CA'
):
name layer1 layer2 layer3
burger catsup mustard bacon
如果您需要获取所有item.id
值,则 需要使用嵌套的SELECT
。这是可以完成的一种方法:
SELECT item.name, layer1.topping as `layer1`, layer2.topping as `layer2`, layer3.topping as `layer3`
FROM `one` item
LEFT JOIN `two` layer1
ON layer1.layer = 1
AND (layer1.location IS NULL OR layer1.location = 'CA')
LEFT JOIN `two` layer2
ON layer2.layer = 2
AND (layer2.location IS NULL OR layer2.location = 'CA')
LEFT JOIN `two` layer3
ON layer3.layer = 3
AND (layer3.location IS NULL OR layer3.location = 'CA')
JOIN(
SELECT item.name,
MIN((layer1.location IS NULL) + (layer2.location IS NULL) + (layer3.location IS NULL)) AS mostspecific
FROM `one` item
LEFT JOIN `two` layer1
ON layer1.layer = 1
AND (layer1.location IS NULL OR layer1.location = 'CA')
LEFT JOIN `two` layer2
ON layer2.layer = 2
AND (layer2.location IS NULL OR layer2.location = 'CA')
LEFT JOIN `two` layer3
ON layer3.layer = 3
AND (layer3.location IS NULL OR layer3.location = 'CA')
GROUP BY item.name
) sp ON item.name = sp.name AND (layer1.location IS NULL) + (layer2.location IS NULL) + (layer3.location IS NULL) = sp.mostspecific
输出:
name layer1 layer2 layer3
burger catsup cheese bacon
hotdog catsup cheese bacon
注释$geo
应该用引号引起来,否则将被视为列名。而且,正如戈登在评论中指出的那样,表two
似乎应该有一个itemid
,以便您可以将浇头链接到特定的项目(以防您将培根作为菜单项)。有效的热狗浇头)。