在 Varchar 上左连接 INT

Left Join INT on Varchar

我正在写一份报告来展示我们的客户在建造房屋时想要的功能。 我想左连接 2 个表,但是数据的存储方式让我很难进行连接。

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

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

Table 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,两个表的数据都是这样存储的。

正如我在评论中所写,请阅读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 列前后添加了一个逗号。

第一步是去找设计这个table结构的人(即使是你)然后用棍子敲打他们的脑袋。

第 2 步是重新设计 table,这里需要一个 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`
);

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

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.

效率更高