2017-02-16 98 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

你在'wHere'裏錯過了一個H – SqlZim

+0

要小心'between' [壞習慣踢:錯誤處理日期/範圍查詢 - Aaron Bertrand - 2009-10-16](http://sqlblog.com/ blog/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