public ReleaseIdentifierSubstitution(MemoryRepository repo, IColumn extractionIdentifierToSubFor, IExtractableCohort extractableCohort, bool isPartOfMultiCHISubstitution, IQuerySyntaxHelper querySyntaxHelper) : base(repo)
        {
            if (!extractionIdentifierToSubFor.IsExtractionIdentifier)
            {
                throw new Exception("Column " + extractionIdentifierToSubFor + " is not marked IsExtractionIdentifier so cannot be substituted for a ReleaseIdentifier");
            }

            OriginalDatasetColumn   = extractionIdentifierToSubFor;
            this._querySyntaxHelper = querySyntaxHelper;
            if (OriginalDatasetColumn.ColumnInfo == null)
            {
                throw new Exception("The column " + OriginalDatasetColumn.GetRuntimeName() + " references a ColumnInfo that has been deleted");
            }

            var syntaxHelper = extractableCohort.GetQuerySyntaxHelper();

            //the externally referenced Cohort table
            var externalCohortTable = extractableCohort.ExternalCohortTable;

            var privateIdentifierFieldDiscovered = externalCohortTable.Discover().ExpectTable(externalCohortTable.TableName).DiscoverColumn(externalCohortTable.PrivateIdentifierField);

            string collateStatement = "";

            //the release identifier join might require collation

            //if the private has a collation
            if (!string.IsNullOrWhiteSpace(privateIdentifierFieldDiscovered.Collation))
            {
                var cohortCollation     = privateIdentifierFieldDiscovered.Collation;
                var otherTableCollation = OriginalDatasetColumn.ColumnInfo.Collation;


                //only collate if the server types match and if the collations differ
                if (privateIdentifierFieldDiscovered.Table.Database.Server.DatabaseType == OriginalDatasetColumn.ColumnInfo.TableInfo.DatabaseType)
                {
                    if (!string.IsNullOrWhiteSpace(otherTableCollation) && !string.Equals(cohortCollation, otherTableCollation))
                    {
                        collateStatement = " collate " + cohortCollation;
                    }
                }
            }


            if (!isPartOfMultiCHISubstitution)
            {
                SelectSQL = extractableCohort.GetReleaseIdentifier();
                Alias     = syntaxHelper.GetRuntimeName(SelectSQL);
            }
            else
            {
                SelectSQL = "(SELECT DISTINCT " +
                            extractableCohort.GetReleaseIdentifier() +
                            " FROM " +
                            externalCohortTable.TableName + " WHERE " + extractableCohort.WhereSQL() + " AND " + externalCohortTable.PrivateIdentifierField + "=" + OriginalDatasetColumn.SelectSQL + collateStatement + ")";

                if (!string.IsNullOrWhiteSpace(OriginalDatasetColumn.Alias))
                {
                    string toReplace     = extractableCohort.GetPrivateIdentifier(true);
                    string toReplaceWith = extractableCohort.GetReleaseIdentifier(true);

                    //take the same name as the underlying column
                    Alias = OriginalDatasetColumn.Alias;

                    //but replace all instances of CHI with PROCHI (or Barcode, or whatever)
                    if (!Alias.Contains(toReplace) || Regex.Matches(Alias, Regex.Escape(toReplace)).Count > 1)
                    {
                        throw new Exception("Expected OriginalDatasetColumn " + OriginalDatasetColumn.Alias + " to have the text \"" + toReplace + "\" appearing once (and only once in it's name)," +
                                            "we planned to replace that text with:" + toReplaceWith);
                    }


                    Alias = Alias.Replace(toReplace, toReplaceWith);
                }
                else
                {
                    throw new Exception("In cases where you have multiple columns marked IsExtractionIdentifier, they must all have Aliases, the column " + OriginalDatasetColumn.SelectSQL + " does not have one");
                }
            }

            JoinSQL = OriginalDatasetColumn.SelectSQL + "=" + externalCohortTable.PrivateIdentifierField + collateStatement;
        }
        public ExtractionTimeTimeCoverageAggregator(ICatalogue catalogue, IExtractableCohort cohort)
        {
            _catalogue = catalogue;

            Buckets = new Dictionary <DateTime, ExtractionTimeTimeCoverageAggregatorBucket>();

            if (!catalogue.TimeCoverage_ExtractionInformation_ID.HasValue)
            {
                return;
            }
            try
            {
                _expectedTimeFieldInOutputBuffer = catalogue.TimeCoverage_ExtractionInformation.GetRuntimeName();
            }
            catch (Exception e)
            {
                throw new Exception("Could not resolve TimeCoverage_ExtractionInformation for Catalogue '" + catalogue + "',time coverage ExtractionInformationID was:" + catalogue.TimeCoverage_ExtractionInformation_ID, e);
            }

            _expectedExtractionIdentifierInOutputBuffer = cohort.GetQuerySyntaxHelper().GetRuntimeName(cohort.GetReleaseIdentifier());
        }