【问题标题】:MySQL - How to select rows in a table where id value is in a comma delimited field in another table?MySQL - 如何选择表中的行,其中 id 值位于另一个表中的逗号分隔字段中?
【发布时间】: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 门课程,这将无法解决 - 这要么是不可能的,要么您最终会复制数据。

标签: php mysql select comma delimited


【解决方案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', ..) 将它们转换为整数。

解释所有对数组的作用(按顺序):

  1. , 爆炸
  2. 修剪空格,例如 , 逗号空格会留下一个空格
  3. 过滤器将删除任何虚假元素,例如,,空注释0是其中的一部分
  4. 将类型转换为 int 有几个原因。
  5. 然后我们再次内爆。

这似乎有点多余,但它清理了用户提供的输入。例如,考虑以下情况:

 $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,你是对的。也许您不能在第二个参数中添加一列?但是,我在文档中看不到这一点。但是,正如我在回答中解释的那样,一开始就没有必要使用它。
  • 非常感谢,我现在得到了一个结果,不是我所期望的,但我认为这是由于某个地方的拼写错误,就像我说的那样,我已经连续工作了整整三天,并且眼花缭乱,谢谢
  • 你是慈悲的天使,今晚我可以睡觉了,谢谢
猜你喜欢
  • 1970-01-01
  • 2012-03-20
  • 2021-12-11
  • 2017-05-12
  • 2020-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-01
相关资源
最近更新 更多