2012-08-15 57 views
0

我有一個簡單的查詢返回以下行:合併行的列在SQL Server

當前行:

Empl ECode DCode  LCode  Earn Dedn Liab 
==== ==== =====  =====  ==== ==== ==== 
123  PerHr Null  Null  13  0  0 
123  Null Union  Null  0  10  0 
123  Null Per   Null  0  20  0 
123  Null Null  MyHealth 0  0  5 
123  Null Null  401   0  0  10 
123  Null Null  Train  0  0  15 
123  Null Null  CAFTA  0  0  20 

不過,我需要看到上面列如下:

Empl ECode DCode LCode  Earn Dedn Liab 
==== ==== ===== =====  ==== ==== ==== 
123  PerHr Union MyHealth 13  10  5 
123  Null Per  401   0  20  10 
123  Null Null Train  0  0  15 
123  Null Null CAFTA  0  0  20 

它更像合併後續行到前面的行哪裏有空白點遇到EarnCodeDednCode & LiabCode。其實我想看到的是把所有東西捲起來放在前面的行上。

在甲骨文,我們有這個LAST_VALUE函數,我們可以使用,但在這種情況下,我根本無法弄清楚如何處理這個。

在上面的例子中,ECode的總和值列是EarnDCodeDedn,和LCodeLiab是;請注意,無論何時ECode,DCodeLCode不爲空,Earn,DednLiab列中都有相應的值。

順便說一下,我們正在使用SQL Server 2008 R2。

希望得到您的建議,謝謝。

+1

規則究竟是什麼,什麼時候合併,何時不合適? – Hogan 2012-08-15 03:04:29

+0

我也想看看你的要求。 – 2012-08-15 03:06:51

+0

實際上,唯一的要求是「壓縮」所有代碼,以便儘可能佔用一行,並附帶它的彙總值。在上面的例子中,ECode PerHr是第一行,並且DCode和LCode都沒有;然而,在第二行中,DCode有一個聯盟代碼,這個聯盟代碼會隨着它的Dedn sum而向上移動,佔用null DCode。 LCode MyHealth將移動到第一排佔用空置的LCode。所以基本上,壓縮所有的代碼佔據先前的行,無論ECode,DCode和LCode是否爲空。 – T2C 2012-08-15 03:33:40

回答

1

這基本上是同樣的技術Tango_Guy做,但沒有臨時表,並作出了明確的排序。因爲每個Empl的行數是< =已經存在的行數,所以我不需要爲最左邊的表格創建一個虛擬表格,只是將基礎數據過濾到3個代碼中匹配的位置。此外,我審查了你的討論,並且Earn和ECode一起移動。事實上非零在沒有ECODE實際上已丟失列賺取(這是一個約束一個很好的例子 - 非零贏取時,不允許ECODE爲NULL):

http://sqlfiddle.com/#!3/7bd04/3

CREATE TABLE data(ID INT IDENTITY NOT NULL, 
        Empl VARCHAR(3), 
        ECode VARCHAR(8), 
        DCode VARCHAR(8), 
        LCode VARCHAR(8), 
        Earn INT NOT NULL, 
        Dedn INT NOT NULL, 
        Liab INT NOT NULL) ; 

INSERT INTO data (Empl, ECode, DCode, LCode, Earn, Dedn, Liab) 
VALUES ('123', 'PerHr', NULL, NULL, 13, 0, 0), 
     ('123', NULL, 'Union', NULL, 0, 10, 0), 
     ('123', NULL, 'Per', NULL, 0, 20, 0), 
     ('123', NULL, NULL, 'MyHealth', 0, 0, 5), 
     ('123', NULL, NULL, '401', 0, 0, 10), 
     ('123', NULL, NULL, 'Train', 0, 0, 15), 
     ('123', NULL, NULL, 'CAFTA', 0, 0, 20); 

WITH basedata AS (
    SELECT *, ROW_NUMBER() OVER(ORDER BY ID) AS OrigSort, ROW_NUMBER() OVER(PARTITION BY Empl ORDER BY ID) AS EmplSort 
    FROM data 
), 
E AS (
    SELECT Empl, ECode, Earn, ROW_NUMBER() OVER(PARTITION BY Empl ORDER BY OrigSort) AS EmplSort 
    FROM basedata 
    WHERE ECode IS NOT NULL 
), 
D AS (
    SELECT Empl, DCode, Dedn, ROW_NUMBER() OVER(PARTITION BY Empl ORDER BY OrigSort) AS EmplSort 
    FROM basedata 
    WHERE DCode IS NOT NULL 
), 
L AS (
    SELECT Empl, LCode, Liab, ROW_NUMBER() OVER(PARTITION BY Empl ORDER BY OrigSort) AS EmplSort 
    FROM basedata 
    WHERE LCode IS NOT NULL 
) 
SELECT basedata.Empl, E.ECode, D.Dcode, L.LCode, E.Earn, D.Dedn, L.Liab 
FROM basedata 
LEFT JOIN E 
    ON E.Empl = basedata.Empl AND E.EmplSort = basedata.EmplSort 
LEFT JOIN D 
    ON D.Empl = basedata.Empl AND D.EmplSort = basedata.EmplSort 
LEFT JOIN L 
    ON L.Empl = basedata.Empl AND L.EmplSort = basedata.EmplSort 
WHERE E.ECode IS NOT NULL OR D.DCode IS NOT NULL OR L.LCode IS NOT NULL 
ORDER BY basedata.Empl, basedata.EmplSort 
+0

它工作完美!只是一些小的調整,以適應我們目前的存儲過程,並讓我們的薪酬報告工作。當他們遇到類似的情況時,也許其他人會發現這些代碼作爲基礎。榮獲Cade和Tango_Guy提供算法! – T2C 2012-08-16 02:34:33

0

不知道這是你需要什麼,但你嘗試過coalesc

SELECT Name, Class, Color, ProductNumber, 
COALESCE(Class, Color, ProductNumber) AS FirstNotNull 
FROM Production.Product ; 
+0

這是一個來自這裏的示例http://msdn.microsoft.com/en-us/library/ms190349.aspx – 2012-08-15 03:58:21

+0

Coalesce水平地(跨列)組合東西......他希望跨行執行此操作。 – 2012-08-15 04:03:45

+0

Tango_Guy是正確的;這需要跨行進行,通過推高所有較低的行來佔用前面行中的任何空ECode,DCode和LCode,如示例所示。 – T2C 2012-08-15 04:07:43

0

我有一個解決方案,但它是非常缺憾。如果有人有更好的東西,那會很棒。

然而,算法:

1)獲取rownumbers在列
2值的每一個不同的列表)加入基於ROWNUMBER

實施例中的所有列:

select Distinct ECode into #Ecode  from source_table order by rowid; 
select Distinct DCode into #Dcode  from source_table order by rowid; 
select Distinct LCode into #Lcode  from source_table order by rowid; 
select Distinct Earn into #Earn from source_table order by rowid; 
select Distinct Dedn into #Dedn from source_table order by rowid; 
select Distinct Liab into #Liab from source_table order by rowid; 

select b.ECode, c.DCode, d.LCode, e.Earn, f.Dedn, g.Liab 
from source_table a -- Note: a source for row numbers that will be >= the below 
left outer join #Ecode b on a.rowid = b.rowid 
left outer join #DCode c on a.rowid = c.rowid 
left outer join #LCode d on a.rowid = d.rowid 
left outer join #Earn e on a.rowid = e.rowid 
left outer join #Dedn f on a.rowid = f.rowid 
left outer join #Liab g on a.rowid = g.rowid 
where 
    b.ecode is not null or 
    c.dcode is not null or 
    d.lcode is not null or 
    e.earn is not null or 
    f.dedn is not null or 
    g.liab is not null; 

我不包括Empl,因爲我不知道你希望它扮演什麼角色。如果這對於一個給定的Empl來說都是如此,那麼你可以添加它,加入它,並通過它。

我不喜歡這個解決方案,所以希望別人能拿出更優雅的東西。

最佳, 大衛

+0

這是一個很好的解決方案;我與Cade的即興算法一起量身定製了代碼,並使用表變量將它放入存儲過程中。它工作得很好。謝謝! – T2C 2012-08-16 02:28:31