2009-08-06 5 views
25

나는 하나의 쿼리에서 모든 과목에 대해받는 학생들과 마크를 보여주는 테이블을 얻고 싶습니다.SQLite의 피벗

이 내 테이블 구조입니다 :

테이블 : markdetails

## studid ## ## subjectid ## ## marks ## 
    A1   3    50 
    A1   4    60 
    A1   5    70 
    B1   3    60 
    B1   4    80 
    C1   5    95 

테이블 : student info

실제 구조 : 나는 다음과 같이 설정 결과를 원하는

## studid ## ## name ## 
     A1   Raam 
     B1   Vivek 
     c1   Alex 

:

테이블 : Student Info

## studid ## ## name## ## subjectid_3 ## ## subjectid_4 ## ## subjectid_5 ## 
     A1  Raam  50    60     70 
     B1  Vivek  60    80    null 
     c1  Alex  null    null    95 

가 어떻게 SQLite는이 작업을 수행 할 수 있습니까?

답변

23

먼저 당신이 임시 테이블에 현재 테이블을 변경해야 다음

alter table student_info rename to student_name 

, 당신은 student_info을 다시 할 것입니다 : 다음

create table student_info add column (
    stuid VARCHAR(5) PRIMARY KEY, 
    name VARCHAR(255), 
    subjectid_3 INTEGER, 
    subjectid_4 INTEGER, 
    subjectid_5 INTEGER 
) 

student_info 웁니다

insert into student_info 
select 
    u.stuid, 
    u.name, 
    s3.marks as subjectid_3, 
    s4.marks as subjectid_4, 
    s5.marks as subjectid_5 
from 
    student_temp u 
    left outer join markdetails s3 on 
     u.stuid = s3.stuid 
     and s3.subjectid = 3 
    left outer join markdetails s4 on 
     u.stuid = s4.stuid 
     and s4.subjectid = 4 
    left outer join markdetails s5 on 
     u.stuid = s5.stuid 
     and s5.subjectid = 5 

이제 임시 테이블을 삭제하십시오.

drop table student_temp 

그러면 테이블을 빠르게 업데이트 할 수 있습니다.

SQLite는 pivot 함수가 없으므로 가장 좋은 방법은 일부 왼쪽 조인을 하드 코딩하는 것입니다. left join은 조인 조건의 모든 행을 일치시키고 두 번째 테이블에 대한 조인 조건을 충족시키지 않는 첫 번째 또는 왼쪽 테이블의 모든 행에 대해 null을 리턴합니다.

+0

덕분에 나는 테이블에 배치의 콘텐츠 및 열을 수정할 내 질문을 못 생각했다고 생각해. 나는 테이블을 바꾸고 싶다. – arams

+0

에릭 감사 ... 그것은 잘 동작합니다. – arams

+0

@arams : 환상적이며 듣기 좋습니다! 제발 당신의 문제가 해결되면 upvote/답변으로 표시! – Eric

14

작성자가 SQL을 사용하여 스키마를 작성하기에 충분하지 않으므로 @Eric의 솔루션을 사용하고자하는 모든이를위한 것입니다.

create table markdetails (studid, subjectid, marks); 
create table student_info (studid, name); 

insert into markdetails values('A1', 3, 50); 
insert into markdetails values('A1', 4, 60); 
insert into markdetails values('A1', 5, 70); 
insert into markdetails values('B1', 3, 60); 
insert into markdetails values('B1', 4, 80); 
insert into markdetails values('C1', 5, 95); 

insert into student_info values('A1', 'Raam'); 
insert into student_info values('B1', 'Vivek'); 
insert into student_info values('C1', 'Alex'); 

여기 group by으로 case를 이용한 다른 해결책이다.

select 
    u.stuid, 
    u.name, 
    s3.marks as subjectid_3, 
    s4.marks as subjectid_4, 
    s5.marks as subjectid_5 
from 
    student_temp u 
    left outer join markdetails s3 on 
     u.stuid = s3.stuid 
     and s3.subjectid = 3 
    left outer join markdetails s4 on 
     u.stuid = s4.stuid 
     and s4.subjectid = 4 
    left outer join markdetails s5 on 
     u.stuid = s5.stuid 
     and s5.subjectid = 5 
; 

많은 양의 데이터가있을 때 하나가 더 나은 실적을 것이다 볼 흥미로운 일이 될 것이다 :

select 
    si.studid, 
    si.name, 
    sum(case when md.subjectid = 3 then md.marks end) subjectid_3, 
    sum(case when md.subjectid = 4 then md.marks end) subjectid_4, 
    sum(case when md.subjectid = 5 then md.marks end) subjectid_5 
from student_info si 
join markdetails md on 
     md.studid = si.studid 
group by si.studid, si.name 
; 

비교를 위해, 여기에 에릭의 솔루션 @에서 같은 select 문이다.

+7

약 150,000 개의 행이있는 테이블에서이를 테스트 할 수있는 기회가있었습니다. 하나의 복잡한 점은 미리 열의 수를 모른다는 것입니다. 그래서 필요한 열의 수를 결정하기 위해 약간의 사전 처리를해야합니다. 또한 모든 행에 같은 수의 데이터가있는 것은 아닙니다. 외부 조인 방법을 사용하면 내 PC가 50 초가 걸렸습니다. 방법이있는 경우 15 초가 걸렸습니다. reshape2와 plyr (R을 사용하여 sqlite를 실행)의 조합을 사용하면 약 1,040 초가 걸립니다. 그러나 마일리지는 다를 수 있습니다. – Chow

+0

@Chow, 완전히 동의합니다. 내 테이블에는 280,000 개의 행이 있으며 20 초가 걸렸습니다. 이 답변은 맨 위에 있어야합니다. – nikpod

6

위대한 부록! 낮은 노력과 시스템로드로 비슷한 문제를 해결할 수있었습니다.I는 "정규화"10 분 타임 스탬프 오전 SUBSTR() 명령을 사용

sqlite> .headers on 
sqlite> .mode column 
sqlite> select * from temps where timestamp > '2014-02-24 22:00:00'; 

Timestamp   sensorID   temperature 
------------------- --------------- ----------- 
2014-02-24 22:00:02 28-0000055f3f10 19.937 
2014-02-24 22:00:03 28-0000055f0378 19.687 
2014-02-24 22:00:04 28-0000055eb504 19.937 
2014-02-24 22:00:05 28-0000055f92f2 19.937 
2014-02-24 22:00:06 28-0000055eef29 19.812 
2014-02-24 22:00:07 28-0000055f7619 19.625 
2014-02-24 22:00:08 28-0000055edf01 19.687 
2014-02-24 22:00:09 28-0000055effda 19.812 
2014-02-24 22:00:09 28-0000055e5ef2 19.875 
2014-02-24 22:00:10 28-0000055f1b83 19.812 
2014-02-24 22:10:03 28-0000055f3f10 19.937 
2014-02-24 22:10:04 28-0000055f0378 19.75 
2014-02-24 22:10:04 28-0000055eb504 19.937 
2014-02-24 22:10:05 28-0000055f92f2 19.937 

:

CREATE TABLE temps (Timestamp DATETIME, sensorID TEXT, temperature NUMERIC); 

예컨대 다음과 같다 : I는 1wire 인터페이스 DS18B20 온도 센서 데이터를 획득하기 위해 라즈베리 파이 사용하고 미문. sensorID가 '센서'

CREATE VIEW [TempsSlot10min] AS 
SELECT SUBSTR(datetime(timestamp),1,15)||'0:00' AS TimeSlot, 
SensorName, 
temperature FROM 
temps JOIN sensors USING (sensorID, sensorID); 

예를 룩업 테이블을 이용하여 SensorName로 변경된 가입으로 :

sqlite> select * from TempsSlot10min where timeslot >= '2014-02-24 22:00:00'; 

TimeSlot    SensorName temperature 
------------------- ---------- ----------- 
2014-02-24 22:00:00 T1   19.937 
2014-02-24 22:00:00 T2   19.687 
2014-02-24 22:00:00 T3   19.937 
2014-02-24 22:00:00 T4   19.937 
2014-02-24 22:00:00 T5   19.812 
2014-02-24 22:00:00 T6   19.625 
2014-02-24 22:00:00 T10   19.687 
2014-02-24 22:00:00 T9   19.812 
2014-02-24 22:00:00 T8   19.875 
2014-02-24 22:00:00 T7   19.812 
2014-02-24 22:10:00 T1   19.937 
2014-02-24 22:10:00 T2   19.75 
2014-02-24 22:10:00 T3   19.937 
2014-02-24 22:10:00 T4   19.937 
2014-02-24 22:10:00 T5   19.875 

이제 마법은 상술 CASE 명령으로 일어난다.

CREATE VIEW [PivotTemps10min] AS 
SELECT TimeSlot, 
AVG(CASE WHEN sensorName = 'T1' THEN temperature END) AS T1, 
AVG(CASE WHEN sensorName = 'T2' THEN temperature END) AS T2, 
... 
AVG(CASE WHEN sensorName = 'T10' THEN temperature END) AS T10 
FROM TempsSlot10min 
GROUP BY TimeSlot; 

예 :

select * from PivotTemps10min where timeslot >= '2014-02-24 22:00:00'; 

TimeSlot    T1   T2    T10 
------------------- ---------- ---------- ... ---------- 
2014-02-24 22:00:00 19.937  19.687   19.687 
2014-02-24 22:10:00 19.937  19.75   19.687 
2014-02-24 22:20:00 19.937  19.75   19.687 
2014-02-24 22:30:00 20.125  19.937   19.937 
2014-02-24 22:40:00 20.187  20.0   19.937 
2014-02-24 22:50:00 20.25  20.062   20.062 
2014-02-24 23:00:00 20.25  20.062   20.062 

여기 남은 유일한 문제는 sensorName 'T1'... 'T10'은 이제 검색 테이블에서 촬영 VIEW [PivotTemps10min] 및하지에 하드 코딩되어있다 .

그럼에도 불구하고,이 대담한 답변에 대해 매우 감사드립니다.

+0

이것은 내가 실제로 찾고 있던 것입니다. 고맙습니다. –

+0

SQL을 사용하는 많은 수의 IoT 애호가가이를 언급 할 것입니다. 내 응용 프로그램은 거의 똑같습니다. – nikpod

0

같은 필드에 아이들을 함께 번들로 묶을 필요가 있다면 group_concat은 친구입니다.

이 스레드에서 사이먼 군침을

거대한 감사 : 에릭 ...을 querry가 student.but에 대한 전체 세부 사항을 얻기 위해 잘 작동 http://sqlite.1065341.n5.nabble.com/Howto-pivot-in-SQLite-tp26766p26771.html

+0

[Help Center] (http://stackoverflow.com/help/how-to-answer)에서 : 외부 리소스에 대한 링크가 권장됩니다. 그러나 링크를 둘러싼 컨텍스트를 추가하여 동료 사용자가 무엇인지 알 수 있도록하십시오. 왜 그곳에 가는지.대상 사이트에 도달 할 수 없거나 영구적으로 오프라인 상태가되는 경우 중요한 링크의 가장 중요한 부분을 항상 인용하십시오. – Adam