【问题标题】:SQL Query with multiple values in one column一列中有多个值的 SQL 查询
【发布时间】:2016-07-18 07:48:16
【问题描述】:

我一直在桌子上敲打我的头,试图弄清楚这一点。我有一个存储作业信息的表,以及作业未完成的原因。原因有数字、01、02、03等。对于待处理的作业,您可能有两个原因。如果选择两个原因,它们将存储在同一列中,以逗号分隔。这是 JOBID 表中的一个示例:

Job_Number     User_Assigned     PendingInfo

1              user1             01,02

还有一个名为 Pending 的表,用于存储这些值实际表示的内容。 01=没有足够的信息,02=没有足够的时间,03=等待审核。示例:

Pending_Num    PendingWord

01             Not Enough Info
02             Not Enough Time

我要做的是查询数据库以提供所有工作编号、用户、待处理信息和待处理原因。我可以打破第一个值,但不知道如何做第二个。到目前为止我有限的技能:

select Job_number,user_assigned,SUBSTRING(pendinginfo,0,3),pendingword
from jobid,pending
where
    SUBSTRING(pendinginfo,0,3)=pending.pending_num and
    pendinginfo!='00,00' and
    pendinginfo!='NULL'

我希望在这个例子中看到的是:

Job_Number  User_Assigned   PendingInfo   PendingWord       PendingInfo  PendingWord

1           User1           01            Not Enough Info   02           Not Enough Time

提前致谢

【问题讨论】:

  • 是否可以选择更改架构?这种关系实际上应该是映射表或次要原因列。
  • 数据库 101 - 第一个范式 (1NF):每个行/列单元格最多只能包含 一个值。

标签: sql sql-server-2008


【解决方案1】:

如果您的 SQL 想要单独处理它们,您真的不应该在一列中存储多个项目。在这些情况下,您必须执行的“SQL 体操”既是丑陋的 hack,也是性能降低者。

理想的解决方案是将单个项目拆分为单独的列,对于 3NF,如果您真的想要正确地执行此操作,请将这些列作为行移动到单独的表中(但小步骤可能是好吧,如果您确定在短期内永远不会有两个以上的原因)。

那么您的查询将更加简单和快捷。


但是,如果这不是一个选项,您可以使用上述 SQL 体操来执行以下操作:

where find ( ',' |fld| ',', ',02,' ) > 0

假设您的 SQL 方言具有字符串搜索功能(在本例中为 find,但我认为 SQLServer 为 charindex)。

这将确保所有子列都以逗号开头(逗号加字段加逗号)并查找特定的所需值(逗号在两边以确保它是完整的子列匹配)。


如果您不能控制应用程序在该列中放置的内容,我会选择 DBA 解决方案 - DBA 解决方案被定义为 DBA 必须解决其不足之处用户:-)。

在该表中创建两个新列并创建一个插入/更新触发器,该触发器将使用用户放入原始列的两个原因来填充它们。

然后查询这两个 new 列以获取特定值,而不是尝试拆分旧列。

这意味着拆分的成本只发生在行插入/更新上,而不是_every single select`上,从而有效地摊销了成本。


不过,我的答案是重新构建架构。从长远来看,这将是速度、可读查询和可维护性方面的最佳方式。

【讨论】:

  • 是的,重新创建是最好的方法,但目前这不是一个选项。这是我必须处理的情况。抱歉,忘了说这是 MS SQL 2008
  • 然后告诉你的老板这是个坏主意,然后试试charindex 选项。而且,如果表现糟糕,你可以告诉你的老板你是对的,他们是白痴,希望比我通常能做的更机智:-)
  • 我会试试这个 charindex。
【解决方案2】:

我希望您只是维护代码,而不是全新的实现。
请考虑使用不同的方法,使用这样的支持表:

JOBS TABLE
jobID | userID
--------------
1     | user13
2     | user32
3     | user44
--------------

PENDING TABLE
pendingID | pendingText
---------------------------
01        | Not Enough Info
02        | Not Enough Time
---------------------------

JOB_PENDING TABLE
jobID | pendingID
-----------------
1     | 01
1     | 02
2     | 01
3     | 03
3     | 01
-----------------

您可以使用 JOIN 或子查询轻松查询此表。
如果您需要软件的追溯兼容性,您可以添加一个视图来实现此目标。

【讨论】:

    【解决方案3】:

    我有一张这样的桌子:

    Events
    ---------
    eventId int
    eventTypeIds nvarchar(50)
    ...
    
    EventTypes
    --------------
    eventTypeId
    Description
    ...
    

    每个事件可以指定多个事件类型。

    我所做的只是在我的站点代码中编写 2 个过程,而不是 SQL 代码

    1. 一个过程将表字段 (eventTypeIds) 值(如“3,4,15,6”)转换为 ViewState 数组,因此我可以在代码中的任何位置使用它。

    2. 此过程相反,它收集您选中的所有选项并将其转换为

    【讨论】:

      【解决方案4】:

      如果更改架构 是 一个选项(它可能应该是),您不应该在这里实现多对多关系,以便在两个项目之间有一个桥接表吗?这样,您可以将数字及其措辞存储在一个表中,将作业存储在另一个表中,并将“作业失败原因”存储在桥接表中......

      【讨论】:

        【解决方案5】:

        看看我回答的类似问题here

        ;WITH Numbers AS 
        ( 
            SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 0)) AS N
            FROM JobId
        ), 
        Split AS 
        ( 
            SELECT JOB_NUMBER, USER_ASSIGNED, SUBSTRING(PENDING_INFO, Numbers.N, CHARINDEX(',', PENDING_INFO + ',', Numbers.N) - Numbers.N) AS PENDING_NUM
            FROM JobId
            JOIN Numbers ON Numbers.N <= DATALENGTH(PENDING_INFO) + 1 
            AND SUBSTRING(',' + PENDING_INFO, Numbers.N, 1) = ','
        ) 
        SELECT *
        FROM Split JOIN Pending ON Split.PENDING_NUM = Pending.PENDING_NUM
        

        基本思想是每行乘以PENDING_NUMs 的次数。然后,提取字符串的适当部分

        【讨论】:

          【解决方案6】:

          虽然我同意 DBA 的观点,即不要在单个字段中存储多个值,但它是可行的,如下所示,对于应用程序逻辑和一些性能问题是实用的。

          假设您有 10000 个用户组,每个用户组平均有 1000 名成员。您可能希望有一个表 user_groups,其中包含 groupID 和 membersID 等列。您的 membersID 列可以这样填充: (',10,2001,20003,333,4520,') 每个数字都是一个 memberID,都用逗号分隔。在数据的开头和结尾添加逗号。然后您的选择将使用类似 '%,someID,%'。

          如果您无法更改数据 ('01,02,03') 或类似数据,假设您想要包含 01 的行,您仍然可以使用 " select ... LIKE '01,%' OR '%,01' OR '% ,01,%'" 这将确保它在开始、结束或内部匹配,同时避免类似的数字(即:101)。

          【讨论】:

            猜你喜欢
            • 2021-09-12
            • 1970-01-01
            • 1970-01-01
            • 2015-02-21
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多