MySQL - 如何选择表中的行,其中 id 值位于另一个表中的逗号分隔字段中?
Posted
技术标签:
【中文标题】MySQL - 如何选择表中的行,其中 id 值位于另一个表中的逗号分隔字段中?【英文标题】:MySQL - How to select rows in a table where id value is in a comma delimited field in another table? 【发布时间】:2018-09-03 20:45:01 【问题描述】:我已经在这个问题上工作了 3 天,而且眼睛很迷糊。 我有一个 SQL“客户”表,其中包含客户姓名、地址、电子邮件和一个名为“venue”的字段,其中包含他们感兴趣的培训课程地点的逗号分隔的一组“id”。(如:18, 22,35,41)
我有第二张桌子,叫做“场地”,里面有所有课程的场地。 每门课程都是“场地”表中的一个单独的行,带有一个自动递增的 ID。 “客户”表中的场所字段是客户在注册时选择的场所表中“id”行的集合。
一旦客户注册并被传送到“我的兴趣”页面,我想通过输出“venue”表的每个“id”的行数据来显示他们注册感兴趣的课程。在客户表的“customer.venue”字段中。
我希望这是有道理的......
我的客户选择
$sqlc = "Select * from customers ORDER BY id DESC LIMIT 1";
我的场地选择
$venue = $result['venue'];
我当前的“场地”选择代码不起作用
sqlcp = "SELECT * FROM venue WHERE FIND_IN_SET('$venue', id)";
有任何问题请咨询,感谢关注
【问题讨论】:
既然你的$venue
是用户感兴趣的课程id列表,分解成数组,循环查询
"SELECT * FROM venue WHERE id IN ($venue)"
为什么不炸掉它们并使用IN
,field called "venue" containing a comma delimited set of "id"'
AND I have a second table called "venue" which holds the venues of all courses. Each course is a separate row
“一个名为“venue”的字段,其中包含他们感兴趣的培训课程地点的逗号分隔的一组“id”。(例如:18,22,35,41)”。这是一个错误和反模式。为您的数据设置适当的关系结构。这些值应位于子表中的单独行中,并带有返回主客户表的外键。它还将有一个外键返回到场所表,因此总体上将是多对多的关系。那么你的查询就很简单了。
另外,您似乎已经将业务场景中的“场地”和“课程”实体合并为数据库设计中的单个表。如果有人想在 2 个场地举办相同的课程,或者在一个场地举办 2 门课程,这将无法解决 - 这要么是不可能的,要么您最终会复制数据。
【参考方案1】:
现在除非我误解了这个问题:
名为“venue”的字段 [input] 包含逗号分隔的集合
换句话说,我们可以说$result['venue']
就像1,2,3,4
。
然后这一点:
我有第二张桌子,名为“场地”,其中包含所有课程的场地。每门课程都是单独的一行
换句话说,我们可以说id
是场地的主键。
因此,您的输入似乎是分隔列表,并且您的表格具有正确的 ID。为此,我们只需 IN
并提供 ID 列表。
当然,在这种情况下,您可以将它们插入到查询中(ID 不需要在 IN 中使用引号),但这根本不会为您提供任何故障保护。
例如:
//Please don't do this as you can get SQLInjection from the input
$sql = "SELECT * FROM venue WHERE id IN (".$result['venue'].")";
改为执行以下操作:
$venue = implode(',',array_map('intval',array_filter(array_map('trim', explode(',',$result['venue'])))));
$sql = "SELECT * FROM venue WHERE id IN (".$venue.")";
通常我不会连接,但请注意 array_map('intval', ..)
将它们转换为整数。
解释所有对数组的作用(按顺序):
-
由
,
爆炸
修剪空格,例如 ,
逗号空格会留下一个空格
过滤器将删除任何虚假元素,例如,,
空注释0
是其中的一部分
将类型转换为 int
有几个原因。
然后我们再次内爆。
这似乎有点多余,但它清理了用户提供的输入。例如,考虑以下情况:
$v="1,,2 , 4); DROP TABLE users --";
echo "Unsafe:\n";
echo "SELECT * FROM venue WHERE id IN ($v)\n\n";
$venue = implode(',',array_map('intval',array_filter(array_map('trim', explode(',',$v)))));
print_r($venue);
echo "Safer:\n";
echo "SELECT * FROM venue WHERE id IN ($venue)\n\n";
输出
Unsafe:
SELECT * FROM venue WHERE id IN (1,,2 , 4); DROP TABLE users --)
Safer:
SELECT * FROM venue WHERE id IN (1,2,4)
Sandbox
附注多查询注入可能无论如何都不适用于“现代”版本的 php,但这只是一个示例
在性能方面这会更好,因为它可以正确使用场地中的索引。
我认为你过于复杂了。
@Taha Asgari 是正确的,您的论点倒退了。这是一个简单的错误,因为它的目的是在数据库中查找列表中的内容。不是相反,或者至少这是它的常用方式。
一个例子是这样的:
//this is the correct way
SELECT * FROM venue WHERE FIND_IN_SET(1,'1,2,3,4')
//this is the way you have it
SELECT * FROM venue WHERE FIND_IN_SET('1,2,3,4', 1)
供参考FIND_IN_SET
也就是说,在这种情况下我们不需要使用FIND_IN_SET
,因为我们可以只使用IN,这在这种情况下更“合适”。
最后一件事是,如果将这些存储在与客户有关系的单独表中,您可以在 mysql 中完成所有操作。数据库中的 CSV 数据通常效果不佳。您只需要一个包含 2 列的表格。
//table customers_venues
customer_id
venue_id
然后你可以这样查询:
Select
cv.venue
from
customers AS c
JOIN
customers_venues AS cv ON cv.customer_id = c.id
JOIN
venues as v ON cv.venue_id = v.id
但我不知道该说什么LIMIT 1
。
干杯!
【讨论】:
这是一个PHP语法错误,请尝试打开显示错误和错误报告。只需谷歌它就有十亿个如何做到这一点的例子。 另外你是什么意思,I get a blank white screen,
开始或使用我发布的代码之后?因为我在沙箱中测试了该行,请参见上面的链接。【参考方案2】:
我认为你应该这样写代码:
$sqlcp = "SELECT * FROM venue WHERE FIND_IN_SET(id,'$venue')";
【讨论】:
不知道你为什么投了反对票,我个人从未使用过FIND_IN_SET
,但根据documentation,你是对的。也许您不能在第二个参数中添加一列?但是,我在文档中看不到这一点。但是,正如我在回答中解释的那样,一开始就没有必要使用它。
非常感谢,我现在得到了一个结果,不是我所期望的,但我认为这是由于某个地方的拼写错误,就像我说的那样,我已经连续工作了整整三天,并且眼花缭乱,谢谢
你是慈悲的天使,今晚我可以睡觉了,谢谢以上是关于MySQL - 如何选择表中的行,其中 id 值位于另一个表中的逗号分隔字段中?的主要内容,如果未能解决你的问题,请参考以下文章