如何在没有循环的情况下将这些行值放在列中?

时间:2013-11-14 17:18:08

标签: sql sql-server-2008 tsql

我有一张这样的表:

My table

我喜欢这样的事情:

My Result Table

以'Property'开头的行将转到Property列。以“Location”开头的行将转到“Location”列,以“error”开头的行将转到“ErrorMessage”列。这里的表包含类似父子的数据。例如,Property 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。

5 个答案:

答案 0 :(得分: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

答案 1 :(得分: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%'

答案 2 :(得分: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);

答案 3 :(得分: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

答案 4 :(得分:0)

您可以获取所有'error %'行并使用columnDesc作为ErrorMessage,然后将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 %'
;