2012-08-09 55 views
2

我有一個應該轉換爲一個目標表的源表。源表包含四個帶有傳感器值的列。目的地表格應包含四行,一行傳感器值,一行傳感器編號 - 源表格中的每一行。換句話說,目標表將有四倍多的行。 (我相信這被稱爲標準化,至少,我認爲未來將會使用更多或更少的或不同的傳感器時更實際)。將一行分割成更多行 - 錶轉換

更多背景信息來解釋。我已經成功地嘗試一個INSERT觸發器,做,對於單行:

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

您可以張貼表DDL語句? – Taryn 2012-08-09 21:34:37

+0

你的問題是創建一個有四行的表格,一行四列。爲什麼不一次性將值插入表中?寫入的代碼量表示爲小問題付出了大量努力。 – 2012-08-09 21:36:52

+1

是的,這是正常化,是的,這是一件好事。如何獲得最終時間戳,原來不夠好?我同意@戈登 - 只是使用規範化的表(禁止_huge_分析需求)。你不需要遊標或'VALUES'子句 - 你可以直接從'SELECT'中插入INSERT,儘管你需要使用四個不同的數據來分隔數據。 – 2012-08-09 22:03:56

回答

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 
3

如果您只需要將具有四列的表格轉換爲單個表格,其中每行表示來自源表格和來自源表格的列的行號,則此處爲示例:

這裏是SQLFiddle

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