I have a view that's something like
CREATE VIEW OrdersView WITH SCHEMABINDING AS
SELECT o.Id, o.OrderDate, o.LastName, o.TotalPrice, s.Status
FROM dbo.Orders o INNER JOIN dbo.OrderStatus s on o.Id = s.OrderId
WHERE NOT EXISTS (SELECT NULL from dbo.OrderStatus where OrderId = s.OrderId and StatusDate > s.StatusDate
AND EXISTS (SELECT NULL FROM dbo.OrderLineItemType1 WHERE OrderId = o.Id)
The intent is to fetch all orders that have at least one line item of type 1 along with their current status.
We're in the process of adding a second type of line item, and I have modified the view such that it will include orders that have at least one line item of type 1 or type 2:
CREATE VIEW OrdersView WITH SCHEMABINDING AS
SELECT o.Id, o.OrderDate, o.LastName, o.TotalPrice, s.Status
FROM dbo.Orders o INNER JOIN dbo.OrderStatus s on o.Id = s.OrderId
WHERE NOT EXISTS (SELECT NULL from dbo.OrderStatus where OrderId = s.OrderId and StatusDate > s.StatusDate
AND (EXISTS (SELECT NULL FROM dbo.OrderLineItemType1 WHERE OrderId = o.Id)
OR EXISTS (SELECT NULL FROM dbo.OrderLineItemType2 WHERE OrderId = o.Id))
Easy enough, but I've just had a requirement added to show whether an order contains line items of type 1 or type 2 (or both) in the grid where these results are displayed:
Order ID | T1 | T2 | Last name | Price | Status ============================================================ 12345 | x | | Smith | $100.00 | In Production 12346 | x | x | Jones | $147.23 | Part Dispatched 开发者_如何学C12347 | | x | Atwood | $12.50 | Dispatched
The only way I can think of is to do:
CREATE VIEW OrdersView WITH SCHEMABINDING AS
SELECT o.Id,
CASE WHEN EXISTS (SELECT NULL FROM dbo.OrderLineItemType1 WHERE OrderID = o.Id) THEN 1 ELSE 0 END AS HasType1,
CASE WHEN EXISTS (SELECT NULL FROM dbo.OrderLineItemType2 WHERE OrderId = o.ID) THEN 1 ELSE 0 END AS HasType2,
o.OrderDate, o.LastName, o.TotalPrice, s.Status
FROM dbo.Orders o INNER JOIN dbo.OrderStatus s on o.Id = s.OrderId
WHERE NOT EXISTS (SELECT NULL from dbo.OrderStatus where OrderId = s.OrderId and StatusDate > s.StatusDate
AND (EXISTS (SELECT NULL FROM dbo.OrderLineItemType1 WHERE OrderId = o.Id)
OR EXISTS (SELECT NULL FROM dbo.OrderLineItemType2 WHERE OrderId = o.Id))
But this smells wrong with the duplication of the EXISTS
clauses. Is there a better qway to write it? Can I make it perform better?
you can LEFT JOIN on OrderLineItemType1 and OrderLineItemType2 and then filter out rows where both of those columns are NULL in the WHERE clause.
One change that may be worth profiling (but not directly related to your specific question).
The following two lines:
FROM dbo.Orders o INNER JOIN dbo.OrderStatus s on o.Id = s.OrderId
WHERE NOT EXISTS (SELECT NULL from dbo.OrderStatus where OrderId = s.OrderId and StatusDate > s.StatusDate
It may be better to write this as:
FROM dbo.Orders o INNER JOIN dbo.OrderStatus s on o.Id = s.OrderId
LEFT JOIN dbo.OrderStatus s_later on o.Id = s_later.OrderId and s_later.StatusDate > s.StatusDate
WHERE s_later.OrderId is null
I usually find that this performs better (but it's one of those that it's worth profiling both ways).
The LEFT JOIN tries to find later rows that apply to the same order, then the WHERE clause rejects any potential result rows where such a match occurred - so the only matching row from s must be the latest one for this order.
You don't need EXISTS
here at all:
SELECT o.Id, HasType1, HasType2, o.OrderDate, o.LastName, o.TotalPrice, s.Status
FROM dbo.Orders o
CROSS APPLY
(
SELECT TOP 1 s.*
FROM dbo.OrderStatus
WHERE OrderId = o.Id
ORDER BY
StatusDate DESC
) s
OUTER APPLY
(
SELECT TOP 1 1 AS HasType1
FROM dbo.OrderLineItemType1
WHERE OrderID = o.Id
) olt1
OUTER APPLY
(
SELECT TOP 1 1 AS HasType2
FROM dbo.OrderLineItemType2
WHERE OrderID = o.Id
) olt2
精彩评论