2013-04-23 9 views
6

Ho questa tabella denominata people con due date su MySQL:selezionare una sequenza tra due numeri su MySQL

| Name | start_date | end_date | 
| John | 2007-03-01 | 2009-10-12 | 
| Mike | 2001-06-06 | 2010-12-01 | 

Voglio creare una vista che mi permette la ricerca per anno di attività, essendo anno di attività qualsiasi anno tra start_date e end_date. Così, mi piacerebbe ottenere un campo con una sequenza di anni, in questo modo:

| Name | activity_years         | 
| John | 2007,2008,2009         | 
| Mike | 2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 | 

ho provato alcuni approcci, ma non posso farlo. Dal momento che voglio creare una vista, devo fare tutto all'interno di un'istruzione SELECT e questo mi sta dando un po 'di mal di testa.

+0

Niente che valga menzione. Ho provato alcuni loop all'interno di SELECT e creando una procedura che ha creato la sequenza, ma non l'ho fatta funzionare, probabilmente perché mi mancava qualcosa. –

risposta

5

Qualcosa del genere dovrebbe farlo: -

SELECT a.Name, GROUP_CONCAT(YEAR(DATE_ADD(a.start_date, INTERVAL b.aNum YEAR))) AS activity_years 
FROM person a 
CROSS JOIN (SELECT a.i + b.i * 10 AS aNum FROM integers a, integers b) b 
WHERE YEAR(DATE_ADD(a.start_date, INTERVAL b.aNum YEAR)) <= YEAR(a.end_date) 
GROUP BY a.Name 

Esso si basa su una tabella di numeri interi con una colonna denominata i, con i valori da 0 a 9. Si unisce questo contro se stessa per ottenere una serie di numeri da 0 a 99, quindi fa fronte a intervalli di date molto distanti.

Rimozione dei subselect di usarlo in una vista

SELECT p.Name, GROUP_CONCAT(YEAR(DATE_ADD(p.start_date, INTERVAL (a.i + b.i * 10) YEAR))) AS activity_years 
FROM person p 
CROSS JOIN integers a 
CROSS JOIN integers b 
WHERE YEAR(DATE_ADD(p.start_date, INTERVAL (a.i + b.i * 10) YEAR)) <= YEAR(p.end_date) 
GROUP BY p.Name 
+0

Se OP trova che è accettabile creare una nuova tabella di aiuto permanente, potrebbe essere meglio chiamarlo Anni e archiviarli tutti gli anni possibili (ad esempio nel 1980-2050) e solo JOIN su quel tavolo per ottenere i dati? –

+0

Punto giusto e possibilmente vero. Dipende dagli intervalli di date, dalla frequenza con cui vengono utilizzati, ecc. Ad esempio, se gli intervalli di date erano per la data di nascita e la data di morte degli antenati risalenti a mille anni, potrebbe essere un po 'meno flessibile. Anche se dovesse essere espanso per dare tutti i mesi e gli anni nella gamma, allora è facile farlo con quanto sopra. – Kickstart

+0

Modificato per rimuovere la necessità di una sottoselezione – Kickstart

4

SQLFiddle demo

select name, 
     group_concat(tYears.row ORDER BY tYears.row) 
    from people 

join 

(
SELECT @row := @row + 1 as row FROM 
(select 0 union all select 1 union all select 3 union all select 4 union all 
    select 5 union all select 6 union all select 6 union all select 7) t, 
(select 0 union all select 1 union all select 3 union all select 4 union all 
    select 5 union all select 6 union all select 6 union all select 7) t2, 
(select 0 union all select 1 union all select 3 union all select 4 union all 
    select 5 union all select 6 union all select 6 union all select 7) t3, 

(SELECT @row:=1900) t21 
) tYears 

on tYears.row between year(start_date) and year(end_date) 
group by name 
+0

Non lo capisco completamente, ma non riesco a farlo funzionare comunque. Sembra funzionare correttamente su un semplice SELECT, ma non riesco a mettere questo SELECT in una VISTA. Viene visualizzato questo errore: 'Errore 1349: SELECT di View contiene una sottoquery nell'istruzione SQL della clausola FROM' –

+2

È piuttosto semplice. È il cross che unisce i risultati di alcuni selezioni insieme per ottenere un gran numero di risultati (ognuno dei selects sta riportando 8 righe, quindi 512 righe restituite), e unendola a una select per una variabile iniziale (cioè @row) impostato su 1900. Quindi riporta quella variabile indietro una volta per ogni riga, aggiungendo 1 ogni volta. Fornisce quindi un intervallo compreso tra 1901 e 2413. Quindi elimina qualsiasi occorrenza di quella variabile che non è compresa tra l'anno dei dati di inizio e la data di fine, quindi utilizza GROUP_CONCAT per riportare gli anni restanti in un singolo campo. – Kickstart

+0

Grazie per la spiegazione, tuttavia questo non funzionerà ancora perché la limitazione delle subquery sulle viste. –