using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using System.Text.Json; using Erp.Platform.Entities; using Erp.Platform.Enums; using Erp.Platform.Extensions; using Erp.Platform.ListForms; using Erp.Platform.Localization; using Erp.Platform.OrganizationUnits; using Microsoft.Extensions.Localization; using Volo.Abp.Domain.Repositories; using Volo.Abp.ObjectMapping; using Volo.Abp.Settings; using Volo.Abp.Users; namespace Erp.Platform.Queries; public interface ISelectQueryManager { List SelectFields { get; } string SelectQuery { get; } Dictionary SelectQueryParameters { get; } string TotalCountQuery { get; } string GroupQuery { get; } string ChartQuery { get; } public string DeleteQuery { get; } List<(int Index, string Field, string SelectExpr, string Sort, bool IsExpanded, string GroupInterval)> GroupTuples { get; } List<(int Index, string Field, string SelectExpr, string SummaryType)> GroupSummaryTuples { get; } List SummaryQueries { get; } public bool IsAppliedGridFilter { get; } public bool IsAppliedServerFilter { get; } void PrepareQueries(ListForm listform, List listFormFields, DataSourceTypeEnum dataSourceType, List listFormCustomizations = null, QueryParameters queryParams = null); } public class SelectField { public SelectField() { } public SelectField(ListFormField item, string baseTableName) { FieldName = item.FieldName; if (!string.IsNullOrEmpty(item.JoinTableJson)) JoinOptions = JsonSerializer.Deserialize(item.JoinTableJson); if (JoinOptions != null && !string.IsNullOrWhiteSpace(JoinOptions.TableName)) { if (!string.IsNullOrEmpty(JoinOptions.FieldNameAlias)) SelectFieldName = $"\"{JoinOptions.TableName}\".\"{JoinOptions.SelectFieldName}\" AS \"{JoinOptions.FieldNameAlias}\""; else SelectFieldName = $"\"{JoinOptions.TableName}\".\"{JoinOptions.SelectFieldName}\" AS \"{FieldName}\""; JoinSql = $"{JoinOptions.JoinType} \"{JoinOptions.TableName}\" ON \"{JoinOptions.TableName}\".\"{JoinOptions.JoinFieldName}\" = \"{baseTableName}\".\"{JoinOptions.BaseTableJoinFieldName}\""; // JOIN bolumunde birden fazla condition var ise if (!string.IsNullOrEmpty(JoinOptions.JoinFieldName2)) { JoinSql += $" {JoinOptions.JoinCondition2} \"{JoinOptions.JoinFieldName2}\" = {JoinOptions.BaseTableJoinFieldName2_OrValue}"; } IsJoined = true; } else { SelectFieldName = $"\"{baseTableName}\".\"{this.FieldName}\" AS \"{FieldName}\""; IsJoined = false; } } public string FieldName { get; set; } // UserName public string SelectFieldName { get; set; } // ListForm.UserName as UserName public bool IsJoined { get; set; } public JoinTable JoinOptions { get; set; } public string JoinSql { get; set; } } public class SelectQueryManager : PlatformDomainService, ISelectQueryManager { private string SelectCommand { get; set; } private string TableName { get; set; } private string From { get { return SelectCommandType == SelectCommandTypeEnum.Query ? $"({SelectCommand})" : SelectCommand; } } private SelectCommandTypeEnum SelectCommandType { get; set; } private string KeyFieldName { get; set; } private List JoinParts { get; set; } private List WhereParts { get; set; } private List SortParts { get; set; } private DataSourceTypeEnum DataSourceType { get; set; } public List SelectFields { get; private set; } public string SelectQuery { get; private set; } public Dictionary SelectQueryParameters { get; private set; } public string TotalCountQuery { get; private set; } public string GroupQuery { get; private set; } public string DeleteQuery { get; private set; } public string ChartQuery { get; private set; } public List<(int Index, string Field, string SelectExpr, string Sort, bool IsExpanded, string GroupInterval)> GroupTuples { get; private set; } = []; public List<(int Index, string Field, string SelectExpr, string SummaryType)> GroupSummaryTuples { get; private set; } = []; public List SummaryQueries { get; private set; } public bool IsAppliedGridFilter { get; private set; } public bool IsAppliedServerFilter { get; private set; } public IPlatformOuRepository OuRepository { get; } public IRepository BranchUsersRepository { get; } public DefaultValueHelper DefaultValueHelper { get; } public SelectQueryManager( ISettingProvider settingProvider, IStringLocalizer localizer, ICurrentUser currentUser, IObjectMapper objectMapper, IListFormAuthorizationManager authManager, IPlatformOuRepository ouRepository, IRepository branchUsersRepository, DefaultValueHelper defaultValueHelper) : base(settingProvider, localizer, currentUser, objectMapper, authManager) { SelectFields = []; JoinParts = []; WhereParts = []; SortParts = []; SummaryQueries = []; OuRepository = ouRepository; BranchUsersRepository = branchUsersRepository; DefaultValueHelper = defaultValueHelper; } public void PrepareQueries(ListForm listform, List listFormFields, DataSourceTypeEnum dataSourceType, List listFormCustomizations = null, QueryParameters queryParams = null) { if (listform == null) { return; } int take = queryParams?.Take > 0 ? queryParams.Take : listform.PageSize > 0 ? listform.PageSize : PlatformConsts.GridOptions.RowsPerPage; int skip = queryParams?.Skip ?? 0; DataSourceType = dataSourceType; SelectCommand = DefaultValueHelper.GetDefaultValue(listform.SelectCommand); TableName = listform.TableName.IsNullOrEmpty() ? SelectCommand : listform.TableName; KeyFieldName = listform.KeyFieldName; SelectCommandType = listform.SelectCommandType; var KeyField = new SelectField { FieldName = KeyFieldName, SelectFieldName = $"\"{TableName}\".\"{KeyFieldName}\" AS \"{KeyFieldName}\"", IsJoined = false }; SelectFields.AddRange(GetSelectAndJoinFields(listFormFields)); if (!SelectFields.Any(a => a.FieldName == KeyField.FieldName)) { SelectFields.Add(KeyField); } var joinParts = SelectFields.Where(c => !string.IsNullOrEmpty(c.JoinSql)).Select(c => c.JoinSql).Distinct(); JoinParts.AddRange(joinParts); List whereFields = GetWhereFields(listform, listFormFields, queryParams); WhereParts.AddRange(whereFields); List sortFields = GetSortFields(listform, listFormFields, queryParams?.Sort); SortParts.AddRange(sortFields); SelectQuery = GetSelectString(); SetJoinStringFromCustomizations(listFormCustomizations); SelectQuery += GetJoinString(); SetWhereStringFromCustomizations(listFormCustomizations); SelectQuery += GetWhereString(); SelectQuery += GetSortString(); // queryParams null ise grid olusturmak icin gelmistir, paging yapma if (queryParams != null && queryParams.Take > 0) { SelectQuery += GetPagingString(take, skip); } TotalCountQuery = GetTotalCountQuery(); GroupQuery = GetGroupQuery(listFormFields, queryParams); DeleteQuery = GetDeleteQuery(queryParams); ChartQuery = GetChartQuery(listform, queryParams); #region Total Summary Queries if (queryParams != null && !queryParams.TotalSummary.IsNullOrWhiteSpace()) { var items = new List(); var summaries = queryParams.TotalSummary.Split(PlatformConsts.MultiValueDelimiter); for (int i = 0; i < summaries.Length; i++) { var summary = summaries[i].Split(' '); var fieldName = summary[0]; var summmaryType = summary[1]; // asc, desc fieldName = ConvertAliasToFieldName(fieldName, listFormFields); if (fieldName == "undefined") { continue; } SummaryQueries.Add(GetSummaryQuery(fieldName, summmaryType)); } } #endregion } private List GetSelectAndJoinFields(List listFormFields) { List selectFields = []; foreach (var itemField in listFormFields.OrderBy(c => c.JoinTableJson)) { if (!itemField.IsActive.HasValue || !itemField.IsActive.Value || itemField.IsDeleted) { continue; } selectFields.Add(new(itemField, TableName)); } return selectFields; } /// Sadece join li alanlar icin gercek SqlField bigisini verir /// /// /// /// private string ConvertAliasToFieldName(string filterName, List listFormFields, string groupInterval = null) { var format = groupInterval switch { "year" => DataSourceType == DataSourceTypeEnum.Mssql ? "DATEPART(YEAR, {0})" : DataSourceType == DataSourceTypeEnum.Postgresql ? "DATE_PART('YEAR', {0})" : "", "quarter" => DataSourceType == DataSourceTypeEnum.Mssql ? "DATEPART(QUARTER, {0})" : DataSourceType == DataSourceTypeEnum.Postgresql ? "DATE_PART('QUARTER', {0})" : "", "month" => DataSourceType == DataSourceTypeEnum.Mssql ? "DATEPART(MONTH, {0})" : DataSourceType == DataSourceTypeEnum.Postgresql ? "DATE_PART('MONTH', {0})" : "", "day" => DataSourceType == DataSourceTypeEnum.Mssql ? "DATEPART(DAY, {0})" : DataSourceType == DataSourceTypeEnum.Postgresql ? "DATE_PART('DAY', {0})" : "", "dayOfWeek" => DataSourceType == DataSourceTypeEnum.Mssql ? "DATEPART(DW, {0})" : DataSourceType == DataSourceTypeEnum.Postgresql ? "DATE_PART('DOW', {0})" : "", _ => "{0}" }; var field = listFormFields.FirstOrDefault(a => a.FieldName == filterName && !string.IsNullOrWhiteSpace(a.JoinTableJson)); if (field is not null) { var jt = JsonSerializer.Deserialize(field.JoinTableJson); if (!jt.TableName.IsNullOrWhiteSpace()) { return string.Format(format, $"\"{jt.TableName}\".\"{jt.SelectFieldName}\""); } } return string.Format(format, $"\"{TableName}\".\"{filterName}\""); } private string GetSelectString() { return $"SELECT {string.Join(',', SelectFields.Select(c => $"{c.SelectFieldName}"))} FROM \"{From}\" AS \"{TableName}\""; } private string SetJoinStringFromCustomizations(List listFormCustomizations) { if (listFormCustomizations.IsNullOrEmpty()) { return string.Empty; } var customizations = listFormCustomizations .Where(a => a.CustomizationType == ListFormCustomizationTypeEnum.ServerJoin) .Select(a => a.CustomizationData) .ToList(); JoinParts.AddRange(customizations); return string.Join(' ', customizations); } /// /// WhereParts icerisine ListFormCustomization tanimindan gelen filtreleri ekler /// /// private void SetWhereStringFromCustomizations(List listFormCustomizations) { if (listFormCustomizations.IsNullOrEmpty()) { return; } var customizations = listFormCustomizations .Where(a => a.CustomizationType == ListFormCustomizationTypeEnum.ServerWhere) .Select(a => a.CustomizationData) .ToList(); foreach (var item in customizations) { if (WhereParts.Any()) { WhereParts.Add("AND"); } WhereParts.Add(DefaultValueHelper.GetDefaultValue(item)); IsAppliedServerFilter = true; } } private List GetWhereFields(ListForm listform, List listFormFields, QueryParameters queryParams = null) { var whereParts = new List(); if (!string.IsNullOrEmpty(queryParams?.Filter)) { var filters = queryParams.Filter.Replace('[', '(') .Replace(']', ')') .Replace("\"\"", "''") // (empty string) "" -> '' .Replace("\"", "") .Replace(",\"or\",", " or ") .Replace(",\"and\",", " and "); var filterItems = filters.Split(",").ToList(); if (filterItems .Where(a => !a.Contains('!') && a != "and" && a != "or") .ToList().Count % 3 == 0) //Eğer gelen veri 'and', 'or' veya '!' dışında kalan item adedi 3 ün katıysa { SelectQueryParameters = new Dictionary(); var forDeger = 3; for (int i = 0; i < filterItems.Count; i += forDeger) { if (filterItems[i].Contains('!')) { forDeger = 1; whereParts.Add(filterItems[i].Replace("!", "NOT")); IsAppliedGridFilter = true; } else if (filterItems[i] == "and" || filterItems[i] == "or") { forDeger = 1; whereParts.Add(filterItems[i]); IsAppliedGridFilter = true; } else { forDeger = 3; var fieldName = filterItems[i]; var op = filterItems[i + 1]; var fieldValue = filterItems[i + 2]; var filter = ParseFilter(fieldName, op, fieldValue, listFormFields, i); if (filter != "") { whereParts.Add(filter); IsAppliedGridFilter = true; } } } } } if (!listform.DefaultFilter.IsNullOrWhiteSpace()) { if (whereParts.Any()) { whereParts.Add("AND"); } whereParts.Add(DefaultValueHelper.GetDefaultValue(listform.DefaultFilter)); IsAppliedServerFilter = true; } if (PlatformConsts.IsMultiTenant && listform.IsTenant) { if (whereParts.Any()) { whereParts.Add("AND"); } if (CurrentTenant.IsAvailable) { whereParts.Add($"\"TenantId\" = '{CurrentTenant.Id}'"); } else { whereParts.Add($"\"TenantId\" IS NULL"); } } if (listform.IsBranch) { if (whereParts.Any()) { whereParts.Add("AND"); } var ids = BranchUsersRepository.GetListAsync((a) => a.UserId == CurrentUser.Id.Value).Result; if (ids.Count > 0) { whereParts.Add($"\"BranchId\" IN ({string.Join(",", ids.Select(a => $"'{a.BranchId}'"))})"); } else { whereParts.Add($"\"BranchId\" = '{Guid.Empty}'"); } } if (listform.IsOrganizationUnit) { if (whereParts.Any()) { whereParts.Add("AND"); } var ids = OuRepository.GetOrganizationUnitIdsWithChildren(CurrentUser.Id.Value).Result; if (ids.Count > 0) { whereParts.Add($"\"OrganizationUnitId\" IN ({string.Join(",", ids.Select(a => $"'{a}'"))})"); } else { whereParts.Add($"\"OrganizationUnitId\" = '{Guid.Empty}'"); } } if (!whereParts.Any()) { whereParts.Add("1 = 1"); } return whereParts; } /// FieldName operator Id seklinde olan filtreleri ayirir /// /// /// private string ParseFilter( string fieldName, string op, string fieldValue, List listFormFields, int customKey) { string sqlPart = string.Empty; if (string.IsNullOrWhiteSpace(fieldName) || string.IsNullOrWhiteSpace(op)) { return sqlPart; } var fieldDbType = DbType.String; var fieldFilter = fieldName.Split('.'); var filterFieldName = fieldFilter.First().RemoveParentheses(); var filterGroupInterval = fieldFilter.Length > 1 ? fieldFilter.Last().ToLower() : null; var filterParamKey = $"@{filterFieldName}{customKey}"; var filterParamKeyLower = filterParamKey; var filterOperator = op.RemoveParentheses(); var filterValue = fieldValue.RemoveParentheses(); var listFormField = listFormFields.FirstOrDefault(c => c.FieldName == filterFieldName); if (listFormField == null) { fieldDbType = ListFormManager.InferDbTypeFromString(filterValue); } else { // filterGroupInterval sayı olduğu için (örn OrderDate.Month), eğer bu gelirse sayıya parse ediyoruz, // diğer durumlarda field tipine parse ediyoruz fieldDbType = filterGroupInterval switch { "year" or "quarter" or "month" or "day" or "dayOfWeek" => DbType.Int32, _ => listFormField.SourceDbType }; } if (filterValue == "null") { if (filterOperator == "=") filterOperator = "isblank"; if (filterOperator == "<>") filterOperator = "isnotblank"; } var lastCharacters = fieldValue.Replace(filterValue, string.Empty); // Sadece parantezleri almak için var filterSqlFieldName = ConvertAliasToFieldName(filterFieldName, listFormFields, filterGroupInterval); if (filterOperator == "=" && DataSourceType == DataSourceTypeEnum.Postgresql && ( fieldDbType == DbType.String || fieldDbType == DbType.AnsiString)) { filterSqlFieldName = $"lower({filterSqlFieldName})"; filterParamKeyLower = $"lower({filterParamKeyLower})"; filterValue = filterValue.Replace('I', 'ı'); } filterSqlFieldName = fieldFilter.First().Replace(filterFieldName, filterSqlFieldName); var sqlOperator = ""; string formatSql = "{0} {1} {2}"; string concatOp = DataSourceType == DataSourceTypeEnum.Mssql ? "+" : DataSourceType == DataSourceTypeEnum.Postgresql ? "||" : ""; string likeOp = DataSourceType == DataSourceTypeEnum.Mssql ? "LIKE" : DataSourceType == DataSourceTypeEnum.Postgresql ? "ILIKE" : ""; if (filterOperator == "=") sqlOperator = "="; else if (filterOperator == "<>") sqlOperator = "<>"; else if (filterOperator == "<") sqlOperator = "<"; else if (filterOperator == "<=") sqlOperator = "<="; else if (filterOperator == ">") sqlOperator = ">"; else if (filterOperator == ">=") sqlOperator = ">="; else if (filterOperator == "contains") formatSql = "{0} " + likeOp + " '%' " + concatOp + " {2} " + concatOp + " '%'"; else if (filterOperator == "notcontains") formatSql = "{0} NOT " + likeOp + " '%' " + concatOp + " {2} " + concatOp + " '%'"; else if (filterOperator == "startswith") formatSql = "{0} " + likeOp + " {2} " + concatOp + " '%'"; else if (filterOperator == "endswith") formatSql = "{0} " + likeOp + " '%' " + concatOp + " {2}"; else if (filterOperator == "isblank") formatSql = "{0} IS NULL"; else if (filterOperator == "isnotblank") formatSql = "{0} IS NOT NULL"; sqlPart = string.Format(formatSql, filterSqlFieldName, sqlOperator, filterParamKeyLower); if (lastCharacters.Any()) { sqlPart += lastCharacters; } if (formatSql.Contains("{2}")) { SelectQueryParameters.Add(filterParamKey, QueryHelper.GetFormattedValue(fieldDbType, filterValue)); } return sqlPart; } private List GetSortFields(ListForm listform, List listFormFields, string sort = null) { var sortFields = new List(); if (listform.SortMode == PlatformConsts.GridOptions.SortModeNone) { sortFields.Add("CURRENT_TIMESTAMP"); return SortParts; } // kullanicinin islemi ile siralama yapiliyor ise if (!string.IsNullOrEmpty(sort)) { var sorts = sort.Split(PlatformConsts.MultiValueDelimiter, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < sorts.Length; i++) { // sorts[i] su sekilde gelir: "AlanIsmi desc" var sortElem = sorts[i].Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries); sortElem[0] = $"\"{sortElem[0].Trim()}\""; // Grid uzerinden gelen siralama istegi icin alan ismini koseli parantes icerisine al (Anahtar isimdeki alanlar icin Bug olusmasini onler, ornegin Key isminde bir alana ait siralama istegi gelebilir) sortFields.Add(sortElem.JoinAsString(" ")); // Gelen istegi su sekle donusturur: [AlanIsmi] desc } } else // ekran tanimi ile siralama yapiliyor ise { foreach (var itemField in listFormFields.Where(c => c.SortIndex.HasValue && c.SortIndex > 0).OrderBy(c => c.SortIndex)) { sortFields.Add($"\"{itemField.FieldName}\" {itemField.SortDirection}"); } } // Varsayilan olarak siramalama yok ise siralamayi etkilemeyecek bir alan ekle (paging islemlerinde Order By bolumu istenildigi icin eklendi) if (sortFields.Count == 0) { sortFields.Add("CURRENT_TIMESTAMP"); } return sortFields; } private string GetJoinString() { return " " + string.Join(' ', JoinParts); } private string GetWhereString() { if (WhereParts.Count == 0) return ""; return " WHERE " + string.Join(' ', WhereParts); } private string GetSortString() { return " ORDER BY " + string.Join(',', SortParts); } private string GetPagingString(int take, int? skip = 0) { return $" OFFSET {skip} ROWS FETCH NEXT {take} ROWS ONLY"; } private string GetTotalCountQuery() { var sql = $"SELECT COUNT(\"{TableName}\".\"{KeyFieldName}\") FROM \"{From}\" AS \"{TableName}\""; sql += GetJoinString(); sql += GetWhereString(); return sql; } private string GetSummaryQuery(string fieldName, string summaryType) { var sql = $"SELECT {summaryType}({fieldName}) FROM \"{From}\" AS \"{TableName}\""; sql += GetJoinString(); sql += GetWhereString(); return sql; } private string GetGroupQuery(List listFormFields, QueryParameters queryParams = null) { if (queryParams == null || queryParams.Group.IsNullOrWhiteSpace()) { return null; } var validSummaryTypes = new string[] { "sum", "avg", "min", "max", "count" }; var validSortTypes = new string[] { "asc", "desc" }; var validGroupIntervals = new string[] { "day", "dayOfWeek", "month", "quarter", "year" }; // queryParams.Group veri yapisi: // AlanIsmi desc isExpanded groupInterval // Örn: group:IsEnabled asc false|TextDate asc false year|TextDate asc false month|CultureName asc false // yapilan grup islemlerinde her bir gruplama icin bir ya da birden fazla istek geliyor. var groups = queryParams.Group?.Split(PlatformConsts.MultiValueDelimiter); foreach (var (group, i) in groups.Select((a, i) => (a, i))) { var items = group.Trim().Split(' '); if (!items.Length.IsBetween(2, 4)) { continue; } var field = items[0]; var sort = validSortTypes.Contains(items[1]) ? items[1] : "asc"; var isExpanded = items.Length > 2 && items[2] == "true"; var groupInterval = items.Length > 3 ? validGroupIntervals.Contains(items[3]) ? items[3] : null : null; var fieldName = ConvertAliasToFieldName(field, listFormFields, groupInterval);// Alias li bir alan ise gercek alani bul GroupTuples.Add((i, fieldName, $"Group_{i}", sort, isExpanded, groupInterval)); } // gruplanan bir alan icin grup satirinda summary bilgisinin gorunmesi icin gerekli veri yapisidir, // grup sorgusu ile birlikte calistirilir. // Gelen veri yapisi: FieldName SummaryType|FieldName SummaryType // Örn: groupSummary:TextCount sum|TextCount count // Not: Gelen sira ile ayni sekilde geri dondurulmelidir! GroupSummaryItems bunun icin kullaniliyor var groupSummaries = queryParams.GroupSummary?.Split(PlatformConsts.MultiValueDelimiter); if (!groupSummaries.IsNullOrEmpty()) { foreach (var (groupSummary, i) in groupSummaries.Select((a, i) => (a, i))) { var gs = groupSummary.Trim().Split(' '); if (gs.Length != 2) { continue; } var field = gs[0].ToString(); var summaryType = gs[1].ToString(); if (!validSummaryTypes.Contains(summaryType)) { continue; } var fieldName = ConvertAliasToFieldName(field, listFormFields);// Alias li bir alan ise gercek alani bul GroupSummaryTuples.Add((i, fieldName, $"Summary_{i}", summaryType)); } } var sqlSub = new StringBuilder(); sqlSub.Append("SELECT "); sqlSub.Append(string.Join(',', GroupTuples.Select((a) => $"{a.Field} AS \"{a.SelectExpr}\""))); sqlSub.Append(string.Join(',', GroupSummaryTuples.Select((a) => $",{a.SummaryType}({a.Field}) AS \"{a.SelectExpr}\""))); sqlSub.Append(",COUNT(1) AS \"Summary_Count\""); sqlSub.Append($" FROM \"{From}\" AS \"{TableName}\""); sqlSub.Append(GetJoinString()); sqlSub.Append(GetWhereString()); sqlSub.Append($" GROUP BY {string.Join(',', GroupTuples.Select((a) => a.Field))}"); sqlSub.Append($" ORDER BY {string.Join(',', GroupTuples.Select((a, i) => $"\"{a.SelectExpr}\" {a.Sort}"))}"); if (queryParams.Take > 0) { sqlSub.Append(GetPagingString(queryParams.Take, queryParams.Skip)); } else { sqlSub.Append(" OFFSET 0 ROWS"); } var sqlMain = new StringBuilder(); sqlMain.Append("SELECT "); sqlMain.Append(string.Join(',', GroupTuples.Select((a) => $"\"{a.SelectExpr}\""))); foreach (var item in GroupTuples.Select((groupTuple, i) => (groupTuple, i))) { var prevItems = GroupTuples.Take(item.i + 1); if (prevItems.Count() == 1) { sqlMain.Append($",\"{item.groupTuple.SelectExpr}\" AS \"{item.groupTuple.SelectExpr}_Key\""); } else { sqlMain.Append($",CONCAT({string.Join(",'" + PlatformConsts.MultiValueDelimiter + "',", prevItems.Select(a => $"\"{a.SelectExpr}\""))}) AS \"{item.groupTuple.SelectExpr}_Key\""); } } sqlMain.Append(", \"Summary_Count\""); foreach (var summaryTuple in GroupSummaryTuples) { var sType = summaryTuple.SummaryType == "count" ? "sum" : summaryTuple.SummaryType; var summarySelect = $"{sType}(\"{summaryTuple.SelectExpr}\")"; sqlMain.Append($",{summarySelect} OVER() AS \"{summaryTuple.SelectExpr}_All\""); var partitionBy = new List(); foreach (var groupTuple in GroupTuples) { partitionBy.Add($"\"{groupTuple.SelectExpr}\""); sqlMain.Append($",{summarySelect} OVER(PARTITION BY {string.Join(',', partitionBy)}) AS \"{summaryTuple.SelectExpr}_{groupTuple.Index}\""); } partitionBy.Clear(); } // foreach (var summaryTuple in GroupSummaryTuples) // { // var summarySelect = $"{summaryTuple.SummaryType}({summaryTuple.SelectExpr})"; // sqlMain.Append($",{summarySelect} OVER() AS {summaryTuple.SelectExpr}_All"); // foreach (var item in GroupTuples.Select((tuple, i) => (tuple, i))) // { // var groupTuple = item.tuple; // if (item.i == 0) // { // sqlMain.Append($",{summaryTuple.SelectExpr} AS {summaryTuple.SelectExpr}_{groupTuple.Index}"); // } // else // { // sqlMain.Append($",{summarySelect} OVER(PARTITION BY {groupTuple.SelectExpr}) AS {summaryTuple.SelectExpr}_{groupTuple.Index}"); // } // } // } sqlMain.Append($" FROM ({sqlSub}) AS \"Sub\""); sqlMain.Append($" ORDER BY {string.Join(',', GroupTuples.Select((a, i) => $"\"{a.SelectExpr}\" {a.Sort}"))}"); return sqlMain.ToString(); } private string GetDeleteQuery(QueryParameters queryParams = null) { if (queryParams == null || queryParams.CreateDeleteQuery == false) return null; return $"DELETE \"{TableName}\" FROM {SelectCommand} AS \"{TableName}\" {GetWhereString()}"; } public string GetChartQuery(ListForm listform, QueryParameters queryParams = null) { if (listform == null || string.IsNullOrWhiteSpace(listform.SeriesJson) || queryParams == null) return null; var seriesList = JsonSerializer.Deserialize>(listform.SeriesJson); if (seriesList == null || seriesList.Count == 0) return null; // ArgumentField listesi var argumentFields = seriesList.Select(s => s.ArgumentField).Distinct().ToList(); // ArgumentField ifadesini oluştur string argumentExpression; if (argumentFields.Count == 1) { // Tek ArgumentField argumentExpression = $"[{argumentFields.First()}]"; } else { // Birden fazla → '|' ile birleştir argumentExpression = string.Join(" + '|' + ", argumentFields.Select(f => $"[{f}]")); } // Select sütunlarını oluştur var selectParts = new List { $"{argumentExpression} AS ArgumentField" }; foreach (var series in seriesList) { string sqlFunc = series.SummaryType.ToUpper() switch { "COUNT" => $"COUNT([{series.ValueField}])", "SUM" => $"SUM([{series.ValueField}])", "AVG" => $"AVG([{series.ValueField}])", "MIN" => $"MIN([{series.ValueField}])", "MAX" => $"MAX([{series.ValueField}])", _ => throw new NotSupportedException($"Unsupported SummaryType: {series.SummaryType}") }; selectParts.Add($"{sqlFunc} AS [{series.Name}]"); } // SQL cümlesi var sql = $@" SELECT {string.Join(", ", selectParts)} FROM [{listform.SelectCommand}] {GetWhereString()} GROUP BY {argumentExpression}"; return sql; } }