2017-03-27 77 views
4

我必須將表格中的行合併到一行中。 表看起來象下面這樣:如何將數據庫表格行合併到一行中

表名:dbo.Operations

NUMBER | OPERATION_DATE    | STATUS  | WEIGHT_BEFORE | WEIGHT_AFTER 
A1  | 2016-11-10 23:18:59.000  | START  | 3077  | 3077 
A1  | 2016-11-10 23:47:59.000  | END   | 3077  | 2741 
A1  | 2016-11-10 23:48:59.000  | START  | 2741  | 2741 
A1  | 2016-11-10 23:50:59.000  | END   | 2741  | 2510 
B3  | 2016-11-10 23:18:59.000  | START  | 300   | 300 
B3  | 2016-11-10 23:47:59.000  | END   | 290   | 287 

我希望得到的結果:

NUMBER | START_DATE     | END_DATE     | WEIGHT_BEFORE | WEIGHT_AFTER 
A1  | 2016-11-10 23:18:59.000  | 2016-11-10 23:47:59.000  | 3077  | 2741 
A1  | 2016-11-10 23:48:59.000  | 2016-11-10 23:50:59.000  | 2741  | 2510 
B3  | 2016-11-10 23:18:59.000  | 2016-11-10 23:47:59.000  | 300   | 287 

我想選擇的結果。 我應該使用JOIN嗎?我可以在沒有GROUP BY語句的情況下創建查詢嗎?

+0

您的預期結果背後的邏輯是什麼? –

+1

您想要像結果一樣SELECT?還是希望轉換表的模式和數據以使表內容看起來像結果? – mortb

+0

只選擇結果。 – Mateusz

回答

3

使用cross apply()獲得下一個 '端' 爲每個 '開始':

select 
    t.Number 
    , Start_Date = t.Operation_Date 
    , End_date = x.Operation_Date 
    , t.Weight_Before 
    , x.Weight_After 
from dbo.Operations t 
    cross apply (
    select top 1 i.Operation_Date, i.Weight_After 
    from dbo.Operations i 
    where i.Number = t.Number 
     and i.Status = 'End' 
     and i.Operation_Date > t.Operation_Date 
    order by i.Operation_Date asc 
    ) x 
where t.Status = 'start'; 
+0

對於像這樣相當簡單的東西,交叉應用看起來有點沉重嗎? – Matthew

+0

@Mthethew你應該編輯你的答案而不是刪除它。這仍然是一個很好的答案。 – SqlZim

+0

呃,唉,我真的沒有時間,我在工作,只有真正使用我的代表賞金來獲得我需要的答案。 – Matthew

1

我會做這樣的:

SELECT a.number 
    ,a.operation_date AS START_DATE 
    ,b.operation_date AS END_DATE 
    ,a.weight_before 
    ,b.weight_after 
FROM dbo.Operations a 
    ,dbo.Operations b 
WHERE a.STATUS = 'START' 
    AND b.STATUS = 'END' 
    AND a.number = b.number; 

或與更可讀的版本:;-)

SELECT a.number 
    ,a.operation_date AS START_DATE 
    ,b.operation_date AS END_DATE 
    ,a.weight_before 
    ,b.weight_after 
FROM dbo.Operations a 
JOIN dbo.Operations b ON a.number = b.number 
WHERE a.STATUS = 'START' 
    AND b.STATUS = 'END'; 
+1

[踢壞的習慣:使用舊式JOIN - Aaron Bertrand](http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/08/bad-habits-to-kick-using-old-style -joins.aspx) – SqlZim

+0

這沒有考慮到每個'number'的開始和結束的多個實例。例如爲數字'A1'返回4行而不是2行。 – SqlZim

1

儘管答案已被接受,但下面的查詢給出了所需的輸出:

DECLARE @SAMPLEDATA TABLE(NUMBER VARCHAR(10), OPERATION_DATE DATETIME,  STATUS VARCHAR(20), WEIGHT_BEFORE INT, WEIGHT_AFTER INT) 

INSERT INTO @SAMPLEDATA VALUES 
('A1',  '2016-11-10 23:18:59.000'  , 'START'  , 3077  , 3077), 
('A1',   '2016-11-10 23:47:59.000'  , 'END'  , 3077  , 2741), 
('A1',   '2016-11-10 23:48:59.000'  , 'START'  , 2741  , 2741), 
('A1',   '2016-11-10 23:50:59.000'  , 'END'   , 2741  , 2510), 
('B3',   '2016-11-10 23:18:59.000'  , 'START'  , 300   , 300), 
('B3',   '2016-11-10 23:47:59.000'  , 'END'   , 290   , 287) 

;WITH CTE 
AS 
(
    SELECT SNO,NUMBER,OPERATION_DATE,WEIGHT_BEFORE,WEIGHT_AFTER,STATUS FROM  (SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 100))SNO,* FROM @SAMPLEDATA)A 
) 
SELECT NUMBER,OPERATION_DATE [START_DATE], 
(SELECT OPERATION_DATE FROM CTE T2 WHERE T2.SNO=T1.SNO+1)END_DATE, 
WEIGHT_BEFORE, 
(SELECT WEIGHT_AFTER FROM CTE T2 WHERE T2.SNO=T1.SNO+1)WEIGHT_AFTER 
FROM CTE T1 WHERE STATUS='START' 

輸出

---------------------------------------------------------------------- 
--NUMBER START_DATE END_DATE WEIGHT_BEFORE WEIGHT_AFTER 
---------------------------------------------------------------------- 
A1 2016-11-10 23:18:59.000 2016-11-10 23:47:59.000 3077 2741 
A1 2016-11-10 23:48:59.000 2016-11-10 23:50:59.000 2741 2510 
B3 2016-11-10 23:18:59.000 2016-11-10 23:47:59.000 300  287 
---------------------------------------------------------------------- 
0

使在相同的列數和相同的列名(別名)的第一和第二表。並在兩個表選擇語句上使用UNION。

相關問題