Transpose rows to columns in SQLite

时间:2017-04-06 17:14:18

标签: sqlite

I have data like this:

enter image description here

I am trying to transform it to this (using SQLite). In the desired result, within each id, each start should be on the same row as the chronologically closest end. If an id has a start but no end (like id=4), then the corresponding end, will be empty (as shown below).

enter image description here

I have tried this

select 
    id,
    max( case when start_end = "start" then date end) as start,
    max(case when start_end = "end"   then date end ) as end
from df
group by id

But the result is this, which is wrong because id=5 only have one row, when it should have two:

  id      start        end
1  2 1994-05-01 1996-11-04
2  4 1979-07-18       <NA>
3  5 2010-10-01 2012-10-06

Any help is much appreciated

    CREATE TABLE mytable(
   id        INTEGER  NOT NULL PRIMARY KEY 
  ,start_end VARCHAR(5) NOT NULL
  ,date      DATE  NOT NULL
);
INSERT INTO mytable(id,start_end,date) VALUES (2,'start','1994-05-01');
INSERT INTO mytable(id,start_end,date) VALUES (2,'end','1996-11-04');
INSERT INTO mytable(id,start_end,date) VALUES (4,'start','1979-07-18');
INSERT INTO mytable(id,start_end,date) VALUES (5,'start','2005-02-01');
INSERT INTO mytable(id,start_end,date) VALUES (5,'end','2009-09-17');
INSERT INTO mytable(id,start_end,date) VALUES (5,'start','2010-10-01');
INSERT INTO mytable(id,start_end,date) VALUES (5,'end','2012-10-06');

2 个答案:

答案 0 :(得分:1)

select
  s.id        as id,
  s.date      as 'start',
  min(e.date) as 'end' -- earliest end date from "same id&start"
from
  -- only start dates
  (select id, date
   from intable
   where start_end='start'
   ) as s
left join -- keep the start-only lines
  -- only end dates
  (select id, date
   from intable
   where start_end='end'
   ) as e
on      s.id = e.id
  and s.date < e.date -- not too early
group by s.id, s.date -- "same id&start"
order by s.id, s.date; -- ensure sequence
  • 左连接(保持id&#34; 4&#34的仅启动行);两个动态表,开始日期和结束日期。
  • 使用刚刚高于开始日期的最小结束日期(相同的ID,使用min()group by
  • 按ID排序,然后开始日期。

我在测试表上对此进行了测试,该测试表类似于您的转储,但没有&#34; NOT NULL&#34;并且没有&#34; PRIMARY KEY&#34;。我想这个测试表是无关紧要的;另请说明效果。

注意:
在内部找到id 5的三对日期(匹配end&gt; start的日期),但只有那些以ID的两个不同组合中的每一个转发到最低端(min(end))并开始{{1} }。结束&gt;开始但结束不是最小值的行不会返回。这使得两条线具有所需的起始/结束对。

输出(group by ID, start):

.headers on

更新:纳入@MatBailie的有用评论。

答案 1 :(得分:0)

谢谢!这正是我需要做的,只是做了一些改动:

SELECT
  s.value     AS 'url',
  "AVGDATE"   AS 'fieldname',
  sum(e.value)/count(*) AS 'value'
FROM 
  (SELECT url, value
   FROM quicktag
   WHERE fieldname='NAME'
   ) AS s
LEFT JOIN
  (SELECT url, substr(value,1,4) AS value
   FROM quicktag
   WHERE fieldname='DATE'
   ) AS e
ON      s.url = e.url
WHERE e.value != ""
GROUP BY s.value;

我有一张这样的桌子:

url         fieldname   value    
----------  ----------  ----------
1000052801  NAME        Thomas 
1000052801  DATE        2007
1000131579  NAME        Morten
1000131579  DATE        2005     
1000131929  NAME        Tanja
1000131929  DATE        2014     
1000158449  NAME        Knud    
1000158449  DATE        2007
1000158450  NAME        Thomas    
1000158450  DATE        2003

我需要根据网址作为关键字将NAME和DATE相关联,并生成一个平均DATE按多个NAME字段分组的字段。

所以我的结果如下:

url         fieldname   value      
----------  ----------  ---------- 
Thomas      AVGDATE     2005
Morten      AVGDATE     2005     
Tanja       AVGDATE     2014     
Knud        AVGDATE     2007

不幸的是,我没有足够的帖子来计算我的投票数。