2013-11-14 82 views
1

我有一個表是這樣的:如何將這些行值放到沒有循環的列上?

My table

我喜歡得到這樣的:

My Result Table

該行以「住宅」會去屬性列。以'Location'開頭的行將轉到'Location'列,以'error'開頭的行將轉到'ErrorMessage'列。這裏的表格包含像父子一樣的數據。例如,屬性X的位置'abc'有兩個錯誤'1234'和'5678'。

根據迄今爲止的評論,我添加了一些更多的信息。

Aaron Bertrand問: Q1.你可以絕對依賴rowid是連續的嗎?

A1.Rowid依次遞增,但並不總是按照1的相同順序。

讓我們看一個例子。屬性X從rowid = 1開始,屬性Y在8.所有屬性X將在rowid 1到7之間。如果我們轉到另一個級別,則位置abc從2開始,'def'從5開始。位置'abc的所有錯誤'將在rowid 3到4之間。

Q2。是否只有一組數據適用於任何位置/房產組合?或者有可能第15行再次是屬性X,第16行是屬性abc,等等。

A2。 Property-Location組合只有一組數據。所以如果你發現第2行的屬性X - 位置abc,你稍後會在桌子上找到它。

更多信息:這裏的例子只有有限的行數。實際的表格比這更多的行。

到目前爲止,我已經使用WHILE循環獲得了我的結果。我只是想知道是否有任何其他的方式做到這一點,而不經過逐行。我正在使用SQL 2008 R2。

+0

這是一個可怕的數據庫設計。如果你把它分成3個故事:財產,位置和錯誤 - 那麼這至少是一個好的開始 - 那麼你不需要對無關的數據做任何可怕的旋轉 – mp3ferret

+0

Egads,你爲什麼要以這種方式存儲數據第一個地方?根據什麼將這些信息捆綁在一起?事實上,rowid x上的所有內容都屬於上次在rowid

+0

該表格是由第三方提供的文本文件導入的。它不是任何數據庫的一部分。客戶希望從這個文本文件的數據獲得一個數據透視。我的想法是將數據組織成我描述的格式,然後客戶端可以用它做任何事情。 – ahmjt

回答

1

這可以在1個查詢來完成。首先將數據分成三部分(屬性,位置和錯誤)並確定父母的ID。最後,使用正則加入到創建結果:

with P as (
    select ID, ColumnDesc 
    from MyTable P 
    where columnDesc like 'Property %' 
), 
L as (
    select ID, ColumnDesc, (Select MAX(P.id) from P where P.ID<L.ID) as ParentID 
    from MyTable L 
    where columnDesc like 'Location %' 
), 
E as (
    select ID, ColumnDesc, (Select MAX(L.id) from L where L.ID<E.ID) as ParentID 
    from MyTable E 
    where columnDesc like 'error %' 
) 
select 
    P.ColumnDesc as Property, 
    L.ColumnDesc as Location, 
    E.ColumnDesc as Error 
FROM p 
JOIN L ON (L.ParentId = P.ID) 
JOIN E ON (E.ParentID = L.ID) 
ORDER BY P.ID, L.ID, E.ID 
+0

謝謝@ user2970362。這是做的。以防萬一你對這個解決方案的時間感興趣,而對WHILE循環,這是2秒vs 1分22秒!做得好! – ahmjt

0
with ds as (
select 1 as rowid, 'Property X' as columnDesc 
union 
select 2 as rowid, 'Location abc' 
union 
select 3 as rowid, 'error 1234' 
union 
select 3 as rowid, 'error 3456' 
union 
select 4 as rowid, 'Property Y' 
union 
select 5 as rowid, 'Location abc' 
union 
select 6 as rowid, 'error 1234' 
union 
select 7 as rowid, 'Location def' 
union 
select 8 as rowid, 'error 12' 


) 

, 

rnProperty as (
select row_number() over (order by rowid) as rn , * from ds 
where 
columnDesc like 'Property%'), 

rnLocation as (
select row_number() over (order by rowid) as rn , * from ds 
where 
columnDesc like 'Location%') 



select 
rn.columnDesc, rnL.columnDesc, ds2.columnDesc 

from rnProperty rn 
left join rnProperty rn2 on rn2.rn = rn.rn + 1 
left join rnLocation rnL on rnL.rowid > rn.rowid and rnL.rowid < isnull(rn2.rowId,100000) 
left join rnLocation rnL2 on rnL2.rn = rnL.rn + 1 
left join ds ds2 on ds2.rowid > rnL.rowid and ds2.rowid < isnull(rnL2.rowid,1000000) and ds2.columnDesc like 'error%' 
+0

感謝您的回覆。在這個問題中,我沒有給出實際的數據,出於數據安全的原因。實際的表格包含大約100000行。這就是爲什麼儘管我已經使用WHILE循環完成它,但我很好奇它是否可以以更好的方式完成。 – ahmjt

0

在我看來有趣的問題。這是Oracle的一個解決方案。我認爲這是迄今發佈的最短的一個,只是使用帶有兩個子查詢的單個查詢。

WITH data1 AS 
(
    SELECT 1 AS id,'Property X' AS columnDesc FROM DUAL 
    UNION SELECT 2 AS id,'Location abc' FROM DUAL 
    UNION SELECT 3 AS id,'error 1234' FROM DUAL 
    UNION SELECT 4 AS id,'error 3456' FROM DUAL 
    UNION SELECT 5 AS id,'Property Y' FROM DUAL 
    UNION SELECT 6 AS id,'Location abc' FROM DUAL 
    UNION SELECT 7 AS id,'error 1234' FROM DUAL 
    UNION SELECT 8 AS id,'Location def' FROM DUAL 
    UNION SELECT 9 AS id,'error 12'FROM DUAL 
) 
SELECT d2.columnDesc,d3.columnDesc,d.columnDesc 
FROM data1 d, data1 d2, data1 d3 
WHERE d.columnDesc NOT LIKE 'Property%' 
AND d.columnDesc NOT LIKE 'Location%' 
AND d2.id < d.id 
AND d2.id = (SELECT max(id) FROM data1 
      WHERE columnDesc LIKE 'Property%' AND id < d.id) 
AND d3.id < d.id 
AND d3.id = (SELECT max(id) FROM data1 
      WHERE columnDesc LIKE 'Location%' AND id < d.id); 
0

TSQL

WITH 
source AS 
(
    SELECT 1 AS id,'Property X' AS columnDesc 
    UNION ALL SELECT 2 AS id,'Location abc' 
    UNION ALL SELECT 3 AS id,'error 1234' 
    UNION ALL SELECT 4 AS id,'error 3456' 
    UNION ALL SELECT 5 AS id, 'Location def' 
    UNION ALL SELECT 6 AS id,'error 1234' 
    UNION ALL SELECT 7 AS id,'error 3456' 
    UNION ALL SELECT 8 AS id,'Property Y' 
    UNION ALL SELECT 9 AS id,'Location ab' 
    UNION ALL SELECT 10 AS id,'error 12' 
    UNION ALL SELECT 11 AS id,'error 56' 
    UNION ALL SELECT 12 AS id,'Location de' 
    UNION ALL SELECT 13 AS id,'error 12' 
    UNION ALL SELECT 14 AS id,'error 56' 
), 
maxid AS 
(
    SELECT MAX(id) as maxid FROM source 
), 
properties AS 
(
    SELECT id, columnDesc FROM source WHERE columnDesc like 'Property%' 
), 
propertiesPlus AS 
(
    SELECT id, columnDesc, 
    isnull((SELECT MIN(p2.id) FROM properties p2 WHERE p1.id < p2.id), 
    (SELECT maxid FROM maxid)) as nextid 
    FROM properties p1 
), 
locations AS 
(
    SELECT id, columnDesc FROM source WHERE columnDesc like 'Location%' 
), 
locationsPlus AS 
(
    SELECT id, columnDesc, 
    isnull((SELECT MIN(l2.id) FROM locations l2 WHERE l1.id < l2.id), 
    (SELECT maxid FROM maxid)) as nextid 
    FROM locations l1 
), 
errors AS 
(
    SELECT id, columnDesc FROM source WHERE columnDesc like 'error%' 
) 
SELECT p.columnDesc as Property, l.columnDesc as Location, e.columnDesc as Error 
FROM propertiesPlus p 
    JOIN locationsPlus l ON l.id BETWEEN p.id and p.nextid 
    JOIN errors e ON e.id BETWEEN l.id AND l.nextid 
0

你可以得到所有的'error %'行和使用columnDescErrorMessage,然後計算Property作爲最新columnDesc給定的行之前和匹配的面具'Property %',同樣的Location。這裏是我在說的查詢:

SELECT 
    Property  = (SELECT TOP (1) columnDesc 
        FROM atable 
        WHERE rowid < main.rowid AND columnDesc LIKE 'Property %' 
        ORDER BY rowid DESC), 
    Location  = (SELECT TOP (1) columnDesc 
        FROM atable 
        WHERE rowid < main.rowid AND columnDesc LIKE 'Location %' 
        ORDER BY rowid DESC), 
    ErrorMessage = columnDesc 
FROM atable AS main 
WHERE columnDesc LIKE 'error %' 
; 
相關問題