Come posso semplificare la scrittura di query SQL complesse? [chiuso]


42

Sto trovando molto difficile scrivere query SQL complesse che coinvolgono join su molte (almeno 3-4) tabelle e che coinvolgono diverse condizioni nidificate. Le domande che mi viene chiesto di scrivere sono facilmente descritte da alcune frasi, ma possono richiedere una quantità ingannevole di codice per il completamento. Mi trovo spesso a utilizzare viste temporanee per scrivere queste query, che sembrano un po 'una stampella. Quali suggerimenti puoi fornire per semplificare queste complesse query? Più specificamente, come posso suddividere queste query nei passaggi che devo usare per scrivere effettivamente il codice SQL?

Nota che sono l'SQL che mi viene chiesto di scrivere fa parte dei compiti a casa per un corso di database, quindi non voglio software che farà il lavoro per me. Voglio davvero capire il codice che sto scrivendo.

Maggiori dettagli tecnici:

  • Il database è ospitato su un server PostgreSQL in esecuzione sul computer locale.
  • Il database è molto piccolo: non ci sono più di sette tabelle e la tabella più grande ha meno di circa 50 righe.
  • Le query SQL vengono inviate invariate al server, tramite LibreOffice Base.

Le viste temporanee sono in realtà piuttosto utili in quanto è possibile eseguire operazioni su una tabella di questo tipo (come indici complessi espliciti) che è molto difficile da suggerire al parser SQL.

Personalmente, trovo più facile imbrogliare usando una GUI (come LibreOffice Base "Crea query in visualizzazione Struttura" o Office Access "Crea"> "Progettazione query") e quindi visualizzare l'SQL che produce. A volte è necessario modificare l'SQL fornito da un progettista della GUI, ma fornisce un buon punto di partenza
kurdtpage

Risposte:


49

Sto basando la maggior parte di questo sul solo tentativo di ottenere la risposta "giusta", quindi potresti scoprire che ci sono alcuni problemi di prestazioni. Inutile accelerare una query errata.

Comprendi le relazioni tra le tabelle : la maggior parte sarà una a molte. Conosci la tabella "molti". Identifica i campi richiesti per i tuoi iscritti.

Pensa agli scenari di partecipazione a SINISTRA : seleziona tutti i dipendenti e la loro busta paga dello scorso mese. E se non avessero ricevuto uno stipendio il mese scorso?

Conoscere il set di risultati: 1) In un foglio di calcolo, inserire manualmente almeno un record corretto per la query. 2) Scrivi la query in una forma abbastanza semplice per identificare quanti record devono essere restituiti. Utilizzare entrambi questi per testare la query per assicurarsi che l'unione a una nuova tabella non altera il risultato.

Suddividi la query in parti gestibili : non è necessario scriverla tutta in una volta. Le query complesse a volte possono essere solo una raccolta di query semplici.

Fai attenzione ai livelli misti di aggregazione : se devi inserire valori mensili, trimestrali e da inizio anno nello stesso set di risultati, dovrai calcolarli separatamente in query raggruppate su valori diversi.

Sapere quando in UNION A volte è più semplice suddividere i sottogruppi nelle loro dichiarazioni selezionate. Se si dispone di una tabella mista con manager e altri dipendenti e su ciascuna colonna è necessario eseguire dichiarazioni Case basate sull'appartenenza a uno di questi gruppi, potrebbe essere più semplice scrivere una query Manager e unione su una query Employee. Ognuno conterrebbe la propria logica. Dover includere elementi di tabelle diverse in righe diverse è un uso ovvio.

Formule complesse / nidificate : prova a rientrare in modo coerente e non avere paura di utilizzare più righe. "CASO QUANDO CASO QUANDO CASO QUANDO" ti farà impazzire. Prenditi il ​​tempo per pensarci bene. Salvare i calcoli complessi per ultimo. Ottieni prima i record corretti selezionati. Quindi attacchi formule complesse sapendo che stai lavorando con i giusti valori. Vedere i valori utilizzati nelle formule ti aiuterà a individuare le aree in cui devi tenere conto dei valori NULL e dove gestire la divisione per zero errori.

Prova spesso quando aggiungi nuove tabelle per assicurarti di ottenere ancora il set di risultati desiderato e di sapere quale join o clausola è il colpevole.


1
Roba davvero eccellente. Voglio ribadire i punti di Jeff sulla ricerca di join LEFT e la suddivisione di query complesse in query più piccole e più gestibili, per poi combinarle. Scrivo grandi query su grandi database praticamente ogni giorno e queste due cose in particolare vengono fuori continuamente. Esegui sempre le query e le query secondarie il più presto possibile, per assicurarti di ottenere i dati che ti aspetti di vedere ad ogni passaggio.
CodexArcanum,

@CodexArcanum - e quando si eseguono query su big data, non fa male usare TOP;)
JeffO

Concordo su ogni affermazione del tuo suggerimento
Alessandro Rossi,

28
  1. Il rientro sarebbe la prima cosa da fare, se non lo fai già. Non solo è utile con query anche semplici, ma è cruciale quando si tratta di join e query un po 'più complesse di a select top 1 [ColumnName] from [TableName].

  2. Una volta indentato correttamente, nulla vieta di aggiungere commenti all'interno della query stessa, quando appropriato. Non abusarne: se il codice è abbastanza esplicito, l'aggiunta di commenti danneggerà solo la chiarezza del codice. Ma sono ancora i benvenuti per le parti meno esplicite della query.

    Si noti che query più lunghe (incluse query con commenti) significherebbero un maggiore utilizzo della larghezza di banda tra il server delle applicazioni e il server del database. Inoltre, a meno che non si lavori su un prodotto su scala Google con un'enorme quantità di richieste al secondo, che richiedono prestazioni e utilizzo delle risorse eccezionali, le dimensioni aggiunte dai commenti potrebbero non cambiare nulla in termini di prestazioni.

  3. Applicare lo stesso stile su tabelle, colonne, ecc. Aiuta anche la leggibilità. Quando un database legacy ha i tavoli PRODUCT, users, USERS_ObsoleteDONT_USE, PR_SHIPMENTSe HRhbYd_UU, qualcuno sta facendo qualcosa di molto sbagliato.

  4. È importante applicare lo stesso stile anche alle query . Ad esempio, se si stanno scrivendo query per Microsoft SQL Server e si è deciso di utilizzare [TableName]invece di TableNameattenersi. Se si passa a una nuova riga dopo una select, non farlo solo nella metà delle query, ma in tutte.

  5. Non utilizzare* , a meno che non ci siano validi motivi per farlo (come if exists(select * from [TableName] where ...)in Microsoft SQL Server). Non solo *ha un impatto negativo sulle prestazioni in alcuni database (se non nella maggior parte), ma non è utile per lo sviluppatore che utilizza la query. Allo stesso modo, uno sviluppatore deve accedere ai valori per nome, mai per indice.

  6. Infine, per alcuni, non c'è nulla di sbagliato nel fornire una vista . Per qualsiasi altra cosa, le procedure memorizzate possono anche essere utilizzate a seconda del progetto e delle persone¹ con cui stai lavorando².


¹ Alcune persone odiano le procedure memorizzate. Ad altri non piacciono per diversi motivi (perfettamente validi, almeno per loro).

² I tuoi colleghi, gli altri studenti, il tuo insegnante, ecc.


9

Un po 'uno scatto al buio qui, ma se stai scrivendo molte viste temporanee forse non ti sei ancora reso conto che la maggior parte dei posti potresti mettere una tabella in un'istruzione SQL, quella tabella può essere sostituita da una query.

Pertanto, anziché unire la tabella A alla vista temporanea B, è possibile unire la tabella A alla query utilizzata come vista temporanea B. Ad esempio:

    SELECT A.Col1, A.Col2, B.Col1,B.Col2
      FROM (SELECT RealTableZ.Col1, RealTableY.Col2, RealTableY.ID as ID
              FROM RealTableZ 
   LEFT OUTER JOIN RealTableY
                ON RealTableZ.ForeignKeyY=RealTableY.ID
             WHERE RealTableY.Col11>14
            ) As B
        INNER JOIN A
                ON A.ForeignKeyY=B.ID

Questo esempio è piuttosto inutile, ma dovrebbe spiegare la sintassi.

Per le viste che non sono "speciali" (indicizzate, partizionate) ciò dovrebbe comportare lo stesso piano di query come se si utilizzasse una vista.

Per semplificare la scrittura, puoi verificare ogni pezzo per assicurarti di ottenere ciò che ti aspetti prima di scrivere l'intera query.

Mi scuso se questo è già un vecchio cappello per te.


3
Sono abbastanza esperto di SQL e odio davvero questo rientro: può sembrare carino ma completamente inutile "secondo me". Due motivi: non riesco a capire chiaramente se quel join esterno sinistro fa parte della query principale o parte di una sottoquery, ha bisogno di un abbellitore di codice e ogni volta che vuoi aggiungere qualche riga devi ri-abbellire tutto il testo . Pianificare il rientro che necessita solo di TAB è molto più flessibile. Non ho votato verso il basso la tua risposta, ma scoraggio davvero chiunque usi questo stile ... specialmente quando hanno bisogno del mio aiuto.
Alessandro Rossi,

7

Invece di visualizzazioni temporanee, utilizzare la clausola WITH . Ciò rende molto più semplice suddividere le query di grandi dimensioni in parti più piccole più leggibili.


1
Se si utilizza un cte, tenere presente che la query persiste solo fino a quando non viene eseguita la query successiva, quindi in alcuni casi in cui si utilizza il cte in più query, potrebbe essere meglio per le prestazioni utilizzare una tabella temporanea.
Rachel,

3
  1. Acquisisci maggiore familiarità con la teoria degli insiemi se non lo sei già. SQL si basa sulla teoria degli insiemi e la comprensione più approfondita degli insiemi ti aiuterà a familiarizzare con il funzionamento di SQL.
  2. Pratica più SQl, se stai solo imparando SQL ci vorrà del tempo per capire come fare tutto, qualcosa richiede solo tempo prima di capirli davvero, I join sono un ottimo esempio più li usi e meglio ci riuscirai.
  3. Assicurarsi che le tabelle di cui si sta eseguendo la query siano progettate correttamente
  4. Non aver paura di usare le viste su query selezionate, specialmente se hai un set comune che deve essere perfezionato in diversi modi

1

Come qualsiasi altra cosa, si desidera suddividere il problema in parti gestibili.

Questo è davvero il modo in cui risolvi problemi complessi, comunque.

Quindi: vuoi controllare la sottoquery per vedere che restituisce davvero quello che vuoi prima di eseguire una query esterna su di essa. Vuoi provare un join minimo di ogni tabella a cui ti stai unendo in modo da poter vedere che ci stai davvero pensando correttamente. Cose del genere. Sperare di digitare tutto ed uscire esattamente quello che vuoi in una botta è semplicemente irrealistico.

Un'istruzione SQL, una volta raggiunta una certa complessità, è fondamentalmente un piccolo programma in sé e per sé. Fa una grande differenza capire davvero come i dati vengono combinati, selezionati, filtrati e prodotti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.