仅当存在非空值时,SQL左连接非空值
我正在使用地理位置变量,我相信这应该比我现在做的简单得多 我想返回一行,并将其他三个“选项”作为其他值左键连接到该行,这是通过使用用户的地理位置来完成的,一些选项将根据这一点而有所不同。所有选项都有一个默认值,因此我只想在匹配地理位置时覆盖默认值 表1将有汉堡、热狗等项目,而表2将有点像浇头,每个项目将有多达三层浇头,一些将根据地理位置进行更改 表一仅当存在非空值时,SQL左连接非空值,sql,subquery,left-join,Sql,Subquery,Left Join,我正在使用地理位置变量,我相信这应该比我现在做的简单得多 我想返回一行,并将其他三个“选项”作为其他值左键连接到该行,这是通过使用用户的地理位置来完成的,一些选项将根据这一点而有所不同。所有选项都有一个默认值,因此我只想在匹配地理位置时覆盖默认值 表1将有汉堡、热狗等项目,而表2将有点像浇头,每个项目将有多达三层浇头,一些将根据地理位置进行更改 表一 |id | name | ______________ |0 | burger | |1 | hotdog |
|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
我的结果是只返回一个汉堡包和番茄酱、芥末,在第3层的顶部有培根,因此我需要一个值,如果有空值和字母值,则以字母值为层,否则以空值为层。我希望在查询返回500多条记录的速度时不要使用嵌套选择,因为您的查询中存在一个问题,即
连接
条件的或ed部分应该在括号中,以获得您想要的结果,即条件应该如下所示:
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'
):
如果需要为所有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
应在引号中,否则将被视为列名。此外,正如Gordon在评论中指出的那样,表two
似乎应该有一个itemid
,这样您就可以将配料链接到特定的项目(以防您不希望培根成为热狗的有效配料)。如果每个项目都有配料,然后,我希望在第二个表中有一个itemid
。如果返回两个项目,那么order by在结束时会起作用,就像返回多行一样,因为limit 1将只返回一行。是否选择DISTICT work为多行返回第一个值?@RadiumChris如果您的意思是在item.id上没有WHERE
子句,则不会。你的问题中没有提到这个选项。。。您需要查询在该场景中工作吗?如果是这样,您将不得不使用嵌套选择。@RadiumChris您使用的是哪种SQL?MySQL,SQL server???什么版本?我运行的是MySQL5.7,我希望我缺少一些东西来进行快速修复,我可以使用嵌套选择器,或者只返回6个“toppings”(null和geo版本),如果在php中使用它们,则可以显示正确的值。在网络方面,速度推动了太多东西,我想我现在对很多东西都想得太多了。在5.7中没有。在8+中,您可以使用行号和CTE来轻松过滤。否则,您可以通过使用我的查询中显示的顺序,简单地获取每个项目遇到的第一行,在PHP中进行过滤。
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