为什么我的 T-SQL 查询返回不一致的输出?

Why is my T-SQL Query returning inconsistent output?

我正在使用 SQL Server 2014 并且我有以下 T-SQL 查询:

USE MyDatabase
GO

SELECT 
    a.ReservationStayID
    ,c.PMSConfirmationNumber
    ,c.[PropertyCode]
    ,a.StayDate
    ,c.[MTH]
    ,1 AS 'RN'
    ,a.PackagePlanCode
    ,c.[Market Segment Code]
    ,c.[Status]
    ,c.[CurrencyCode]
    ,a.RateAmount
    ,SUM(a.RateAmount) OVER (PARTITION BY a.ReservationStayID) AS 'CUM_Rate'
    ,d.[Exchange Rate]
    ,((a.RateAmount * d.[Exchange Rate]) / 1.15) AS 'Package Revenue Excl VAT'
    ,c.[Tour Operator]
    ,c.[Group Booking ID]
    ,c.[Source of Business]
    ,c.[Booking Origin (1)]
    ,c.[Market FINAL]
    ,ISNULL(ay.[KeyAccountName], 'NA') AS 'Key A/c'
    ,c.[CreatedOn_RSD]
FROM 
    ReservationStayDate a
INNER JOIN 
    [RESERVATIONLIST(2)] c ON c.[ReservationStayID] = a.ReservationStayID
                           AND c.[MTH] = datename(m, StayDate) + ' ' + cast(datepart(yyyy, StayDate) AS VARCHAR)
INNER JOIN 
    [PKGREVENUE] d ON d.[ReservationStayID] = a.ReservationStayID
                   AND d.[StayDate] = a.StayDate
ORDER BY 
    a.ReservationStayID;

查询运行没问题,但输出不一致!有时,我会得到 698,017 行,然后如果我 运行 立即再次查询,我可能会得到 698,020。另一次尝试显示 698,025。

这让我抓狂,因为我的数据库还没有更新。 SAME 查询 运行 每隔 1 分钟进行一次,并且每个 运行 都在记录数量方面提供不一致的输出!是什么导致了这种行为?

我不知道这些附加信息是否有帮助:

当我 运行 上面的查询 "as is" 时,它给了我 4 条 ReservationStayID = 147469 的记录。

然后我将以下行作为过滤器添加到上面的查询中:

WHERE a.ReservationStayID = 147469

令人惊讶的是,我只有 2 行!

[ReservationList(2)][PKGREVENUE] 是浏览量。

这里有 2 个被喜爱的视图:

视图 1:

CREATE VIEW [RESERVATIONLIST(2)] AS

SELECT 
   x.[ReservationStayID],
   b.PropertyCode,
   c.CreatedOn,
   c.CreatedBy,
   c.UpdatedBy,
   c.UpdatedOn,
   xy.Rooms AS [Room Inventory], --added
   (xy.Rooms*[DaysInMonth]) AS [RNAvailable], --added
   (x.[Nights Spent]/(xy.Rooms*[DaysInMonth])) AS [Occupancy],
   c.PMSConfirmationNumber,
   a.ArrivalDate AS [Arrival Date],
   a.DepartureDate AS [Departure Date],
   (a.ArrivalDate - CONVERT(Varchar(10),(CAST(x.CreatedOn as DATE)),(101))) AS 'Booking Lead Time',
    a.FirstName + ' ' + a.LastName AS 'Name',
    j.ProfileID,
    j.EmailAddress AS 'Email',
    b.MarketSegmentCode AS 'Market Segment Code',
    a.DateOfBirth AS 'Date of Birth',
    b.ReservationStatus AS 'Status',
    j.Nationality AS 'Nationality',
    k.[Country of Residence],
    ISNULL(g3.CountryGroup2, 'Not Specified') AS 'Country of Residence 2', 
     c.ReasonForStayCode AS 'Reason For Stay',
     b.RateplanCode,
     x.[Rate Plan RSD] AS 'Rate Plan Code',
     x.[Room Type RSD] AS 'Room Type',
     i.RoomType3 AS 'Room Type 3', -- this code converts the Room Type as per Room Type codes used in the Budget
     al.NonRoombundleID,
     k3.MpDescription AS 'Meal Plan Description',
     ISNULL(k3.MpCode,'RO') AS 'Meal Plan Code',
     x.[Adult RSD] AS 'Adult',
     x.[Child RSD] AS 'Child',
     b.GuestCount AS 'Total Guest',
     x.[Nights Spent] AS 'Room Nights',
     x.[MTH],
     x.[DaysInMonth], --added
     x.[Rate] AS 'Room Rate WITH VAT',
     c.CurrencyCode, 
     y.[Pkg Rev (with VAT)],
     y.[Pkg Rev (excl VAT)], 
    x.CreatedOn AS [CreatedOn_RSD],
    CONVERT(Varchar(10),(CAST(x.CreatedOn as DATE)),(101)) as [DATE CREATED ON],
    datename(m,x.CreatedOn) + ' ' + cast(datepart(yyyy,x.CreatedOn) as varchar) as [Created On (MTH)],
    x.[DateOfArrival],
    x.[DateOfDeparture],
    e.TravelAgencyTypeCode AS 'Source of Business',
    c.TAProfileID,
    c.PropGroupBookingID AS 'Group Booking ID', 
    e.Name AS 'Tour Operator', 
    g.CountryGroup AS 'Market', 
    c.TAProfileID2, 
    e2.Name AS 'Booking Origin (1)',
   g2.CountryGroup AS 'Booking Origin (2)', 

   (CASE
     WHEN e.TravelAgencyTypeCode = 'DMC' 
     THEN g2.CountryGroup 
     ELSE g.CountryGroup 
      END) AS 'Market (DMC Classified)',

   (CASE
     WHEN e.TravelAgencyTypeCode = 'DMC' THEN g2.CountryGroup
    WHEN c.TAProfileID = '316' AND c.CurrencyCode = 'MUR' THEN 'DB Local'
    WHEN c.TAProfileID = '316' THEN 'DB International'
    ELSE g.CountryGroup
    END) AS 'Market FINAL'

   FROM GuestNameInfo a

  JOIN GuestStaySummary b ON a.ReservationStayID = b.ReservationStayID
  LEFT JOIN ReservationStay c ON c.ReservationStayID =   b.ReservationStayID
  LEFT JOIN TravelAgency e ON e.TravelAgencyID = c.TAProfileID 
 LEFT JOIN Market g ON e.CountryCode = g.CountryCode
 LEFT JOIN TravelAgency e2 ON e2.TravelAgencyID = c.TAProfileID2
 LEFT JOIN Market g2 ON e2.CountryCode = g2.CountryCode

 LEFT JOIN CtyRes h ON h.ReservationStayID = a.ReservationStayID
 LEFT JOIN Market g3 ON g3.CountryCode = h.CountryCode

 LEFT JOIN Profile j ON j.ProfileID = c.ProfileID
 LEFT JOIN HotelInventory xy ON xy.PropertyCode = b.PropertyCode 



 LEFT JOIN
 (
    SELECT 
    min(CountryCode) AS [Country of Residence]
   , min(ProfileID) AS [Profile ID]
   ,min(PostalAddressID) AS [Postal Address ID]

   FROM PostalAddress
   GROUP BY CountryCode,ProfileID,PostalAddressID
  ) k ON k.[Postal Address ID] = c.PostalAddressID


 LEFT JOIN
  (
   SELECT 
     ReservationStayID,
     datename(m,StayDate) + ' ' + cast(datepart(yyyy,StayDate) as varchar) as [MTH],
     datediff(day, dateadd(day, 1-day(StayDate), StayDate),
          dateadd(month, 1, dateadd(day, 1-day(StayDate), StayDate))) AS [DaysInMonth],
     min(adultcount) as 'Adult RSD',
     min(childcount) as 'Child RSD',
     min(RoomTypeCode) AS 'Room Type RSD',
     min(PackagePlanCode) AS 'Rate Plan RSD',
     count(*) AS [Nights Spent],
     avg(RateAmount) as [Rate],
     min(CreatedOn) as CreatedOn,
     min(StayDate) as [DateOfArrival],
     max(StayDate) as [DateOfDeparture]
    FROM ReservationStayDate
    GROUP BY ReservationStayID, datename(m,StayDate) + ' ' +  cast(datepart(yyyy,StayDate) as varchar), datediff(day, dateadd(day, 1-day(StayDate), StayDate),
          dateadd(month, 1, dateadd(day, 1-day(StayDate), StayDate)))
 ) x ON x.ReservationStayID = b.ReservationStayID

 LEFT JOIN RoomCat i ON b.PropertyCode = i.Property AND [Room Type RSD] = i.RoomType


   LEFT JOIN

    (SELECT datename(m,StayDate) + ' ' + cast(datepart(yyyy,StayDate) as varchar) AS [MTH_PKGREV],
       [ReservationStayId], SUM([Package Revenue with VAT]) AS 'Pkg Rev (with VAT)',
       SUM([Package Revenue excl VAT]) AS 'Pkg Rev (excl VAT)'

   FROM PKGREVENUE

   GROUP BY datename(m,StayDate) + ' ' + cast(datepart(yyyy,StayDate) as varchar),[ReservationStayId]


   ) y ON y.[ReservationStayId] = b.ReservationStayID AND [MTH] = datename(m,[MTH_PKGREV]) + ' ' + cast(datepart(yyyy,[MTH_PKGREV]) as varchar)


  LEFT JOIN
   (
  SELECT ReservationStayID, MTH, NonRoombundleID

  FROM NONROOMBUNDLEID

  group by ReservationStayID, MTH, NonRoombundleID

  )al ON al.ReservationStayID = x.ReservationStayID AND al.[MTH] = x.[MTH]

  LEFT JOIN NonRoomBundle k2 ON K2.NonRoomBundleID = al.NonRoombundleID

  LEFT JOIN MealPlan k3 ON k3.MpDescription = k2.Description


  WHERE a.PrimaryGuest = '+'

视图 2:

CREATE VIEW [PKGREVENUE] AS

SELECT
  ReservationStayDate.ReservationStayID AS [ReservationStayId]
  ,ReservationStay.PMSConfirmationNumber AS [PmsConfirmationNumber]
  ,ReservationStayDate.StayDate AS [StayDate]
  ,ReservationStayDate.RateAmount AS [RateAmount]
  ,ReservationStay.CurrencyCode AS [CurrencyCode]
  ,CAST(ROUND(ISNULL((1/CA.SellRate),1),2) as numeric (36,2)) AS 'Exchange Rate' -- since MUR is not in the Exchange Rate Table, this replaces all NULL values for MUR by 1.00

  ,CAST(ROUND(ReservationStayDate.RateAmount * ISNULL((1/CA.SellRate),1),0) as numeric (36,0)) AS 'Package Revenue with VAT'

  ,(CAST(ROUND(ReservationStayDate.RateAmount * ISNULL((1/CA.SellRate),1),0)/1.15 as numeric (36,0))) AS 'Package Revenue excl VAT'

FROM
  ReservationStayDate
  INNER JOIN ReservationStay ON ReservationStay.ReservationStayID = ReservationStayDate.ReservationStayID

  OUTER APPLY
  (
     SELECT TOP(1) ExchangeRate.SellRate
     FROM ExchangeRate
     WHERE
       ExchangeRate.ToCurrencyCode = ReservationStay.CurrencyCode
       AND ExchangeRate.EffectiveDate <= ReservationStayDate.StayDate
      ORDER BY ExchangeRate.EffectiveDate DESC
  ) AS CA

并非 Sql 服务器中的所有函数都是确定性的。查看 Deterministic and Nondeterministic Functions

我在您的查询中没有看到任何非确定性的内容,但您可能想查看您加入的视图并确保非确定性列表中没有任何内容。

感谢所有为我的问题提供帮助的人。我什至得到了否定,我不知道为什么! 无论如何,我想在这里提供有关我如何解决问题的更新。正如你们中的一些人所建议的,我深入研究了确定性和非确定性函数。但是,我无法在我的查询和视图中找到导致主查询行为异常并给出不一致结果的任何此类函数。

我在主查询中尝试了 GROUP BY 子句(尽管我不需要该子句)。看,问题解决了!!现在,我的查询在每次尝试时都会给我相同数量的记录。至于为什么 GROUP BY 子句解决了问题,我完全不知道。只是想在这里与社区分享。可能有人可以阐明 GROUP BY 子句的神奇力量! :-)

当在包含以下内容的语句中 mixed-up 或不一致地使用别名时,总是会发生这种情况:

1-order by
2-group by
3-where clauses

像这一行:

GROUP BY datename(m,StayDate) + ' ' + cast(datepart(yyyy,StayDate)

可能字段 StayDate 存在于查询的不同部分。有时优化器采用不同的路径并选择其他字段。别名指示优化器始终采用正确的字段。