SQL Query在一列中包含多个值

时间:2010-05-10 03:10:37

标签: sql sql-server-2008

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

Job_Number     User_Assigned     PendingInfo

1              user1             01,02

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

Pending_Num    PendingWord

01             Not Enough Info
02             Not Enough Time

我要做的是查询数据库,以便为我提供所有工作号,用户,pendinginfo和待决理由。我可以突破第一个值,但无法弄清楚如何做第二个。到目前为止我的技能有限:

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

提前致谢

6 个答案:

答案 0 :(得分:5)

如果你的SQL想要单独处理它们,你真的不应该在一列中存储多个项目。在这些情况下你必须执行的“SQL体操”既丑陋又糟糕。

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

然后您的查询将更简单,更快。


但是,如果这不是一个选项,你可以使用上述的SQL体操来做类似的事情:

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

假设您的SQL方言具有字符串搜索功能(在这种情况下为find,但我认为charindex用于SQLServer)。

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


如果无法控制应用程序在该列中放置的内容,我会选择DBA解决方案 - DBA解决方案被定义为DBA必须做的工作来解决他们的不足之处用户: - )。

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

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

这意味着拆分成本仅适用于行插入/更新,而不是_every single select`,从而有效地分摊成本。


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

答案 1 :(得分:5)

我希望你只是维护代码,而不是一个全新的实现。
请考虑使用支持表使用不同的方法,如下所示:

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或子查询轻松查询此表 如果您需要对软件进行复古兼容,则可以添加视图以实现此目标。

答案 2 :(得分:3)

我有一张表:

Events
---------
eventId int
eventTypeIds nvarchar(50)
...

EventTypes
--------------
eventTypeId
Description
...

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

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

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

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

答案 3 :(得分:2)

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

答案 4 :(得分:1)

查看我回答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_NUM一样多的次数。然后,提取字符串的适当部分

答案 5 :(得分:0)

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

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

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