在 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
.
效率更高
我正在写一份报告来展示我们的客户在建造房屋时想要的功能。 我想左连接 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
.