ciao,
doppiomango ha scritto:
per adesso ho risolto con codice asp.net ma è una soluzione pellegrina, perchè devo leggere le tabelle un numero spropositato di volte.
Sì, effettivamente non è la soluzione migliore, sarebbe meglio delegare al database il compito di trovare un modo per restituirti quelle righe.
Ti linko una sessione di Davide Mauri che spiega un altro approccio di affrontare questo genere di problemi senza usare cicli o codice .NET. Dagli un'occhiata se hai tempo, è veramente interessante, ti può dare degli spunti utili.
Video: T-SQL Set-based thinkingPenso di aver capito ciò che vuoi ottenere, ma quei
null che hai inserito tra i risultati NON salteranno fuori con delle JOIN "semplici".
Devi predisporre una funzione o tabella che ti restituisca dei numeri, come vedi al minuto 27:30, e poi farne la join (cross join, per l'esattezza) con
ta. In quella sessione si parla di Sql Server, ma se tu usi un altro DBMS il concetto resta il medesimo. Il risultato che otterrai sarà una roba del genere:
rownum, ta.valore
1, valore1
2, valore1
3, valore1
4, valore1
1, valore2
2, valore2
3, valore2
4, valore2
In pratica ti prepari ad accogliere fino a 4 valori provenienti dalle altre tabelle t1~t4 per ciascun valore di
ta.
Allo stesso modo, anche i record di t1~t4 dovranno essere numerati affinché tu possa sapere quale di quelli è il primo, il secondo, il terzo, ecc... per ciascun valore di ta (quindi in t1 il conto deve ricominciare ogni volta che cambia il valore della foreign key che lega t1 a ta).
Questo, se usi Sql Server, lo ottieni grazie alla funzione
ROW_NUMBER, ne vedi un'utilizzo al minuto 40:30.
SELECT t1.taID, t1.valore, ROW_NUMBER() OVER (PARTITION BY t1.taID ORDER BY t1.taID) as numeroRiga FROM t1
Invece, se usi MySql, credo che potresti utilizzare un sistema simile
a questo.
Ora che hai questi elementi, prova a combinarli così. Qui faccio la join solo con t1 e t2 per non allungare esageratamente la query.
WITH tabella1 AS (
SELECT t1.taID, t1.valore, ROW_NUMBER() OVER (PARTITION BY t1.taID ORDER BY t1.taID) as numeroRiga FROM t1
),
tabella2 AS (
SELECT t2.taID, t2.valore, ROW_NUMBER() OVER (PARTITION BY t2.taID ORDER BY t2.taID) as numeroRiga FROM t2
)
SELECT indici.indice, ta.Valore, tabella1.Valore, tabella2.Valore
FROM indici CROSS JOIN ta
LEFT JOIN tabella1 ON (ta.ID = tabella1.taID AND indici.indice=tabella1.numeroRiga)
LEFT JOIN tabella2 ON (ta.ID = tabella2.taID AND indici.indice=tabella2.numeroRiga)
ORDER BY ta.ID, indici.indice;
Questo produce, come da te richiesto, un risultato del genere:
1 ta.valore1 t1.a1 t2.b1
2 ta.valore1 t1.a2 t2.b2
3 ta.valore1 t1.a3 NULL
4 ta.valore1 NULL NULL
1 ta.valore2 t1.a4 t2.b3
2 ta.valore2 NULL t2.b4
3 ta.valore2 NULL t2.b5
4 ta.valore2 NULL NULL
Puoi escludere i risultati che contengono solo dei null imponendo questa condizione (o qualcosa di simile) nella clausola WHERE.
WHERE COALESCE(tabella1.Valore, tabella2.Valore) IS NOT NULL
Il problema di tutto questo sistema è che devi conoscere a priori il numero massimo di record che possono arrivare da t1~t4 per ciascun valore di ta. Qui io ho ipotizzato che fossero 4, ma magari tu ne hai un numero di variabile che non saprei come calcolarmi dinamicamente.
Poi, il piano di esecuzione di questa query non mi pare granché, c'è sicuramente margine di miglioramento.
Magari Andrea Montanari, MVP per SQL Server, se legge questo thread può suggerirti un sistema più efficiente.
ciao
Modificato da BrightSoul il 20 dicembre 2011 22.22 -