2009-06-14 6 views
2

J'ai 2 tables (?):complexe SQL requête de jointure

1) Table Masterdates qui contient toutes les dates depuis le 1er janvier 1900

2) Table Stockdata qui contient des données de stock à la date sous forme , symbole, ouvert, haut, bas, à proximité, volume (clé primaire = date symbole)

C'est ce que je cherche à récupérer (présenté ici au format CSV)

mdate, sdate, Symbole, open , High, ...

6/4/2001,6/4/2001, Foo, 47,49, ...

6/5/2001, null, null, null, null, ...

6/6/2001,6/6/2001, Foo, 54,56, ...

où MDate provient de Masterdates et SDate provient de Stockdata. J'ai besoin que la sortie commence par la première (la plus ancienne) extension du symbole souhaité (dans cet exemple, Foo, à partir du 6/4/2001) dans Stockdata, puis inclue toutes les dates des Masterdates jusqu'à la dernière (dernière) date disponible pour le symbole souhaité dans Stockdata, produisant des valeurs nulles lorsqu'il n'y a pas d'enregistrement Stockdata correspondant pour un enregistrement Masterdate donné dans la plage décrite.

Existe-t-il un moyen de le faire en une seule requête, une série de requêtes, et/ou en ajoutant des tables auxiliaires, ce qui donnera des résultats rapides? Ou devrais-je vider les super-ensembles de ce que je veux, puis construire la sortie finale en utilisant mon langage de programmation (non-SQL)?

TIA

+0

Quel système SQL exactement? MS SQL Server? MySQL? –

Répondre

7

Testé dans Sqlite3, l'implémentation de DB peut différer

SELECT m.date, 
     s.symbol, 
     s.open, 
     s.high, 
     s.low, 
     s.close, 
     s.volume 
FROM  masterdate AS m LEFT OUTER JOIN 
     stockdata AS s ON m.date = s.date 
AND  s.symbol = 'Foo' 
WHERE m.date >= (SELECT MIN(date) FROM stockdata WHERE symbol = 'Foo') 
AND  m.date <= (SELECT MAX(date) FROM stockdata WHERE symbol = 'Foo') 

Si cela ne suffit alors Quicky exécute pas, vous pouvez pronably améliorer les performances en définissant des variables de valeur minimale et maximale dans une requête et puis en utilisant ceux dans la requête principale. Cela vous permettrait d'économiser au moins un coup d'index.

So (dans la syntaxe SQL Server)

SET @symbol = 'Foo' 

SELECT @mindate = MIN(date), 
     @maxdate = MAX(date) 
FROM stockdata 
WHERE stockdata.symbol = @symbol 


SELECT m.date, 
     s.symbol, 
     s.open, 
     s.high, 
     s.low, 
     s.close, 
     s.volume 
FROM  masterdate AS m LEFT OUTER JOIN 
     stockdata AS s ON m.date = s.date 
AND  s.symbol = @symbol 
WHERE m.date BETWEEN @mindate AND @maxdate 

Vous aurez aussi besoin d'être sûr que vous avez un index sur masterdate.date et un indice composite sur stockdata (date, symbole).

+0

22 secondes sur une base de données de 6 Go. Plus vite que je ne le pensais, mais pas là où j'en avais besoin. Je pense que si j'éclate les données, je peux ramener cela à quelque chose de bien mieux (j'ai actuellement tous les jours, intraday, stock, futures, index, nom, données dans un seul tableau). Merci beaucoup! – user119282

1

Si vous utilisez SQLServer, vous pouvez utiliser une procédure stockée TSQL pour récupérer vos résultats. Il aura essentiellement deux lignes:

1) Pour obtenir la première date pour les données disponibles 2) Une requête avec une jointure externe

Si vous utilisez Oracle, vous pouvez utiliser un PL/SQL pour écrire un similaire (bien qu'un peu plus compliqué) procédure stockée pour calculer la réponse que vous voulez.

3

Ceci est une gauche classique rejoindre:

SELECT * FROM masterdates 
    LEFT JOIN stockdata ON masterdates.date = stockdata.date;

Il est évident que cela doit être affiné pour retourner uniquement les colonnes requises.

+0

Mais ça va tout me donner dans Masterdates, non? – user119282

0

Je suggère de remplir les entrées manquantes de la table Stockdata et d'utiliser une jointure interne.Devrait être beaucoup plus rapide.

+0

Pouvez-vous s'il vous plaît expliquer un peu plus? – user35443