这是直接问题的答案,仅给出 4 个工具列:
SELECT LocID = LocationID, Tool
FROM
(
SELECT LocationID, Tool = 'Tool1' FROM dbo.ToolsSelected WHERE Tool1 = 1
UNION ALL
SELECT LocationID, Tool = 'Tool2' FROM dbo.ToolsSelected WHERE Tool2 = 1
UNION ALL
SELECT LocationID, Tool = 'Tool3' FROM dbo.ToolsSelected WHERE Tool3 = 1
UNION ALL
SELECT LocationID, Tool = 'Tool4' FROM dbo.ToolsSelected WHERE Tool4 = 1
) AS x
ORDER BY LocID, Tool;
使用 40 列,您可以做同样的事情,但需要动态生成:
DECLARE @sql NVARCHAR(MAX);
SET @sql = N'';
SELECT @sql += '
UNION ALL
SELECT LocationID, Tool = ''' + name + '''
FROM dbo.ToolsSelected WHERE ' + name + ' = 1'
FROM sys.columns WHERE [object_id] = OBJECT_ID('dbo.ToolsSelected')
AND name LIKE 'Tool[0-9]%';
SELECT @sql = N'SELECT LocID = LocationID, Tool
FROM
(' + STUFF(@sql, 1, 17, '') + '
) AS x ORDER BY LocID, Tool;';
PRINT @sql;
-- EXEC sp_executesql @sql;
*但是*
将这些存储为单独的列是灾难的根源。因此,当您添加 Tool41、Tool42 等时,您必须更改架构,然后更改通过参数等传递列名和 1/0 的所有代码。为什么不将这些表示为简单的数字,例如
CREATE TABLE dbo.LocationTools
(
LocID NVARCHAR(40),
ToolID INT
);
因此,在上述情况下,您将存储:
LocID Tool
----- ----
AZ 2
AZ 3
NY 1
NY 3
NY 4
现在,当您传入他们选择的复选框时,大概从前端您会收到两个值,例如:
LocID: "NY"
Tools: "Tool1, Tool5, Tool26"
如果这是正确的,那么您可以在用户创建或更改他们的选择时填充表格,首先使用拆分函数来分解由复选框指定的逗号分隔列表:
CREATE FUNCTION dbo.SplitTools
(
@ToolList NVARCHAR(MAX)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT ToolID = y.i.value('(./text())[1]', 'int')
FROM
(
SELECT x = CONVERT(XML,
'<i>' + REPLACE(REPLACE(@List, ',', '</i><i>'), 'Tool', '')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
);
GO
(您忘记告诉我们您使用的是哪个版本的 SQL Server - 如果 2008 或更高版本,您可以使用表值参数作为拆分函数的替代方法。)
然后是处理它的过程:
CREATE PROCEDURE dbo.UpdateLocationTools
@LocID NVARCHAR(40),
@Tools NVARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
-- in case they had previously selected tools
-- that are no longer selected, clear first:
DELETE dbo.LocationTools WHERE LocID = @LocID;
INSERT dbo.LocationTools(LocID, ToolID)
SELECT @LocID, ToolID
FROM dbo.SplitTools(@Tools);
END
GO
现在您可以在不更改架构或代码的情况下添加新工具#s,因为您的复选框列表也可以从您的数据中生成 - 假设您有一个dbo.Tools
表或想要添加一个表。该表还可用于数据完整性目的(您可以在 上放置外键dbo.LocationTools.ToolID
)。
您可以非常简单地生成所需的查询:
SELECT LocID, Tool = 'Tool' + CONVERT(VARCHAR(12), ToolID)
FROM dbo.LocationTools
ORDER BY LocID, ToolID;
没有冗余数据,没有带有难以管理的列的宽表,并且适当的索引甚至可以帮助您有效地使用 Tool3 搜索所有位置......