我在SQL Server 2008中有一个包含大约50列的表。这些列中的每一列对应于条形码扫描器;我们在工厂周围散布着各种串口到IP的盒子。收到扫描后,小应用程序会在相关字段中插入日期。
我要做的是对该表中的字段进行比较,而不必手动列出所有字段;理想情况下,我希望能够在表中添加/删除字段,而无需更改在表上运行的SPROCS /脚本。
所以而不是
UPDATE scans
SET completed = 1
WHERE (scanner_1 IS NOT NULL OR scanner_2 IS NOT NULL)
......我正在尝试按照
的方式尝试UPDATE scans
SET completed = 1
WHERE (/* Something to select all columns, maybe with an exclusion */ WHERE fields IS NOT NULL)
我希望我已经解释得这么好了,谢谢你们所有人!
我们有一个列出所有扫描仪和com端口的表,例如
id (PK)
com_port
scanner
然后是一个每个扫描仪都有一个字段的表,该键是在创建记录时自动插入的条形码编号(使用的实例名称有点神秘)
barcode_id (PK)
scanner_1
scanner_2
scanner_3
答案 0 :(得分:1)
我当然同意有关规范化数据库的意见。理想情况下,您应该有一个单独的表,其中外键链接回IP盒和扫描仪。
为了帮助您规范化数据,您可能需要查看UNPIVOT
函数。 E.g。
CREATE TABLE T (ID INT NOT NULL, Scanner1 DATETIME, Scanner2 DATETIME, Scanner3 DATETIME, Scanner4 DATETIME)
INSERT INTO T VALUES
(1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
(2, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL),
(3, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL),
(4, CURRENT_TIMESTAMP, NULL, NULL, NULL),
(5, NULL, NULL, NULL, NULL)
SELECT ID, Scanner, ScannedDate
FROM T
UNPIVOT
( ScannedDate
FOR Scanner IN ([Scanner1], [Scanner2], [Scanner3], [Scanner4])
) UnPvt
ORDER BY ID, Scanner
将返回如下内容:
ID Scanner ScannedDate
-----------------------------------
1 Scanner1 May 31 2012 10:40AM
1 Scanner2 May 31 2012 10:40AM
1 Scanner3 May 31 2012 10:40AM
1 Scanner4 May 31 2012 10:40AM
2 Scanner1 May 31 2012 10:40AM
2 Scanner2 May 31 2012 10:40AM
2 Scanner3 May 31 2012 10:40AM
3 Scanner1 May 31 2012 10:40AM
3 Scanner2 May 31 2012 10:40AM
4 Scanner1 May 31 2012 10:40AM
这仍然存在必须手动写出列的问题,但是你也可以动态创建UNPIVOT语句:
DECLARE @SQL NVARCHAR(MAX) = '',
@Columns NVARCHAR(MAX) = ''
SELECT @Columns = @Columns + ',' + QUOTENAME(Name)
FROM SYS.COLUMNS
WHERE OBJECT_ID = OBJECT_ID(N'T')
AND LEFT(Name, 7) = 'Scanner'
SET @SQL = 'SELECT ID, Scanner, ScannedDate
FROM T
UNPIVOT
( ScannedDate
FOR Scanner IN (' + STUFF(@Columns, 1, 1, '') + ')
) UnPvt
ORDER BY ID, Scanner'
DECLARE @UnPivot TABLE (ID INT, Scanner VARCHAR(50), ScannedDate DATETIME)
INSERT INTO @UnPivot
EXECUTE SP_EXECUTESQL @SQL
SELECT *
FROM @UnPivot
最后,如果您需要将规范化数据转换回平面视图,仍然可以使用PIVOT
函数完成此操作(这假设@SQL和@Columns已经如上定义):
CREATE TABLE ##UnPivot (ID INT, Scanner VARCHAR(50), ScannedDate DATETIME)
INSERT INTO ##UnPivot
EXECUTE SP_EXECUTESQL @SQL
SELECT *
FROM ##UnPivot
SET @SQL = 'SELECT ID' + @Columns + '
FROM ##Unpivot
PIVOT
( MAX(ScannedDate)
FOR Scanner IN (' + STUFF(@Columns, 1, 1, '') + ')
) UnPvt
ORDER BY ID'
EXECUTE SP_EXECUTESQL @SQL
DROP TABLE ##UnPivot
我已经提供了动态取消数据的完整工作示例,然后再次在SQL Fiddle
上再次展开数据修改强>
我刚刚意识到我实际上没有回答原来的问题,我只是建议如何规范化数据。如果不手动输入列,您可以执行以下操作:
DECLARE @SQL NVARCHAR(MAX) = '',
@Columns NVARCHAR(MAX) = ' WHERE 1 = 1 '
SELECT @Columns = @Columns + 'AND ' + QUOTENAME(Name) + ' IS NOT NULL '
FROM SYS.COLUMNS
WHERE OBJECT_ID = OBJECT_ID(N'T')
AND LEFT(Name, 7) = 'Scanner'
SET @SQL = 'UPDATE T SET Completed = 1' + @Columns
EXECUTE SP_EXECUTESQL @SQL
同样,SQL Fiddle
上有一个工作示例