我有一个源表应该转换为一个目标表。源表包含四列具有传感器值的列。目标表应包含四行,其中传感器值为单个,传感器编号为一列 - 源表中的每一行。换句话说,目标表的行数将增加四倍。 (我相信这被称为标准化。至少,我认为将来使用更多或更少或不同的传感器将更加实用。)
更多背景资料来解释。我已经成功尝试了一个插入触发器,可以为一行执行此操作:
CREATE TRIGGER dbo.temperatures_to_sensors
ON dbo.Data
AFTER INSERT
AS
BEGIN
DECLARE @line_no TINYINT;
SET @line_no = 2; -- hardwired for the production line
DECLARE @UTC DATETIME;
DECLARE @value1 FLOAT;
DECLARE @value2 FLOAT;
DECLARE @value3 FLOAT;
DECLARE @value4 FLOAT;
SELECT
@UTC = CAST((CAST(LEFT(inserted.UTC, 16) AS FLOAT) - 2415020.5) AS DATETIME),
@value1 = inserted.temperature_1,
@value2 = inserted.temperature_2,
@value3 = inserted.temperature_3,
@value4 = inserted.temperature_4
FROM inserted;
INSERT INTO dbo.line_sensor_values
(UTC, line_no, sensor_no, sensor_value)
VALUES (@UTC, @line_no, 1, @value1),
(@UTC, @line_no, 2, @value2),
(@UTC, @line_no, 3, @value3),
(@UTC, @line_no, 4, @value4);
END;
GO
现在,我想从旧表中初始化目标表一次。之后,触发器将继续填充值。
我不擅长SQL。我试过了:
CREATE PROCEDURE dbo.init_line_sensor_values
AS
BEGIN
DECLARE @line_no TINYINT;
SET @line_no = 2; -- hardwired for the production line
DECLARE @UTC DATETIME;
DECLARE @value1 FLOAT;
DECLARE @value2 FLOAT;
DECLARE @value3 FLOAT;
DECLARE @value4 FLOAT;
INSERT INTO dbo.line_sensor_values
(UTC, line_no, sensor_no, sensor_value)
VALUES (@UTC, @line_no, 1, @value1),
(@UTC, @line_no, 2, @value2),
(@UTC, @line_no, 3, @value3),
(@UTC, @line_no, 4, @value4)
SELECT
@UTC = CAST((CAST(LEFT(t.UTC, 16) AS FLOAT) - 2415020.5) AS DATETIME),
@value1 = t.temperature_1,
@value2 = t.temperature_2,
@value3 = t.temperature_3,
@value4 = t.temperature_4
FROM dbo.Data AS t;
END;
GO
EXECUTE dbo.init_line_sensor_values
GO
...但是
失败了无法将值NULL插入“UTC”列,表'1000574.dbo.line_sensor_values';列不允许空值。 INSERT失败。
很明显SELECT
应该以不同的方式用于提供INSERT
。或者我必须使用循环? (已创建光标且FETCH NEXT...
和WHILE...
)
已更新
源表可以这种方式创建(简化):
CREATE TABLE dbo.Data(
UTC varchar(32) NOT NULL,
temperature_1 float NULL,
temperature_2 float NULL,
temperature_3 float NULL,
temperature_4 float NULL
PRIMARY KEY CLUSTERED
(
UTC ASC
)
GO
目标表是以这种方式创建的:
CREATE TABLE dbo.line_sensor_values (
UTC DATETIME NOT NULL,
line_no TINYINT NOT NULL, -- line number: 1, 2, 3, etc.
sensor_no TINYINT NOT NULL, -- sensor number: 1, 2, 3, etc.
sensor_value float NULL, -- the measured value
PRIMARY KEY CLUSTERED (
UTC ASC,
line_no ASC,
sensor_no ASC
)
)
GO
感谢您的帮助,Petr
答案 0 :(得分:3)
如果您只需将具有四列的表转换为单个表,其中每行表示源表中的行号和源表中的列,那么这是一个示例:
create table fourColumns
(
column1 varchar(50),
column2 varchar(50),
column3 varchar(50),
column4 varchar(50)
)
insert into fourColumns select 'A','B','C','D'
insert into fourColumns select 'E','F','G','H'
;with MyCTE (lineNumber, columnNumber, Result)
as
(
select ROW_NUMBER() OVER(ORDER BY column1 ASC) AS Row, 1, column1
from fourColumns
union all
select ROW_NUMBER() OVER(ORDER BY column2 ASC) AS Row, 2, column2
from fourColumns
union all
select ROW_NUMBER() OVER(ORDER BY column3 ASC) AS Row, 3, column3
from fourColumns
union all
select ROW_NUMBER() OVER(ORDER BY column4 ASC) AS Row, 4, column4
from fourColumns
)
-- add insert here
select lineNumber,
columnNumber,
Result
from MyCTE
order by lineNumber
答案 1 :(得分:1)
INSERT INTO dbo.line_sensor_value
(UTC, line_no, sensor_no, sensor_value)
select UTC, line_no, sensor_no, temperature_1 as sensor_value from dbo.Data
union
select UTC, line_no, sensor_no, temperature_2 as sensor_value from dbo.Data
union
select UTC, line_no, sensor_no, temperature_3 as sensor_value from dbo.Data
union
select UTC, line_no, sensor_no, temperature_4 as sensor_value from dbo.Data