2009-08-06 9 views
25

Me gustaría obtener una tabla que muestre a los estudiantes y las calificaciones que reciben para todos sus temas en una consulta.Pivote en SQLite

Esta es mi estructura de la tabla:

Tabla: markdetails

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

Tabla: student info

estructura real:

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

Quiero que el conjunto de resultados a este aspecto :

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

¿Cómo puedo lograr esto en SQLite?

Respuesta

23

En primer lugar es necesario cambiar la tabla actual a una tabla temporal:

alter table student_info rename to student_name 

Entonces, usted desea volver a crear 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 
) 

A continuación, rellenar 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 

Ahora, simplemente suelte su tabla temporal:

drop table student_temp 

Y así es como puede actualizar rápidamente su tabla.

SQLite carece de una función pivot, por lo que lo mejor que puede hacer es codificar algunas combinaciones izquierda. Un left join hará coincidir las filas en sus condiciones de unión y devolverá null para cualquier fila de la primera tabla, o de la izquierda, que no cumplan las condiciones de unión para la segunda tabla.

+0

gracias Eric ... la querry funciona bien para conseguir la totalidad de los detalles acerca de un student.but Quiero modificar el contenido y columnas en una table.I Creo que no recibió mi pregunta. Quiero cambiar la mesa. – arams

+0

Gracias ERIC ... Funciona bien. – arams

+0

@arams: ¡Fantástico, me alegro de escucharlo! Vota por favor/marca esto como la respuesta si resolvió tu problema. – Eric

14

Dado que el autor no tuvo la amabilidad de dar el SQL para crear el esquema, aquí está para cualquiera que quiera probar la solución de @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'); 

Aquí es una solución alternativa usando 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 
; 

Para la comparación, aquí es la misma instrucción de selección de @ solución de 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 
; 

Será interesante ver cuál sería un mejor desempeño cuando hay una gran cantidad de datos.

+7

Tuve la oportunidad de probarlo en una tabla con aproximadamente 150,000 filas. Una complicación es que no sé el número de columnas por adelantado, así que tengo que hacer un pequeño preprocesamiento para determinar el número de columnas necesarias. Además, no todas las filas tienen la misma cantidad de datos. Con el método de combinación externa, mi PC tardó 50 segundos. Con el caso cuando el método, tomó 15 segundos. Usando una combinación de reshape2 y plyr (estoy usando R para ejecutar sqlite), tomó aproximadamente 1,040 segundos. Tu millaje puede variar, sin embargo. – Chow

+0

@Chow, totalmente de acuerdo. mi mesa está con 280,000 filas y tomó como 20 segundos. Esta respuesta debería estar en la parte superior. – nikpod

6

great appendix! me ayudó a resolver un problema similar con poco esfuerzo y carga del sistema.Estoy usando un Frambuesa Pi para obtener los datos del sensor de temperatura DS18B20-interfaz 1wire como sigue:

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

ejemplo:

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 

utilizando el comando SUBSTR() Soy "normalizar" los sellos de tiempo de 10 minutos períodos. Con unirse a los sensorID se cambia en un SensorName utilizando la tabla de consulta

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

ejemplo 'sensores':

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 

ahora, la magia sucede con la instrucción citado caso.

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; 

ejemplo:

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 

El único problema que queda aquí es que el sensorName 'T1' ... 'T10' ahora está codificado en la vista [PivotTemps10min] y no tomada de la tabla de búsqueda .

No obstante, muchas gracias por las respuestas en este tema!

+0

Esto es realmente lo que estaba buscando. Muchas gracias. –

+0

Estoy seguro de que una gran cantidad de entusiastas de IoT que usan SQL se referirán a esto. Mi aplicación es casi exactamente la misma. – nikpod

0

Si tiene un requisito más simple de agrupar a los niños en el mismo campo, group_concat es su amigo.

Muchas gracias a Simon Esclavos de este tema: http://sqlite.1065341.n5.nabble.com/Howto-pivot-in-SQLite-tp26766p26771.html

+0

del [Centro de ayuda] (http://stackoverflow.com/help/how-to-answer): se recomiendan enlaces a recursos externos, pero agregue contexto alrededor del enlace para que los demás usuarios tengan una idea de lo que es y por qué está ahí.Siempre cite la parte más relevante de un enlace importante, en caso de que el sitio objetivo no esté disponible o esté permanentemente fuera de línea. – Adam