Sql Server — Объединение подзапросов с использованием вычисляемых полей

#sql #sql-server #tsql

#sql #sql-сервер #tsql

Вопрос:

Я пытаюсь рассчитать процентное изменение цены между днями. Поскольку дни не являются последовательными, я встраиваю в запрос вычисляемое поле, которое сообщает мне, какой сегодня относительный день (день 1, день 2 и т.д.). Чтобы сравнить сегодняшний день со вчерашним, я изменил номер вычисляемого дня на 1 в подзапросе. что я хочу сделать, так это объединить внутренний и внешний запрос в расчетный относительный день. Код, который я придумал, является:

 SELECT TOP 11 
       P.Date,
       (AVG(P.SettlementPri) - PriceY) / PriceY as PriceChange, 
       P.Symbol,
       (RANK() OVER (ORDER BY P.Date desc)) as dayrank_Today
FROM OTE P
  JOIN (SELECT TOP 11 
               C.Date, 
               AVG(SettlementPri) as PriceY, 
               (RANK() OVER (ORDER BY C.Date desc)) 1 as dayrank_Yest
          FROM OTE C
         WHERE C.ComCode = 'C-' 
      GROUP BY c.Date) C ON dayrank_Today = C.dayrank_Yest
WHERE P.ComCode = 'C-' 
GROUP BY P.Symbol, P.Date 
  

Если я пытаюсь выполнить запрос, я получаю сообщение об ошибке, указывающее, что dayrank_Today является недопустимым столбцом. Я пытался переименовать его, квалифицировать, выкрикивать оскорбления в его адрес, и я приседаю. Все еще ошибка.

Комментарии:

1. какую базу данных вы используете? sql server?

2. Немного сложно понять ваш вопрос. Можете ли вы предоставить нам структуру таблицы (только соответствующие поля), входные данные, желаемый результат запроса? В идеале вам нужно предоставить скрипт, который создает таблицы и заполняет их образцами данных.

3. @M.R.: TOP является SQL Server; RANK означает SQL Server 2005

4. AVG(P.SettlementPri) это среднее значение по Symbol amp; Date , но PriceY это среднее значение только по Date . Правильно ли это для сравнения двух? Это не ошибка?

Ответ №1:

Вы не можете выполнить выбор вычисляемого столбца, а затем использовать его в объединении. Вы можете использовать CTE, с которыми я не очень знаком, или вы можете просто выполнять выбор таблицы следующим образом:

 
SELECT 
     P.Date,       
     (AVG(AvgPrice) - C.PriceY) / C.PriceY as PriceChange, 
     P.Symbol,       
     P.dayrank_Today FROM
(SELECT TOP 11 
       ComCode,
       Date,
       AVG(SettlementPri) as AvgPrice,
       Symbol,
       (RANK() OVER (ORDER BY Date desc)) as dayrank_Today
FROM OTE WHERE ComCode = 'C-') P 
  JOIN (SELECT TOP 11 
               C.Date, 
               AVG(SettlementPri) as PriceY, 
               (RANK() OVER (ORDER BY C.Date desc)) 1 as dayrank_Yest
          FROM OTE C
         WHERE C.ComCode = 'C-' 
      GROUP BY c.Date) C ON dayrank_Today = C.dayrank_Yest 
GROUP BY P.Symbol, P.Date 

  

Комментарии:

1. M.R. Спасибо за быстрый ответ. Я попробовал ваш код, но, к сожалению, получаю сообщение об ошибке, в котором говорится, что цена не может быть привязана.

2. M.R. Я новичок в использовании Stackoverflow, поэтому я немного улучшаю ситуацию. Я предоставил дополнительную информацию о моем редактировании вашего ответа. Если это неправильный способ сделать что-то, просто дайте мне знать.

3. @GoingBaldBySql — было бы лучше обновить ваш вопрос, а не редактировать этот ответ. Однако не удаляйте существующий код и не давайте понять, что вы отвечаете на этот ответ.

4. @GoingBalBySql: Можете ли вы сказать мне, какая из дорогих привязок не выполняется? Скорее всего, я неправильно понял имена ваших полей … Т.Е. принадлежит ли PriceY таблице OTEИЛИ ее выделенному столбцу во второй таблице select?

5. @andriy M: правильно — @goingBaldBySql, вы должны добавить ‘group by’ к обоим подвыборкам..

Ответ №2:

Если возможно, рассмотрите возможность использования CTE, поскольку это очень упрощает задачу. Что-то вроде этого:

 With Raw as
(
    SELECT TOP 11 C.Date,
    Avg(SettlementPri) As PriceY,
    Rank() OVER (ORDER BY C.Date desc) as dayrank
    FROM OTE C WHERE C.Comcode = 'C-'
    Group by C.Date
) 

select today.pricey as todayprice ,
yesterday.pricey as yesterdayprice,
(today.pricey - yesterday.pricey)/today.pricey * 100 as percentchange 
from Raw today
left outer join Raw yesterday on today.dayrank = yesterday.dayrank   1
  

Очевидно, что это не включает символ, но его можно включить довольно легко.
Если использование синтаксиса ‘With’ не подходит, вы также можете использовать вычисляемые поля с внешним Applyhttp://technet.microsoft.com/en-us/library/ms175156.aspx

Хотя CTE будет означать, что вам нужно будет написать расчет цены только один раз, что намного чище

Приветствия

Ответ №3:

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

Вместо того, чтобы использовать имя столбца в качестве параметра для ON, скопируйте инструкцию, которая в первую очередь присвоила вам имя colmun:

заменить:

 ON dayrank_Today = C.dayrank_Yest
  

с:

 ON (RANK() OVER (ORDER BY Date desc)) = C.dayrank_Yest 
  

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