2017-02-16 4 views
0

Я конвертирую некоторый код из Oracle в SQL Server (2012) и столкнулся с проблемой, когда этот подзапрос использует PARTITION/ORDER BY для извлечения самой последней записи , Подзапрос прекрасно работает сам по себе, но, как это подзапрос, я получаю сообщение об ошибке:Найти самую последнюю запись в подзапросе (SQL Server)

SQL Server Database Error: The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP, OFFSET or FOR XML is also specified.

Вот часть SQL:

FROM (
    SELECT distinct enr.MemberNum, 
    (ISNULL(enr.MemberFirstName, '') + ' ' + ISNULL(enr.MemberLastName, '')) AS MEMBER_NAME, 
    enr.MemberBirthDate as DOB, 
    enr.MemberGender as Gender, 
    LAST_VALUE(enr.MemberCurrentAge) OVER (PARTITION BY MemberNum ORDER BY StaticDate ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS AGE, 
    LAST_VALUE(enr.EligStateAidCategory)OVER (PARTITION BY MemberNum ORDER BY StaticDate ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS EligStateAidCategory, 
    LAST_VALUE(enr.EligStateAidCategory)OVER (PARTITION BY MemberNum ORDER BY StaticDate ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS AID_CAT_ROLL_UP, 
    LAST_VALUE(enr.EligFinanceAidCategoryRollup)OVER (PARTITION BY MemberNum ORDER BY StaticDate ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS EligFinanceAidCategoryRollup, 
    SUM(enr.MemberMonth) OVER (PARTITION BY MemberNum) AS TOTAL_MEMBER_MONTHS 
    FROM dv_Enrollment enr 
    WHERE enr.StaticDate BETWEEN '01-JUN-2016' AND '30-JUN-2016' 
)A 

Итак, я посмотрел вокруг и обнаружил, что вы можете использовать TOP (2147483647) хак, так что я попытался изменить первую строку:

SELECT distinct TOP (2147483647) enr.MemberNum, 

Но я все еще получаю ту же ошибку. Все другие способы, о которых я думал, также требуют ORDER BY (с использованием DENSE RANK и т. Д.).

+4

Я не вижу в заказе 'order by'. можете ли вы опубликовать полный текст запроса? –

+0

вам не хватает H в 'wHere' – SqlZim

+0

будьте осторожны с' between' [Плохие привычки к удару: неверная обработка даты/диапазона запросов - Aaron Bertrand - 2009-10-16] (http://sqlblog.com/ блоги/aaron_bertrand/archive/2009/10/16/bad-habits-to-kick-mishandling-date-range-queries.aspx) – SqlZim

ответ

2

В обеих базах данных, я хотел бы написать это как:

FROM (SELECT enr.MemberNum, 
      (ISNULL(enr.MemberFirstName, '') + ' ' + ISNULL(enr.MemberLastName, '')) AS MEMBER_NAME, 
      enr.MemberBirthDate as DOB, 
      enr.MemberGender as Gender, 
      MAX(CASE WHEN seqnum = 1 THEN enr.MemberCurrentAge END) AS AGE, 
      MAX(CASE WHEN seqnum = 1 THEN enr.EligStateAidCategory END) AS EligStateAidCategory, 
      MAX(CASE WHEN seqnum = 1 THEN enr.EligStateAidCategory END) AS AID_CAT_ROLL_UP, 
      MAX(CASE WHEN seqnum = 1 THEN enr.EligFinanceAidCategoryRollup END) AS EligFinanceAidCategoryRollup, 
      SUM(enr.MemberMonth) as TOTAL_MEMBER_MONTHS 
    FROM (SELECT enr.*, 
       ROW_NUMBER() OVER (PARTITION BY MemberNum ORDER BY StaticDate DESC) as seqnum 
      FROM dv_Enrollment enr 
     ) enr 
    WHERE enr.StaticDate >= DATE '2016-06-01' AND -- DATE not needed in SQL Server 
      enr.StaticDate < DATE '2016-07-01'  -- DATE not needed in SQL Server 
    GROUP BY enr.MemberNum, enr.MemberFirstName, enr.MemberLastName, 
      enr.MemberBirthDate, enr.MemberGender 
    ) A 

Почему изменения?

  • Изменения даты предназначены только для того, чтобы быть осторожными относительно компонентов времени на дату. BETWEEN с датой/временем - это плохая привычка, потому что иногда это может привести к неправильному коду и трудно отлаживать ошибки.
  • Мне просто не нравится использовать SELECT DISTINCT для обозначения GROUP BY. Умно использовать его с функциями окна (и необходимо с LAST_VALUE()), но я думаю, что код в конечном итоге вводит в заблуждение.
  • Я нахожу использование подзапроса с seqnum, чтобы было ясно, что четыре переменные «последнего значения» все тяговые данные из последней строки.
  • Кроме того, вид не является стабильным (то есть, ключ не является уникальным), seqnum гарантирует, что значения все из того же ряда. last_value() не.
+0

Очень приятно, а тем более переписывать по сравнению с моим подходом. +1 – SqlZim

0

Переключить это на общий подзапрос и cross apply() и посмотреть, что произойдет.

select 
    e.MemberNum 
    , e.MemberName 
    , e.DOB 
    , e.Gender 
    , x.MemberCurrentAge 
    , x.EligStateAidCategory 
    , x.EligFinanceAidCategoryRollup 
    , x.MemberMonth 
    , e.Total_Member_Months 
from (
    select 
     enr.MemberNum 
     , MemberName = isnull(enr.MemberFirstName+' ', '') + isnull(enr.MemberLastName, '') 
     , DOB = enr.MemberBirthDate 
     , Gender = enr.MemberGender 
     /* This sounds like a weird thing to sum */ 
     , Total_Member_Months = sum(enr.MemberMonth) 
    from dv_Enrollment enr 
    group by 
     enr.MemberNum 
     , isnull(enr.MemberFirstName+' ', '') + isnull(enr.MemberLastName, '') 
     , enr.MemberBirthDate 
     , enr.MemberGender 
    ) as e 
    /* cross apply() is like an inner join 
    , use outer apply() for something like a left join */ 
    cross apply (
    select top 1 
     i.MemberCurrentAge 
     , i.EligStateAidCategory 
     , i.EligFinanceAidCategoryRollup 
     , i.MemberMonth 
     from dv_Enrollment as i 
     where i.MemberNum = e.MemberNum 
     and i.StaticDate >= '20160601' 
     and i.StatisDate <= '20160630' 
     order by i.StaticDate desc -- descending for most recent 
    ) as x 
Смежные вопросы