2009-08-06 10 views
25

Mi piacerebbe avere una tabella che mostra gli studenti e i voti che ricevono per tutti i loro soggetti in una query.Pivot in SQLite

Questa è la mia struttura della tabella:

Tabella: markdetails

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

Tabella: student info

attuale struttura:

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

Voglio che il set di risultati a guardare come questo :

Tabella: 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 

Come posso fare questo in SQLite?

risposta

23

In primo luogo è necessario modificare la tabella corrente per una tabella temporanea:

alter table student_info rename to student_name 

Quindi, ti consigliamo di ricreare 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 
) 

Poi, popolato 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 

Ora basta rilasciare il tavolo temporaneo:

drop table student_temp 

Ed è così che puoi aggiornare rapidamente il tuo tavolo.

SQLite non ha una funzione pivot, quindi il meglio che si può fare è codificare in modo rigido alcuni join di sinistra. Un left join porterà corrispondenze a tutte le righe nelle condizioni di join e restituirà null per tutte le righe dalla prima o dalla sinistra, tabella che non soddisfano le condizioni di join per la seconda tabella.

+0

grazie Eric ... il querry funziona bene per ottenere i dettagli dell'intera circa uno student.but voglio modificare il contenuto e colonne in un table.I penso che tu non abbia ottenuto la mia domanda. Voglio cambiare tavolo. – arams

+0

Grazie ERIC ... Funziona benissimo. – arams

+0

@arams: fantastico, felice di sentirlo! Si prega di revocare/contrassegnare questo come la risposta se ha risolto il tuo problema! – Eric

14

Poiché l'autore non è stato così gentile da fornire l'SQL per creare lo schema, qui è per chiunque voglia provare la soluzione di @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'); 

Ecco una soluzione alternativa utilizzando case con group by.

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 
; 

Per confronto, qui è la stessa dichiarazione prescelta da @ soluzione di Eric:

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 
; 

Sarà interessante vedere quale sarebbe meglio eseguire quando c'è un sacco di dati.

+7

Ho avuto l'opportunità di testare questo, su un tavolo con circa 150.000 righe. Una complicazione è che non conosco il numero di colonne in anticipo, quindi devo fare un po 'di pre-elaborazione per determinare il numero di colonne necessarie. Inoltre, non tutte le righe hanno lo stesso numero di dati. Con il metodo di join esterno, il mio PC ha impiegato 50 secondi. Con il caso quando il metodo, ci sono voluti 15 secondi. Usando una combinazione di reshape2 e plyr (sto usando R per eseguire sqlite), ci sono voluti circa 1.040 secondi. Il chilometraggio può variare, tuttavia. – Chow

+0

@Chow, totalmente d'accordo. il mio tavolo ha 280.000 file e ci sono voluti 20 secondi. Questa risposta dovrebbe essere in cima. – nikpod

6

grande appendice! mi ha aiutato a risolvere un problema simile con scarso sforzo e carico di sistema.Uso un Raspberry Pi avere 1wire dell'interfaccia dati del sensore di temperatura DS18B20 come segue:

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

esempio:

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 

utilizzando il comando SUBSTR() Sono "normalizzare" il Timestamp a 10 minuti periodi. Con il ENTRARE sensorID si trasforma in un SENSORNAME utilizzando la ricerca-tavolo 'sensori

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

esempio:

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 

ora, la magia accade con le istruzioni caso summenzionato.

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; 

esempio:

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 

L'unico problema che rimane è che il SENSORNAME 'T1' ... 'T10' è ora insita nel VIEW [PivotTemps10min] e non presi dalla tabella di ricerca .

Tuttavia, grazie mille per le risposte in questo senso!

+0

Questo è davvero quello che stavo cercando. Grazie mille. –

+0

Sono sicuro che un gran numero di appassionati di IoT che usano SQL faranno riferimento a questo. La mia applicazione è quasi identica. – nikpod

0

Se si dispone di un requisito più semplice di raggruppare insieme i bambini nello stesso campo, group_concat è tuo amico.

grazie enorme a Simon Slaver da questa discussione: http://sqlite.1065341.n5.nabble.com/Howto-pivot-in-SQLite-tp26766p26771.html

+0

Dal [Centro assistenza] (http://stackoverflow.com/help/how-to-answer): i collegamenti a risorse esterne sono incoraggiati, ma per favore aggiungi un contesto intorno al link in modo che i tuoi utenti possano avere un'idea di cosa sia e perché è lì.Citare sempre la parte più rilevante di un link importante, nel caso in cui il sito target non sia raggiungibile o sia permanentemente offline. – Adam