update - sql raggruppamento dati




Come recuperare in modo efficiente i dati in una o più relazioni (5)

Prova a usare EXISTS, suppongo, per questo caso potrebbe essere meglio unire le tabelle. Sul mio oracolo db sta dando un tempo di esecuzione leggermente migliore della query di esempio, ma questo potrebbe essere db-specifico.

SELECT first_table.ID, CASE WHEN EXISTS (SELECT * FROM second_table WHERE first_table.ID = second_table.ID) THEN 1 ELSE 0 END FROM first_table

Sto incontrando un problema in cui ho bisogno di eseguire una query che dovrebbe ottenere alcune righe da una tabella principale e avere un indicatore se la chiave della tabella principale esiste in una sottotabella (relazione da uno a molti).

La query potrebbe essere qualcosa del genere:

select a.index, (select count(1) from second_table b where a.index = b.index) 
from first_table a;

In questo modo otterrei il risultato desiderato (0 = nessun record dipendente in seconda tabella, altrimenti ci sono), ma eseguo una sottoquery per ogni record che ottengo dal database. Devo ottenere questo indicatore per almeno tre tabelle simili e la query principale è già un join interno tra almeno due tabelle ...

La mia domanda è se c'è un modo veramente efficace per gestire questo. Ho pensato di tenere un record in una nuova colonna "first_table", ma il dbadmin non consente i trigger e tenerne traccia per codice è troppo rischioso.

Quale sarebbe un buon approccio per risolvere questo?

L'applicazione di questa query sarà per due cose:

  1. Indica che almeno una riga in seconda_tabella esiste per una data riga in first_table. Significa indicarlo in una lista. Se non esiste alcuna riga nella seconda tabella, non accenderò questo indicatore.
  2. Per cercare tutte le righe in first_table che hanno almeno una riga in second_table o che non hanno righe nella seconda tabella.

Un'altra opzione che ho appena trovato:

select a.index, b.index 
from first_table a 
left join (select distinct(index) as index from second_table) b on a.index = b.index

In questo modo otterrò null per b.index se non esiste (la visualizzazione può essere finalmente adattata, sono interessato alle prestazioni delle query qui).

L'obiettivo finale di questa domanda è trovare un approccio di progettazione appropriato per questo tipo di caso. Succede spesso, una vera applicazione potrebbe essere un sistema POS per mostrare tutti i client e avere una sola icona nella lista come indicatore se il cliente ha ordini aperti.


perché non provare questo

select a.index,count(b.[table id])  
from first_table a
left join second_table b
    on a.index = b.index
group by a.index

Suppongo che non sia possibile modificare le definizioni delle tabelle, ad esempio partizionare le colonne.

Ora, per ottenere una buona performance è necessario prendere in considerazione altri tavoli che vengono aggiunti al tuo tavolo principale.

Tutto dipende dai dati demografici dei dati.

  1. Se gli altri join comprimono le righe per il fattore alto, dovresti considerare di fare un join tra la tua prima tabella e la seconda tabella. Ciò consentirà all'ottimizzatore di scegliere il miglior ordine di join, ovvero, prima di unirsi ad altre tabelle, le righe risultanti si uniranno alla seconda tabella acquisendo le prestazioni.

  2. Altrimenti, puoi adottare un approccio subquery (ti suggerisco di usare esiste, potrebbe essere la soluzione di Mikhail).

  3. Inoltre, potresti prendere in considerazione la creazione di una tabella temporanea, se hai bisogno di tali query più di una volta nella stessa sessione.


Due idee: una che non comporta il cambio delle tabelle e una che lo fa. Prima quella che usa le tabelle esistenti:

SELECT
  a.index,
  b.index IS NOT NULL,
  c.index IS NOT NULL
FROM
  a_table a
LEFT JOIN
  b_table b ON b.index = a.index
LEFT JOIN
  c_table c ON c.index = a.index
GROUP BY
  a.index, b.index, c.index

Vale la pena notare che questa query (e probabilmente qualsiasi che la assomigli) sarà molto utile se b_table.index e c_table.index sono o chiavi primarie o sono altrimenti indicizzati.

Ora l'altra idea. Se è possibile, invece di inserire una riga in b_table o c_table per indicare qualcosa sulla riga corrispondente in a_table , indicarlo direttamente sulla riga a_table . Aggiungi le exists_in_b_table e exists_in_c_table a a_table . Ogni volta che inserisci una riga in b_table , imposta a_table.exists_in_b_table = true per la riga corrispondente in a_table . Le eliminazioni sono più lavoro poiché per aggiornare la riga a_table è necessario controllare se ci sono righe in b_table diverse da quella appena cancellata con lo stesso indice. Se le eliminazioni non sono frequenti, tuttavia, ciò potrebbe essere accettabile.


Non sono esperto nell'uso del caso, ma raccomanderò il join ...

funziona anche se utilizzi tre o più tabelle ..

SELECT t1.ID,t2.name, t3.date
FROM  Table1 t1 
LEFT OUTER JOIN Table2 t2 ON t1.ID = t2.ID
LEFT OUTER JOIN Table3 t3 ON t2.ID = t3.ID
--WHERE t1.ID = @ProductID -- this is optional condition, if want specific ID details..

questo ti aiuterà a recuperare i dati dalle tabelle Normalizzate (BCNF), dato che classificano sempre i dati con tipo di natura in tabelle separate.

Spero che questo faccia ...





sql-execution-plan