I have a simple structure where I am not sure how to handle some of the issues that pop up.
There are 4 tables: Reports
, ReportParameters
, ScheduledReports
, ScheduledReportParameters
.
ReportParameters
lists the needed parameters for the reports.
ScheduledReports
is a scheduled instance of a report. (Report X to run on Thursday as an example).
ScheduledReportParameters
is the list of parameters and their values to use when this instance runs.
Basic layout:
Reports:
ReportID (PK)
ReportParameters:
ReportParameterID (PK)
ReportID (FK to Reports)
Name
ScheduledReports:
ScheduledReportID (PK)
ReportID (FK to reports)
ScheduledReportParameters:
ScheduledReportID (FK to ScheduledReports)
ReportParameterID (FK to ReportParameters)
Value
(PK is formed by the ScheduledReportID and ReportParameterID)
This has the issue where the parameter associated with a scheduled report doesn't have to agree with what the base report actually expects, it could be to a different base report entirely and not the report the scheduled report is based off of.
So, I thought I could add the ReportID
to the ScheduledReportParameters
, but that doesn't help as there wouldn't be anything enforcing that the ReportID
there agrees with what the ScheduledReport
is based off of.
Am I missing something simple? Or, is this trickier than I had thought?
Having a scheduled report with parameters that don't actually go with the report isn't a big deal to me as when I pull them, the joins will automatically filter out any potential bad ones but I would like to prevent bad data going in the first place. I know I could use triggers to do this, but that can get ugly quickly.
Best Answer
It looks like you are not aware that foreign key can be based on several columns.
So, yes, add a column
ReportID
toScheduledReportParameters
and include it in two foreign keys to enforce the constraints.One foreign key between
ScheduledReportParameters
andScheduledReports
using two fields(ScheduledReportID, ReportID)
.Second foreign key between
ScheduledReportParameters
andReportParameters
using two fields(ReportParameterID, ReportID)
.Full script
Reports
ReportParameters
ScheduledReports
ScheduledReportParameters
It is necessary to have unique index on two columns that are used by the foreign key. I added explicit indexes in this example (
IX_ReportParameterID_ReportID
andIX_ScheduledReportID_ReportID
). You can also add the second column into the primary key of the corresponding table.Sample data
Testing constraints
Add parameter values for report 1:
Try to add value for the parameter that doesn't belong to the report (parameter 3 belongs to report 2, not 1:
Try to add parameter value for the wrong scheduled report (while parameter 3 belongs to report 2, schedule 1 is not for report 2):
Missing parameter values
Please note, that this schema doesn't prevent missing values for parameters. For example, you can delete value
V2
:Thus now the schedule
S1
has value only for parameterP1
and doesn't have value for parameterP2
.