在Varchar

时间:2016-10-31 12:36:05

标签: sql-server tsql int left-join varchar

我正在编写一份报告,以显示客户在家中建设时需要的功能。 我想离开加入2个表但是数据的存储方式使我很难进行连接。

表1 tbl_Main_Holding有一个名为Requirements的字段,数据存储为varchar,可以有多个值,如1,4,7

1 = "Eco-Build"
4 = "Conservatory"
7 = "Basement"

表2 [tbl_Features]具有字段ID(INT)和描述(Varchar)

SELECT * FROM dbo.tbl_Main_Holding AS rm 
LEFT JOIN [dbo].[tbl_Features] AS f
ON rm.Requirements = f.id

下面的连接不会工作,因为我需要将varchar转换为INT 然而,这不是我的问题我的问题是如何显示已选择多个功能的客户端的结果,这个离开加入的工作方式如何? 我使用SQL Server 2008,两个表的数据都存储起来。 enter image description here enter image description here

2 个答案:

答案 0 :(得分:5)

步骤1是找到设计这个表结构的人(即使是你),然后用棍子将它们绕在头部周围。

第2步是重新设计表,这里需要junction table,而不是将多个整数填充到单个varchar列中。为了在第二步结束时做好准备,你应该再次用棍子击打原设计师。

CREATE TABLE tbl_Main_Holding_Requirements
(
    MainHoldingID INT NOT NULL, --FK TO `tbl_main_Holding`
    FeatureID INT NOT NULL -- FK TO Require `tbl_Features`
);

现在,每个要求代表此表中的一行,而不是列表中的新项,因此您的加入现在很简单:

SELECT  * 
FROM    dbo.tbl_Main_Holding AS rm 
        LEFT JOIN dbo.tbl_Main_Holding_Requirements AS r
            ON r.MainHoldingID = rm.ID
        LEFT JOIN [dbo].[tbl_Features] AS f
            ON f.ID = r.FeatureID;

如果您需要将其重新添加到逗号分隔列表中,则可以在表示层或SQL-Server's XML Extensions中执行此操作:

SELECT  *,
        Features = STUFF(f.Features.value('.', 'NVARCHAR(MAX)'), 1, 1, '')
FROM    dbo.tbl_Main_Holding AS rm 
        OUTER APPLY
        (   SELECT  CONCAT(',', f.Description)
            FROM    dbo.tbl_Main_Holding_Requirements AS r
                    INNER JOIN [dbo].[tbl_Features] AS f
                        ON f.ID = r.FeatureID
            WHERE   r.MainHoldingID = rm.ID
            FOR XML PATH(''), TYPE
        ) f (Features);

如果无法执行第二步,那么您可以使用LIKE

解决此问题
SELECT  * 
FROM    dbo.tbl_Main_Holding AS rm 
        LEFT JOIN [dbo].[tbl_Features] AS f
            ON ',' + rm.Requirements + ',' LIKE '%,' + CONVERT(VARCHAR(10), f.ID) + ',%';

再一次,如果需要将功能缩减回单行,那么您可以再次使用XML扩展:

SELECT  *,
        Features = STUFF(f.Features.value('.', 'NVARCHAR(MAX)'), 1, 1, '')
FROM    dbo.tbl_Main_Holding AS rm 
        OUTER APPLY
        (   SELECT  CONCAT(',', f.Description)
            FROM    [dbo].[tbl_Features] AS f
            WHERE   ',' + rm.Requirements + ',' LIKE '%,' + CONVERT(VARCHAR(10), f.ID) + ',%'
            FOR XML PATH(''), TYPE
        ) f (Features);

另一种选择是使用某种Split function将逗号分隔值拆分为一个列表,但正如本文中的测试所示,如果您不需要从列表中访问各个值,那么使用LIKE更有效率。

答案 1 :(得分:1)

正如我在评论中所写,请阅读Is storing a delimited list in a database column really that bad?
你真的应该规范化你的数据库以避免这些事情。

现在,假设您无法更改数据库架构,可以使用like的简单技巧:

SELECT * FROM dbo.tbl_Main_Holding AS rm 
LEFT JOIN [dbo].[tbl_Features] AS f
ON ',' + rm.Requirements +',' LIKE '%,' + CAST(f.id as varchar(10)) + ',%'

请注意,我已在rm.Requirements列之前和之后以及f.id列之前和之后添加了逗号。