Hi,
I have been designing a view in Oracle that is then used by Crystal reports. This view is becoming more and more complex and I have eventually hit a problem that, hopefully, somebody can help me out with.
Simplified, the problem is with one of the tables used in the main view. It shows a record of sales for each property on the system. However, sales may be cancelled and then re-sold. Thus, the Sales Table includes a column holding the Sale sequence number.
My problem results from a procedure change by the system users. The 3rd party system will not allow the amendment of the reservation and cancellation dates (and other important data) once the sale has been cancelled. Occasionally, users have cancelled a sale which contained incorrect data. This causes problems in a raft of other reports we have designed. (e.g. when the reservation date of the subsequent sale precedes the cancellation date of the previous sale because the latter date was input incorrectly.)
The users have decided that they will use another column on the Sales table, the “Cancellation Reason” code, to flag these rows as “Cancellation Due To Administrative Error” (Code = 998). After changing the code to 998, the users will then go on to re-create and re-cancel the Sale with the correct dates, etc. We have been told to completely ignore any rows with a cancellation reason code of 998.
The view that I am having problems with, requires rows that have an effective start date equal to when the current sale was reserved and an effective end date equal to when the next sale was reserved. Previously I declared the Sales Table under two separate aliases and joined them by ( NextSale.Sequence = (ThisSale.Sequence + 1) )
Of course, since the introduction of “rows to ignore”, the solution is now not so simple. I have tried to break the problem down into a hierarchical set of two views. I firstly designed the child view as follows (considerably simplified for the example):
CREATE OR REPLACE VIEW SalesView
AS
SELECT
Sales.PlotRef,
( SELECT
COUNT(*)
FROM
Sales Sales2
WHERE
( Sales2. PlotRef = Sales1. PlotRef
AND
Sales2. Sequence < Sales1. Sequence
AND
Sales2. CancelReason <> '998'
)
)
Sales.Sequence,
.
.
FROM
Sales
WHERE
Sales2. CancelReason <> '998'
This view excludes all the Sales rows that have been cancelled due to Admin Error and re-sequences the Sales records for each plot. (i.e. the sequence numbers will still be contiguous, even if an “Admin Error” row has been excluded.) Running a query on this view suggests that it is working correctly. (i.e. the number of rows in the base Sales table minus the “Cancellation Code = ‘998’” rows.
In the parent view, I then declare this child view twice to allow me to join each sales row to its successor. Again, I have considerably simplified the view for this example:
SELECT
<View Fields>
FROM
SalesView ThisSale,
SalesView NextSale
WHERE
( NextSale.PlotRef (+) = Sales.PlotRef
AND
( NextSale.Sequence (+) = (ThisSale.Sequence + 1) )
)
The left outer join here is because for each plot there will be at least one sales row (the most recent) that has no successor. I use an NVL function to generate “high values” effective end date in this case.
Theoretically, I should get the same number rows in this view as the number of non-998 rows in the base Sales table. However, I only seem to be getting rows where there is an actual successor to the Sales record. (i.e. where the plot has been legitimately cancelled and resold.) This suggests to me that the Left Outer Join, as shown above, is still acting as a standard Inner Join.
I hope that somebody can help me out here. Hopefully, it is a simple oversight but, if not, perhaps somebody can suggest an alternate strategy?
Many thanks for any help.
Regards,
Harry.
I have been designing a view in Oracle that is then used by Crystal reports. This view is becoming more and more complex and I have eventually hit a problem that, hopefully, somebody can help me out with.
Simplified, the problem is with one of the tables used in the main view. It shows a record of sales for each property on the system. However, sales may be cancelled and then re-sold. Thus, the Sales Table includes a column holding the Sale sequence number.
My problem results from a procedure change by the system users. The 3rd party system will not allow the amendment of the reservation and cancellation dates (and other important data) once the sale has been cancelled. Occasionally, users have cancelled a sale which contained incorrect data. This causes problems in a raft of other reports we have designed. (e.g. when the reservation date of the subsequent sale precedes the cancellation date of the previous sale because the latter date was input incorrectly.)
The users have decided that they will use another column on the Sales table, the “Cancellation Reason” code, to flag these rows as “Cancellation Due To Administrative Error” (Code = 998). After changing the code to 998, the users will then go on to re-create and re-cancel the Sale with the correct dates, etc. We have been told to completely ignore any rows with a cancellation reason code of 998.
The view that I am having problems with, requires rows that have an effective start date equal to when the current sale was reserved and an effective end date equal to when the next sale was reserved. Previously I declared the Sales Table under two separate aliases and joined them by ( NextSale.Sequence = (ThisSale.Sequence + 1) )
Of course, since the introduction of “rows to ignore”, the solution is now not so simple. I have tried to break the problem down into a hierarchical set of two views. I firstly designed the child view as follows (considerably simplified for the example):
CREATE OR REPLACE VIEW SalesView
AS
SELECT
Sales.PlotRef,
( SELECT
COUNT(*)
FROM
Sales Sales2
WHERE
( Sales2. PlotRef = Sales1. PlotRef
AND
Sales2. Sequence < Sales1. Sequence
AND
Sales2. CancelReason <> '998'
)
)
Sales.Sequence,
.
.
FROM
Sales
WHERE
Sales2. CancelReason <> '998'
This view excludes all the Sales rows that have been cancelled due to Admin Error and re-sequences the Sales records for each plot. (i.e. the sequence numbers will still be contiguous, even if an “Admin Error” row has been excluded.) Running a query on this view suggests that it is working correctly. (i.e. the number of rows in the base Sales table minus the “Cancellation Code = ‘998’” rows.
In the parent view, I then declare this child view twice to allow me to join each sales row to its successor. Again, I have considerably simplified the view for this example:
SELECT
<View Fields>
FROM
SalesView ThisSale,
SalesView NextSale
WHERE
( NextSale.PlotRef (+) = Sales.PlotRef
AND
( NextSale.Sequence (+) = (ThisSale.Sequence + 1) )
)
The left outer join here is because for each plot there will be at least one sales row (the most recent) that has no successor. I use an NVL function to generate “high values” effective end date in this case.
Theoretically, I should get the same number rows in this view as the number of non-998 rows in the base Sales table. However, I only seem to be getting rows where there is an actual successor to the Sales record. (i.e. where the plot has been legitimately cancelled and resold.) This suggests to me that the Left Outer Join, as shown above, is still acting as a standard Inner Join.
I hope that somebody can help me out here. Hopefully, it is a simple oversight but, if not, perhaps somebody can suggest an alternate strategy?
Many thanks for any help.
Regards,
Harry.