Сложный (?) SQL-запрос на соединение - PullRequest
2 голосов
/ 14 июня 2009

У меня есть 2 таблицы:

1) таблица Masterdates, которая содержит все даты с 1 января 1900 года

2) таблица Stockdata, которая содержит данные о запасах в форме дата, символ, открытие, максимум, минимум, закрытие, объем (первичный ключ = дата, символ)

Это то, что я хочу получить (представлено здесь в формате CSV)

MDate, SDATE, Symbol, 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, ...

где MDate от Masterdates, а SDate от Stockdata. Мне нужно, чтобы вывод начинался с первой (самой ранней) даты экстента для нужного символа (в этом примере Foo, начиная с 04.06.2001) в Stockdata, а затем включал все даты в Masterdates вплоть до последней включительно. (последняя) доступная дата для требуемого символа в Stockdata с выводом значений NULL, где нет соответствующей записи Stockdata для данной записи Masterdate в указанном диапазоне.

Есть ли способ сделать это в одном запросе, серии запросов и / или путем добавления вспомогательных таблиц, которые дадут быстрые результаты? Или мне придется выгрузить надмножества того, что я хочу, и затем создать окончательный вывод, используя мой (не SQL) язык программирования?

ТИА

Ответы [ 4 ]

7 голосов
/ 14 июня 2009

Протестировано в SQLITE3, реализация вашей БД может отличаться

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')

Если это не выполняется достаточно быстро, вы можете заметно улучшить производительность, задав переменные для минимального и максимального значения в одном запросе, а затем используя их в основном запросе. Это спасет вас как минимум от одного попадания в индекс.

Итак (в синтаксисе 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

Вы также должны быть уверены, что у вас есть индекс на masterdate.date и составной индекс на stockdata (дата, символ).

3 голосов
/ 14 июня 2009

Это классическое левое соединение:

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

Очевидно, что это должно быть уточнено, чтобы вернуть только необходимые столбцы.

1 голос
/ 14 июня 2009

Если вы используете SQLServer, вы можете использовать хранимую процедуру TSQL, чтобы получить свои результаты обратно. В основном это будет две строки:

1) Чтобы получить первую дату для доступных данных 2) Запрос с внешним объединением

Если вы используете Oracle, вы можете использовать PL / SQL для написания аналогичной (хотя и несколько более сложной) хранимой процедуры для вычисления нужного ответа.

0 голосов
/ 24 января 2010

Я бы предложил заполнить недостающие записи из таблицы Stockdata и использовать внутреннее соединение. Должно быть намного быстрее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...