Domanda

Devo interrogare questo DB per ottenere ogni riga, ma anche la SOMMA di uno dei valori di colonna dei risultati. Potrei usare php per ottenere il valore totale, ma poi avrei bisogno di eseguire due loop, uno per ottenere il totale (che va in alto sopra i risultati). Quindi preferirei che la query la catturasse e farei solo un & Quot; total & Quot; riga, ma l'unico modo per farlo funzionare è con una subquery che è essenzialmente una ripetizione della query originale. C'è un modo migliore?

SELECT 
CONCAT(u.firstname, ' ', u.lastname ) name, u.id, s.description, s.shiftstart, s.shiftend, 
    (SELECT 
    SUM( TIME_TO_SEC( TIMEDIFF( shiftend, shiftstart ) ) ) /3600
    FROM shifts
    WHERE id =  '$user'
    AND DATE( shiftstart )
    BETWEEN '$start'
    AND '$end') total
FROM shifts s
INNER JOIN users u ON ( s.id = u.id )
WHERE s.id = '$user'
AND DATE( shiftstart )
BETWEEN '$start'
AND '$end'
ORDER BY shiftstart

Le funzioni e i risultati sopra riportati:

name        id     description  shiftstart             shiftend               total
Joe User    joeuser    Stuff    2009-01-05 07:45:00    2009-01-05 12:15:00    39.5000
Joe User    joeuser    Stuff    2009-01-05 13:00:00    2009-01-05 17:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-06 07:45:00    2009-01-06 10:45:00    39.5000
Joe User    joeuser    Stuff    2009-01-06 10:45:00    2009-01-06 12:45:00    39.5000
Joe User    joeuser    Stuff    2009-01-06 13:30:00    2009-01-06 14:30:00    39.5000
Joe User    joeuser    Stuff    2009-01-06 14:30:00    2009-01-06 17:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-07 09:45:00    2009-01-07 14:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-07 15:00:00    2009-01-07 17:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-08 08:00:00    2009-01-08 12:15:00    39.5000
Joe User    joeuser    Stuff    2009-01-08 13:15:00    2009-01-08 17:00:00    39.5000
Joe User    joeuser    Stuff    2009-01-09 07:45:00    2009-01-09 10:45:00    39.5000
Joe User    joeuser    Stuff    2009-01-09 11:45:00    2009-01-09 15:15:00    39.5000
Joe User    joeuser    Stuff    2009-01-09 15:15:00    2009-01-09 17:00:00    39.5000

Qual è ciò di cui ho bisogno, ma probabilmente non è il modo migliore per ottenerlo.

È stato utile?

Soluzione

MySQL supporta un modificatore speciale raggruppato chiamato ROLLUP .

SELECT CONCAT(u.firstname, ' ', u.lastname ) name, u.id, 
  s.description, s.shiftstart, s.shiftend, 
  SUM( TIME_TO_SEC( TIMEDIFF( shiftend, shiftstart ) ) ) /3600 total
FROM shifts s INNER JOIN users u ON ( s.id = u.id )
WHERE s.id = ? AND DATE( shiftstart ) BETWEEN ? AND ?
GROUP BY u.id, s.shiftstart WITH ROLLUP
ORDER BY shiftstart;

Altri suggerimenti

Il modo migliore è farlo con il codice. Le persone continuano a insistere sull'uso di SQL, che è un'algebra relazionale, per svolgere compiti procedurali. Cercare di mettere in atto le procedure procedurali su SQL è sempre una cattiva idea, sia in termini di complessità che di prestazioni. Prendi questo consiglio da un DBA professionale.

Esegui due query dal tuo codice. Emetti prima il set più grande, quindi la linea totale in qualsiasi formato desideri. Le tue domande saranno più piccole e più semplici, le tue prestazioni miglioreranno e otterrai l'output che desideri.

Qualche altro consiglio: lo spazio su disco è economico e la maggior parte delle tabelle del database vengono lette molto più spesso di quanto siano scritte. Imposta un trigger di inserimento / aggiornamento (se possibile in MySQL) per popolare una colonna separata con campi calcolati come & Quot; CONCAT(u.firstname,' ',u.lastname) & Quot; e usalo per le query. Le funzioni per riga non sono scalabili e uccideranno le prestazioni del tuo DBMS man mano che aumentano.

Qualsiasi cosa può essere migliore al confronto; la domanda è il confronto con cosa, giusto?

Il problema chiave che hai indicato è che volevi il totale in cima ai risultati; Crystal Reports e altre app gestiscono questo tipo di magia essendo un motore a 2 passaggi. Il primo passaggio ottiene i totali.

Esistono compromessi con qualsiasi soluzione. Se ottieni un & Quot separato; totale & Quot; riga, quindi l'app di ricezione dovrà eliminarla dai risultati o giocare qualche altro trucco per nasconderla.

Una possibilità, che può essere un'opzione se non si sta scrivendo per un sito Web da 1 milione di hit / ora, è semplicemente fare 2 chiamate, una per le informazioni generali, come il nome, il TOTAL Time, ecc. quindi per i dettagli ... Appare dalla query che si stanno selezionando i risultati di una sola persona.

Siamo tutti per risparmiare overhead e larghezza di banda, ma a volte, semplice è meglio ...

EDIT: Pax mi ha battuto alla quot &; salva " pulsante ... lol ...

Usa l'estensione mysql fornita esattamente per questo scopo, come descritto nella risposta di Bill Karwin (che ho votato io stesso).

Se questo non fosse disponibile, l'opzione 2 sarebbe un'altra istruzione SQL: SELECT SUM ...) SQL è davvero ottimizzato per essere estremamente efficiente per questo tipo di cose, rispetto a qualsiasi ciclo di codice procedurale che è probabile che tu abbia scrivere.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top