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)" 为什么不炸掉它们并使用INfield 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 值位于另一个表中的逗号分隔字段中?的主要内容,如果未能解决你的问题,请参考以下文章

如何只选择第二个表中的行?

Mysql:从一个表中选择不在另一个表中的行

如何计算 MySQL 表中的行数(PHP PDO)

如何删除EXCEL表中的大量数据行,要删除的行数大概8万

MySQL - 如何更改表中的行顺序

如何使用填充旧表中的行的动态数据动态更新新MySQL表中的行?