【问题标题】:Storing IDs as comma separated values将 ID 存储为逗号分隔值
【发布时间】:2012-03-30 14:19:34
【问题描述】:

如何从数据库中选择 ID 存储在 varchar 逗号分隔的所有行。例如,我有一张桌子:

, 7, 9, 11

如何选择具有这些 ID 的行?

【问题讨论】:

  • 您可能需要考虑将这些 ID 拆分到单独的表中。将它们存储为逗号分隔值将是一场噩梦。
  • 性能也是一个问题。这不是您在数据库中存储数据的方式。
  • 它也更容易出错。如果存储整数,结果总是相同的。但是在存储字符串时,搜索“7”将不会产生与“7.0”甚至“7(空格)”相同的结果。 +1 用于规范化表格。

标签: mysql sql


【解决方案1】:

规范化您的数据库。您应该最有可能使用查找表。

【讨论】:

  • 不确定查找表到底是什么意思。
  • 您应该有一个表,其中包含 PK 参考和上面每个单独值的行。 7,9,11 应该作为三个单独的记录在数据库中(在另一个表中)列出
【解决方案2】:

你有两个选择:

  1. 使用函数将字符串拆分为临时表,然后将您选择的表连接到该临时表。
  2. 使用动态 SQL 查询 id in (@variable) 所在的表 --- 如果您选择这种方式,这是一个错误的选择。

【讨论】:

    【解决方案3】:
    select * from table_name where id in (7, 9, 11)
    

    如果您通常在开头有逗号,则需要先将其删除。

    【讨论】:

    • 这行不通 - 他将 ID 作为 CSV 存储在单个列中。
    • 正如所指出的,由于数据的存储方式,这将不起作用。
    【解决方案4】:

    使用 match(column) 对抗('7,9,11')

    这将显示您 id 的所有 varchar 列,其中 7,9,11 在那里。 但是您必须确保您的列具有全文索引。

    【讨论】:

    • 在这种情况下搜索 (9, 7, 11) 会发生什么?
    • 相同的结果,因为 match against 分别匹配每个逗号分隔值。
    【解决方案5】:

    就在昨天,我在这里修复了一个旧应用程序中的一个错误,并看到他们是这样处理它的:

    AND (T.ServiceIDs = '#SegmentID#' OR T.ServiceIDs LIKE '#SegmentID#,%'
                    OR T.ServiceIDs LIKE '%,#SegmentID#,%' OR T.ServiceIDs LIKE '%,#SegmentID#')
    

    我假设您说的是数据库中 ServiceID 的值可能包含 7、9、11 并且变量 SegmentID 是一个或多个值。它在 CFIF 语句中检查 SegmentID 实际上有一个值(由于先前的逻辑会默认它,因此总是如此。

    我个人会按照其他人的建议去做,我会创建一个我一直称为桥接表的东西,它允许您从一个表中获得 0 到多个 PK,这些 PK 与另一个表的 PK 相关。

    几年前我不得不解决这个问题,因为我无法更改表结构,我创建了一个自定义表类型和一组函数,这样我就可以通过 SQL 处理这些值,就好像它们来自一个表一样。该自定义表类型解决方案虽然是特定于 Oracle 的,但如果没有我的一些研究,我不知道如何在 MySQL 中做到这一点。

    【讨论】:

      【解决方案6】:

      查询列表如此困难是有原因的:数据库不是为使用分隔列表而设计的。它们经过优化,可以最好地处理数据行(或数据集)。创建正确的表结构将导致更好的查询性能和更简单的 sql 查询。 (因此,虽然技术上可行,但您应该认真考虑按照 Todd 和其他人的建议对数据库进行规范化。)

      Many-to-many 关系最好用三 (3) 个表来表示。假设您正在销售各种“尺寸”的“小部件”。创建两个代表主要实体的表:

      小部件 (独特的小部件)

      WidgetID | WidgetTitle
      1        | Widget 1
      2        | Widget 2
      ....
      

      尺寸 (唯一尺寸)

      SizeID  | SizeTitle
       7      | X-Small
       8      | Small
       9      | Medium
      10      | Large
      11      | X-Large
      

      然后创建一个联结表,来存储这两个实体之间的关系,即哪些小部件以哪些尺寸可用

      WidgetSize (每个小部件的可用尺寸)

      WidgetID | SizeID
      1        | 7         <== Widget 1  "X-Small"
      1        | 8         <== Widget 1 + "Small"
      2        | 7         <== Widget 2 + "X-Small"
      2        | 9         ....
      2        | 10
      2        | 11
      ....
      

      使用该结构,您可以轻松返回具有任何(或全部)尺寸列表的所有小部件。未经测试,但类似于下面的 sql 的东西应该可以工作。

      • 查找任何尺寸的可用小部件:&lt;cfset listOfSizes = "7,9,11"&gt;

         SELECT w.WidgetID, w.WidgetTitle
         FROM   Widget w 
         WHERE  EXISTS 
               (   SELECT 1 
                   FROM   WidgetSize ws 
                   WHERE  ws.WidgetID = w.WidgetID
                   AND    ws.SizeID IN ( 
                           <cfqueryparam value="#listOfSizeIds#" 
                                  cfsqltype="cf_sql_integer" list="true" > 
                          )
               )
        
      • 查找所有三种尺寸的小部件:&lt;cfset listOfSizes = "7,9,11"&gt;

          SELECT   w.WidgetID, w.WidgetTitle, COUNT(*) AS MatchCount
          FROM     Widget w INNER JOIN WidgetSize ws ON ws.WidgetID = w.WidgetID
          WHERE    ws.SizeID IN ( 
                           <cfqueryparam value="#listOfSizeIds#" 
                                  cfsqltype="cf_sql_integer" list="true" > 
                   )
          GROUP BY w.WidgetID, w.WidgetTitle
          HAVING   MatchCount = 3
        

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-30
        • 2019-12-28
        • 1970-01-01
        • 1970-01-01
        • 2017-06-22
        相关资源
        最近更新 更多