2013-03-14 14 views
7

Come afferma il titolo, vorrei dividere due valori l'uno con l'altro che si trovano nella stessa colonna. E.g.Come dividere due valori dalla stessa colonna in SQL

A    B    C   D 
    Shirts   2011   85   0 
    Shirts   2012   92  percent change from 2011 to 2012 
    Shirts   2013   100  percent change from 2012 to 2013 
    Pants   2011   31   0 
    Pants   2012   42  percent change from 2011 to 2012 
    Pants   2013   55  percent change from 2012 to 2013 
    Jacket   2011   10   0 
    Jacket   2012   16  percent change from 2011 to 2012 
    Jacket   2013   18  percent change from 2012 to 2013 

In questo esempio colonna D sarebbe un derivato dalla colonna C, dove il valore del 2012 viene sottratto dal 2011, e poi volte da un 100 per ottenere la percentuale.

Non so come impostare la query up Ho provato a fare un sacco di sottoquery ma non sapevo come collegarle insieme. Qualsiasi aiuto sarebbe molto apprezzato.

+0

se fossi in te, lo farò SQL esterno, per esempio fai la logica in PHP. – Raptor

+1

Che motore SQL? –

+0

Non è possibile farlo con Simple Sql, è necessario utilizzare la stored procedure/funzioni nel database o un linguaggio lato server per implementare la business logic –

risposta

1

Ecco un'opzione per ottenere quello che stai dopo

SELECT t1.a, t1.b, t1.c, 
    CASE WHEN t2.c IS NULL THEN 0 ELSE t1.c - t2.c END AS d, 
    CASE WHEN t2.c IS NULL THEN 0 ELSE (1.0 * t1.c - t2.c)/t1.c * 100.0 END AS pct 
FROM t t1 
LEFT OUTER JOIN t t2 ON t1.a = t2.a 
    AND t1.b = t2.b + 1 

SQL Fiddle Example

+0

Ho una breve domanda che hai inserito +1 alla fine nella colonna t2.b e mi stavo chiedendo a cosa servisse? – user2167857

+0

Ecco come si unisce una riga all'altra. Quindi, un valore t1.b corrisponde al valore di t2.b + 1 o 2011 = 2010 + 1. t1 è la riga del 2011 e t2 è la riga del 2010. – bobs

+0

hey @bobs mi dispiace disturbare così tanto sono abbastanza nuovo per SQL, quindi sto ancora imparando tutte le corde.Ho scritto il seguente SQL e ottenuto un valore di colonna per PCT come tutti gli 0, qualche aiuto? SELEZIONA a.FiscalYear , a.Dx_Group , a.TotalAppnts_NEW , a.TotalAppnts_RETURN , caso in cui b.TotalAppnts_NEW è nullo Poi 0 altro ((b.TotalAppnts_NEW-a.TotalAppnts_NEW) /a.TotalAppnts_NEW) * 100 fine PCT Da ONC.tTEMP_ORCM_Visits come A LEFT OUTER JOIN ( SELEZIONA b.FiscalYear , b.Dx_Group , b.TotalAppnts_NEW , b.TotalAppnts_RETURN Da ONC.tTEMP_ORCM_Visits b) B sul a.Dx_Group = b.dx_group e a.FiscalYear = b.fiscalyear + 1 – user2167857

0

Prova questo:

SELECT t1.type A, t1.year B, t1.value C, 
IF(
    EXISTS(
    SELECT 1 FROM table t2 WHERE t1.type = t2.type AND t1.year = (t2.year - 1) 
), 
    ((SELECT t3.year FROM table t3 WHERE t1.type = t3.type AND t1.year = (t3.year - 1)) - t1.year)/t1.year, 
    0 
) D 
FROM table t1 

Non super efficiente, ma si può fare.

+0

grazie @aiias proverò questo e ti terremo aggiornato – user2167857

1

Sono d'accordo con Shivan, ma solo perché non so come farlo senza PHP. Con PHP è solo questione di tirare i due totali, fare i conti e inviare una query con le risposte.

ANCHE SICURO DI LEGGERE QUESTO PERCHÉ È LA PARTE PIÙ IMPORTANTE La vostra matematica è sbagliata. (Shirts2011 - Shirts2012) * 100 non ti dà la variazione percentuale. Ti dà solo 100 times the difference of the two (in realtà, la differenza negativa in base alla tua formulazione). Quello che vuoi, matematica-saggio, è:

((Item2012-Item2011)/Item2011)*100 

So che la parentesi esterni non sono necessari, ma lo fanno più facile da leggere. La variazione percentuale è uguale a 100 volte il rapporto tra la differenza dei due e l'iniziale.

Modificato per aggiungere codice PHP.

Il PHP sembra volgare, ma ha fatto il lavoro.

$conn = new PDO(HOST:DATABASE, USERNAME, PASSWORD); 
    $query = "SELECT A, B, C FROM yourTable"; 
    $st = $conn->prepare($query); 
    $st->execute(); 

$list = array(); 
while($row = $st->fetch(PDO::FETCH_ASSOC)) 
    $list[] = $row; 

$fill = array(); 
for($i=1; $i<count($list); $i++) 
    if($list[$i]['A'] == $list[$i-1][A]) 
     $fill[] = $array('A' => $list[$i]['A'], 
         'B' => $list[$i]['B'], 
         'D' => ($list[$i]['C']-$list[$i-1]['C'])/$list[$i-1]['C']*100); 

$update = new PDO(HOST:DATABASE, USERNAME, PASSWORD); 
    for($i=0; $i<count($fill); $i++){ 
     $query = "UPDATE yourTable SET D = " . $fill[$i]['D'] . " WHERE A = " . $fill[$i]['A'] . " AND B = " . $fill[$i]['B']; 
     $st = $update->prepare($query); 
     $st->execute(); 
    } 

Basta inizializzare il tavolo dove i 2011 colonne D = 0.

UPDATE yourTable SET D = 0 WHERE B = 2011; 

E prima che le fiamme iniziano, Conosco un foreach avrebbe funzionato; Penso solo a uno standard per un aspetto migliore (e ti consente di saltare il primo valore del 2011).

+0

lol so che la formula è appena diventata pigro, ho pensato che la parte più importante stava cercando di capire come dividere due valori che sono nella stessa colonna. mi scuso se fa davvero la differenza. Inoltre non ho familiarità con PHP non l'ho usato prima. Proverò la soluzione di aiias domani, ma nel frattempo qualcuno ha un'altra soluzione? – user2167857

1

Se sto capendo correttamente i tuoi requisiti, potresti usare un cte ricorsivo per ottenere i risultati. Questo utilizza ROW_NUMBER() e partizioni (gruppi di) colonna A.

Questo metodo sarebbe miglior lavoro se non si può garantire anni sequenziali nella colonna B. Se avete sempre sequenziali anni, poi bob fornisce la migliore alternativa.

with cte as (
    select A, B, C, 
    ROW_NUMBER() OVER (PARTITION BY A ORDER BY B) rn 
    from yourtable 
), 
recursive_cte as (
    select A, B, C, 0 prc 
    from cte 
    where rn = 1 
    union all 
    select y.A, y.B, y.C, y.C-c.C prc 
    from cte y 
    join cte c on y.a=c.a and y.rn=c.rn+1 
) 
select * 
from recursive_cte 
order by a, b 

SQL Fiddle Demo

Ciò restituirà la differenza tra ogni anno e la precedente raggruppati per colonna A. Esso utilizza un 2 ° CTE solo per semplicità. Se si desidera modificare la percentuale effettiva, aggiornare la formula sopra riportata.

--edit

Dal momento che suona come siete in cerca di crescita percentuale, provare a sostituire YC-aA PRC con questa formula, invece:

cast(y.C as decimal(10,2))/cast(c.C as decimal(10,2)) 

Usa CAST se i dati i tipi sono interi.

+0

grazie sgeddes ci proverò domani, ho una domanda veloce, CTE è un'altra parola per sottomissione? – user2167857

+0

@ user2167857 - sì, è più semplice della riscrittura :) Dipende dai tuoi bisogni - questo funzionerà bene se per anni gli anni non sono necessariamente sequenziali (2011-2013). Se tuttavia è sempre garantito che siano sequenziali, ci sono alternative più semplici (a titolo di esempio, il bob ne fornisce uno). Dipende solo dalle tue esigenze. Buona fortuna. – sgeddes

+0

grazie per il tuo aiuto, lo apprezzo davvero, come hai detto che la risposta di Bob ha funzionato meglio per me, anche se apprezzo molto che tu abbia dedicato del tempo per aiutarmi. – user2167857

0

Prova questo:

select Y2013.*, Y2012.C, Y2013.C, Y2013.C/Y2011.C 
from (
    select * from data where B = year(getdate()) 
) Y2013 
left join (
    select * from data where B = year(getdate()) - 1 
) Y2012 on Y2012.A = Y2013.A 
left join (
    select * from data where B = year(getdate()) - 2 
) Y2011 on Y2011.A = Y2012.A 
and Y2011.A = Y2013.A 
+0

stavo pensando di farlo in questo modo, ma questo sarebbe stato inserito in un pacchetto SSIS e poi scaricato in una tabella, per essere utilizzato in futuro, quindi l'anno 2014 verrà aggiunto e il 2011 sarà scomparso – user2167857

+0

@ user2167857: Come incurante di me; controlla ora. –

0

si potrebbe provare anche questo:

UPDATE mytable t1 
    INNER JOIN mytable t2 
    ON t1.A = t2.A AND t2.B = t1.B - 1 
SET t1.D = ((t1.C - t2.C)/t2.C) * 100; 

vedere fiddle.

Supponendo di avere già 0 come valore predefinito per D. In caso contrario, è sufficiente impostarlo su 0 per tutte le righe prima di eseguire questa query.

2

È possibile raggiungere questo obiettivo con un self-join:

SELECT curr.ClothingType, curr.SalesYear, curr.NumberSold 
    , COALESCE((CAST((curr.NumberSold - prev.NumberSold) AS NUMERIC(5,2))/prev.NumberSold) * 100, 0) AS PercentChange 
FROM #Clothes AS curr 
LEFT JOIN #Clothes AS prev ON curr.ClothingType = prev.ClothingType 
    AND curr.SalesYear = prev.SalesYear + 1 

SQL Fiddle Example

+0

Ho provato la tua strada e continuo a ottenere gli 0 come risultato per la parte di calcolo che sto aggiungendo l'SQL che ho scritto puoi farmi sapere se c'è qualcosa che sto facendo male. grazie per il tuo aiuto SELEZIONA a .FiscalYear , a.Dx_Group , a.TotalAppnts_NEW , a.TotalAppnts_RETURN , caso in cui b.TotalAppnts_NEW NON è nullo e a.TotalAppnts_NE W non è null, ((b.TotalAppnts_NEW-a.TotalAppnts_NEW) /a.TotalAppnts_NEW) * 100 ELSE 0 End PCT Da ONC.tTEMP_ORCM_Visits come A LEFT OUTER JOIN ONC.tTEMP_ORCM_Visits come B su a.Dx_Group = b. Dx_Group e a.FiscalYear = b.FiscalYear + 1 – user2167857

+0

@ user2167857 Le tue colonne sono probabilmente numeri interi e la tua query genererà la divisione in interi, rimuovendo la frazione (percentuale). Nota il mio 'CAST (AS NUMERIC (5,2))' che trasformerà il numeratore in un valore 'NUMERIC', consentendo ai calcoli di mantenere i valori percentuali che stai cercando. –

+0

Wegner Grazie amico la tua e la risposta di Bob è quasi esattamente la stessa apprezzo tutto l'aiuto. – user2167857

Problemi correlati