本文记录了一次使用abp Core5 ,vue 开发复杂报表的经历。

0、需求概述

业务需求是:统计一个化工厂车队形式记录数据中异常停车的报表,维度可以按照车俩、驾驶员两个维度进行统计,统计的元素有:

TLX01 堵车|TLX02 限行|TLX03 途中车辆维修|TLX04 停车休息|TLX05 雨雾天气|TLX06 装卸货或装卸货排队|TLX07 围栏停留|TLX08 吃饭|TLX09 加油|TLX10 洗车加水。

原始报表样式:

解决思路是:

1、sqlserver 分析数据源

1.1 表数据

整个报表牵扯的5张表, 分表示,停车日志、明细、要统计的停车事件类型、驾驶员信息,如下:

select * from TruckAwaitLog where LogId=‘F02D9B3E-D172-473A-8D01-FFF28A92B17C’ //停车日志
select * from TruckAwaitLogDetail where MainId=‘F02D9B3E-D172-473A-8D01-FFF28A92B17C’ //明细
select * from TruckAwaitLogType //停车事件类型
select * from [人员信息] where [人员信息].userid=‘0640’

1.2 统计数据源的sql脚本

  • —异常停留类型统计表(按车俩)
SELECT truck.cCode_Name,truck.cCode, TruckAwaitLog.MainTruckId as 主驾驶,
TruckAwaitLogType.TypeId,TruckAwaitLogType.TypeName,SUM(TruckAwaitLog.TotalDuration) as 时长, count(truck.cCode) AS  次数FROM TruckAwaitLog left join TruckAwaitLogTypeon TruckAwaitLog.TypeId= TruckAwaitLogType.TypeId   left join [YDDATA].[dbo].[车辆] as truckon  truck.cCode = TruckAwaitLog.MainTruckIdGROUP BY  truck.cCode_Name ,truck.cCode,TruckAwaitLog.MainTruckId,TruckAwaitLogType.TypeId,TruckAwaitLogType.TypeName order by  TruckAwaitLog.MainTruckId

  • –异常停留类型统计表(按驾驶员)
SELECT  TruckAwaitLog.TruckEscortUserId as 主驾驶,Human.cCode_Name,TruckAwaitLogType.TypeId,TruckAwaitLogType.TypeName,SUM(TruckAwaitLog.TotalDuration) as 时长,count(TruckAwaitLog.LogId) AS  次数FROM TruckAwaitLog left join TruckAwaitLogTypeon TruckAwaitLog.TypeId= TruckAwaitLogType.TypeId     inner join [YDDATA].[dbo].[V人员信息] as Humanon  Human.userid = TruckAwaitLog.MainUserIdGROUP BY  Human.cCode_Name, TruckAwaitLog.TruckEscortUserId,TruckAwaitLogType.TypeId,TruckAwaitLogType.TypeName

经分析后,使用多表查询,达到的报表要求, 还需处理行专列问题,由于开发框架采用ABP的DDD模式,尽量不使用原生sql,所以使用仓储模式,多模块关联,linq处理数据问题,行专列使用动态 Linq.Dynamic 构建行转列。

2、Abp 中Efcore的多模块关联查询

2.1回顾ABP 架构模型

2.2 回顾abp 的代码分层模型

2.3 回顾abp 的分层调用关系模型

2.3 ABP 模块构建

2.3.1 构建领域对象

 /// <summary>/// TruckAwaitLog,领域对象/// </summary>[Table("TruckAwaitLog")]public class TruckAwaitLog : Entity<Guid>{ /// <summary>/// 默认构造函数(需要初始化属性的在此处理)/// </summary>public TruckAwaitLog(){}#region Property Members[Column("LogId")]public override Guid Id { get; set; }//[Required]//[Required]//public virtual Guid LogId { get; set; }//[Required]public virtual string AccId { get; set; }//[Required]public virtual string VouchId { get; set; }//[Required][Required]public virtual string MainUserId { get; set; }//[Required]public virtual string SubUserId { get; set; }//[Required]public virtual string TruckEscortUserId { get; set; }

ABP 重写主键ID
由于ABP设计的领域对象 Entity : IEntity有主键默认名称:id

namespace Abp.Domain.Entities
{//// 摘要://     Basic implementation of IEntity interface. An entity can inherit this class of//     directly implement to IEntity interface.//// 类型参数://   TPrimaryKey://     Type of the primary key of the entity[Serializable]public abstract class Entity<TPrimaryKey> : IEntity<TPrimaryKey>{//// 摘要://     Unique identifier for this entity.public virtual TPrimaryKey Id{get;set;}//// 摘要://     Checks if this entity is transient (it has not an Id).//// 返回结果://     True, if this entity is transientpublic virtual bool IsTransient(){if (EqualityComparer<TPrimaryKey>.Default.Equals(Id, default(TPrimaryKey))){return true;}if (typeof(TPrimaryKey) == typeof(int)){return Convert.ToInt32(Id) <= 0;}if (typeof(TPrimaryKey) == typeof(long)){return Convert.ToInt64(Id) <= 0;}return false;}public virtual bool EntityEquals(object obj){if (obj == null || !(obj is Entity<TPrimaryKey>)){return false;}if (this == obj){return true;}Entity<TPrimaryKey> entity = (Entity<TPrimaryKey>)obj;if (IsTransient() && entity.IsTransient()){return false;}Type type = GetType();Type type2 = entity.GetType();if (!type.GetTypeInfo().IsAssignableFrom(type2) && !type2.GetTypeInfo().IsAssignableFrom(type)){return false;}if (this is IMayHaveTenant && entity is IMayHaveTenant && this.As<IMayHaveTenant>().TenantId != entity.As<IMayHaveTenant>().TenantId){return false;}if (this is IMustHaveTenant && entity is IMustHaveTenant && this.As<IMustHaveTenant>().TenantId != entity.As<IMustHaveTenant>().TenantId){return false;}return Id.Equals(entity.Id);}public override string ToString(){return $"[{GetType().Name} {Id}]";}}
}

所以我们表设计主键不是id的情况下要改写,规则如下。

[Column(“你那表的源主键名”)] public override leixing Id{ get; set; }>

  • 重写ID [Column(“数据库指定的ID”)]>

[Column(“CarTypeID”)]
public override int Id { get; set; }

  • 2.映射中指定 这里用的是AutoMapper

第一个UserID是Dto模型里面的 第二个Id是实体类中我们重写的那个Id

1 var carTypeDtoMapper = mapperConfig.CreateMap<CarType,
CarTypeDto>(); 2 carTypeDtoMapper.ForMember(dto => dto.CarTypeID, map
=> map.MapFrom(m => m.Id));
3.对于多表查询外键ID无效的情况 可以在实体中指定外键

1 [ForeignKey(“CarBrand”)] 2 public int? BrandID { get; set; }
对于ForeignKeyVS给我们做了良好的解释>
1 //如果将 ForeigKey 特性添加到外键属性,则应指定关联的导航属性的名称。如果将 ForeigKey
特性添加到导航属性,则应指定关联的外键的名称。如果导航属性具有多个外键,则使用逗号分隔的外键名称列表。
public ForeignKeyAttribute(string name);
4.获取数据 将数据返回 这里用的是DTO模型传输数据>
1 var list = _carTypeRepository.GetAllList();
2 将POCO对象转为DTO对象
3 return list.MapTo<List>();

2.3.2 构建基础设施对象

 public partial class SecondDbContext : AbpZeroDbContext<Tenant, Role, User, SecondDbContext>, IAbpPersistedGrantDbContext{/// <summary>/// TruckAwaitLog,数据表对象/// </summary>public virtual DbSet<TruckAwaitLog> TruckAwaitLogs { get; set; }/// <summary>/// TruckAwaitLogDetail,数据表对象/// </summary>public virtual DbSet<TruckAwaitLogDetail> TruckAwaitLogDetails { get; set; }/// <summary>/// TruckAwaitLogType,数据表对象/// </summary>public virtual DbSet<TruckAwaitLogType> TruckAwaitLogTypes { get; set; }/// <summary>/// TruckStatus,数据表对象/// </summary>public virtual DbSet<TruckStatus> TruckStatuss { get; set; }/// <summary>/// 车辆,数据表对象/// </summary>public virtual DbSet<车辆> 车辆s { get; set; }/// <summary>/// V人员信息,数据表对象/// </summary>public virtual DbSet<V人员信息> V人员信息s { get; set; }//IdentityServer接口实现public virtual DbSet<PersistedGrantEntity> PersistedGrants { get; set; }public SecondDbContext(DbContextOptions<SecondDbContext> options) : base(options){}}
}

2.3.2 构建应用层对象

    /// <summary>/// TruckAwaitLog,应用层服务接口实现/// </summary>[DisableAuditing][AbpAuthorize]public class TruckAwaitLogAppService : MyAsyncServiceBase<TruckAwaitLog, TruckAwaitLogDto, Guid, TruckAwaitLogPagedDto, CreateTruckAwaitLogDto, TruckAwaitLogDto>, ITruckAwaitLogAppService{private readonly IRepository<TruckAwaitLog, Guid> _truckAwaitLogRepository;private readonly IRepository<TruckAwaitLogDetail, string> _truckAwaitLogDetailRepository;private readonly IRepository<TruckAwaitLogType, string> _truckAwaitLogTypeRepository;private readonly IRepository<车辆, string> _truckRepository;private readonly IRepository<V人员信息, string> _renYuanRepository;private readonly IRepository<User, long> _userRepository;//用户信息仓储对象public TruckAwaitLogAppService(IRepository<TruckAwaitLog, Guid> truckAwaitLogRepository,IRepository<TruckAwaitLogDetail, string> truckAwaitLogDetailRepository,IRepository<TruckAwaitLogType, string> truckAwaitLogTypeRepository,IRepository<车辆, string> truckRepository,IRepository<V人员信息, string> renYuanRepository,IRepository<User, long> userRepository) : base(truckAwaitLogRepository){_truckAwaitLogRepository = truckAwaitLogRepository;_truckAwaitLogDetailRepository = truckAwaitLogDetailRepository;_truckAwaitLogTypeRepository = truckAwaitLogTypeRepository;_truckRepository = truckRepository;_renYuanRepository = renYuanRepository;_userRepository = userRepository;}

2.4 多模块关联查询、分组统计、列转行

-在 Application.Service 模块构建联合查询

 //Linq 构建关联查询 -异常停留类型统计表(按车俩)
//构建关联查询var query = from truckAwaitLog in _truckAwaitLogRepository.GetAll()join truckAwaitLogType in _truckAwaitLogTypeRepository.GetAll() on truckAwaitLog.TypeId equals truckAwaitLogType.Idjoin truck in _truckRepository.GetAll() on truckAwaitLog.MainTruckId equals truck.Idwhere truckAwaitLog.AddDate >= input.AddDateStart && truckAwaitLog.AddDate <= input.AddDateEndselect new TruckAwaitLogQueryDto{NameID = truck.Id,Name = truck.CCode_Name,// StopEventAreaTypeID = truckAwaitLogType.TypeId,StopEventArea = truckAwaitLogType.TypeName,TotalDuration = truckAwaitLog.TotalDuration};
//构建关联查询结构上实现分组统计var queryColumn = (from m in querygroup m by//new { m.NameID, m.Name, m.StopEventArea, m.StopEventAreaTypeID }new { m.NameID, m.Name, m.StopEventArea }into gselect new TruckAwaitLogQueryDto{NameID = g.Key.NameID,Name = g.Key.Name + g.Key.NameID,// StopEventAreaTypeID = g.Key.StopEventAreaTypeID,StopEventArea = g.Key.StopEventArea,TotalDuration = g.Sum(p => p.TotalDuration),Numbers = g.Count()}).ToList();
```csharp
//Linq 构建关联查询 -异常停留类型统计表(按驾驶员)//构建关联查询var query = from truckAwaitLog in _truckAwaitLogRepository.GetAll()join truckAwaitLogType in _truckAwaitLogTypeRepository.GetAll() on truckAwaitLog.TypeId equals truckAwaitLogType.Idjoin renyuan in _renYuanRepository.GetAll() on truckAwaitLog.MainUserId equals renyuan.Idwhere truckAwaitLog.AddDate >= input.AddDateStart && truckAwaitLog.AddDate <= input.AddDateEndselect new TruckAwaitLogQueryDto{NameID = renyuan.Id,Name = renyuan.CCode_Name,//  StopEventAreaTypeID = truckAwaitLogType.TypeId,StopEventArea = truckAwaitLogType.TypeName,TotalDuration = truckAwaitLog.TotalDuration};
//构建关联查询结构上实现分组统计var queryColumn = (from m in querygroup m bynew { m.NameID, m.Name, m.StopEventArea }into gselect new TruckAwaitLogQueryDto{NameID = g.Key.NameID,Name = g.Key.Name + g.Key.NameID,// StopEventAreaTypeID = g.Key.StopEventAreaTypeID,StopEventArea = g.Key.StopEventArea,TotalDuration = g.Sum(p => p.TotalDuration),Numbers = g.Count()}).ToList();

-在 Application.Service 封装完整代码供客户端调用

/// <summary>/// 自定义条件处理,暴漏API/// </summary>/// <param name="input">查询条件Dto</param>/// <returns></returns>[DisableAuditing]public async Task<List<dynamic>> CreateReportDataSourceWithUserQueryAsync(TruckAwaitLogPagedDto input){    //报表统计的维度 : 前台传过来分组维度和动态列字段//DEMO: 分组维度:{DimensionList:['Name']  车辆|人员//动态列字段:DynamicColumn:'StopEventArea'}List<string> DimensionList = new List<string>() { "Name" };string DynamicColumn = "StopEventArea";List<string> AllDynamicColumn = null;if (input.QueryType == "按车辆")//按车辆{//构建关联查询var query = from truckAwaitLog in _truckAwaitLogRepository.GetAll()join truckAwaitLogType in _truckAwaitLogTypeRepository.GetAll() on truckAwaitLog.TypeId equals truckAwaitLogType.Idjoin truck in _truckRepository.GetAll() on truckAwaitLog.MainTruckId equals truck.Idwhere truckAwaitLog.AddDate >= input.AddDateStart && truckAwaitLog.AddDate <= input.AddDateEndselect new TruckAwaitLogQueryDto{NameID = truck.Id,Name = truck.CCode_Name,// StopEventAreaTypeID = truckAwaitLogType.TypeId,StopEventArea = truckAwaitLogType.TypeName,TotalDuration = truckAwaitLog.TotalDuration};var queryColumn = (from m in querygroup m by//new { m.NameID, m.Name, m.StopEventArea, m.StopEventAreaTypeID }new { m.NameID, m.Name, m.StopEventArea }into gselect new TruckAwaitLogQueryDto{NameID = g.Key.NameID,Name = g.Key.Name + g.Key.NameID,// StopEventAreaTypeID = g.Key.StopEventAreaTypeID,StopEventArea = g.Key.StopEventArea,TotalDuration = g.Sum(p => p.TotalDuration),Numbers = g.Count()}).ToList();return await Task.FromResult(MyProject.Application.HY.OLAP.Report.Helper.ReportUtility.DynamicRow2ColeByLinq(queryColumn, DimensionList, DynamicColumn, out AllDynamicColumn));}else if (input.QueryType == "按驾驶员")//按人员{//构建关联查询var query = from truckAwaitLog in _truckAwaitLogRepository.GetAll()join truckAwaitLogType in _truckAwaitLogTypeRepository.GetAll() on truckAwaitLog.TypeId equals truckAwaitLogType.Idjoin renyuan in _renYuanRepository.GetAll() on truckAwaitLog.MainUserId equals renyuan.Idwhere truckAwaitLog.AddDate >= input.AddDateStart && truckAwaitLog.AddDate <= input.AddDateEndselect new TruckAwaitLogQueryDto{NameID = renyuan.Id,Name = renyuan.CCode_Name,//  StopEventAreaTypeID = truckAwaitLogType.TypeId,StopEventArea = truckAwaitLogType.TypeName,TotalDuration = truckAwaitLog.TotalDuration};var queryColumn = (from m in querygroup m bynew { m.NameID, m.Name, m.StopEventArea }into gselect new TruckAwaitLogQueryDto{NameID = g.Key.NameID,Name = g.Key.Name + g.Key.NameID,// StopEventAreaTypeID = g.Key.StopEventAreaTypeID,StopEventArea = g.Key.StopEventArea,TotalDuration = g.Sum(p => p.TotalDuration),Numbers = g.Count()}).ToList();//动态Linq方式实现行转列return await Task.FromResult(MyProject.Application.HY.OLAP.Report.Helper.ReportUtility.DynamicRow2ColeByLinq(queryColumn, DimensionList, DynamicColumn, out AllDynamicColumn));// return result   List<dynamic> result = ;}return null;}

2.5.使用Linq.Dynamic 构建行转列为报表提供数据源

需要nuget 引入 Linq.Dynamic。
传入原始数据源

    /// <summary>/// 报表工具类/// 须在nuget引入System.Linq.Dynamic/// </summary>public class ReportUtility{        // <summary>/// 动态Linq方式实现行转列/// </summary>/// <param name="listSource">原始数据集合</param>/// <param name="DimensionList">维度列(分组列)</param>/// <param name="DynamicColumn">动态列(要生成的列)</param>/// <returns>行转列后数据</returns>//private List<TruckAwaitLogQueryDto> GetTruckAwaitLogQueryDtoList(List<TruckAwaitLogType> listTypes, List<EntityTruckAwaitLogByVehicleUser> entityTruckAwaitLogBies)public static List<dynamic> DynamicRow2ColeByLinq<T>(List<T> listSource, List<string> DimensionList, string DynamicColumn, out List<string> AllDynamicColumn) where T : class{//获取所有动态列var columnGroup = listSource.GroupBy(DynamicColumn, "new(it as Vm)") as IEnumerable<IGrouping<dynamic, dynamic>>;List<string> AllColumnList = new List<string>();foreach (var item in columnGroup){if (!string.IsNullOrEmpty(item.Key)){AllColumnList.Add(item.Key);}}AllDynamicColumn = AllColumnList;var dictFunc = new Dictionary<string, Func<T, bool>>();foreach (var column in AllColumnList){var func = DynamicExpression.ParseLambda<T, bool>(string.Format("{0}==\"{1}\"", DynamicColumn, column)).Compile();dictFunc[column] = func;}//获取实体所有属性Dictionary<string, PropertyInfo> PropertyInfoDict = new Dictionary<string, PropertyInfo>();Type type = typeof(T);var propertyInfos = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);//数值列List<string> AllNumberField = new List<string>();foreach (var item in propertyInfos){PropertyInfoDict[item.Name] = item;if (item.PropertyType == typeof(int) || item.PropertyType == typeof(double) || item.PropertyType == typeof(float)){AllNumberField.Add(item.Name);}}//分组var dataGroup = listSource.GroupBy(string.Format("new ({0})", string.Join(",", DimensionList)), "new(it as Vm)") as IEnumerable<IGrouping<dynamic, dynamic>>;List<dynamic> listResult = new List<dynamic>();IDictionary<string, object> itemObj = null;T vm2 = default(T);foreach (var group in dataGroup){itemObj = new ExpandoObject();var listVm = group.Select(e => e.Vm as T).ToList();//维度列赋值vm2 = listVm.FirstOrDefault();foreach (var key in DimensionList){itemObj[key] = PropertyInfoDict[key].GetValue(vm2);}foreach (var column in AllColumnList){vm2 = listVm.FirstOrDefault(dictFunc[column]);if (vm2 != null){foreach (string name in AllNumberField){itemObj[name + column] = PropertyInfoDict[name].GetValue(vm2);}}}listResult.Add(itemObj);   }return listResult;}}

该方法处理后的数据如下。

3、 VUE TABLE 多级表头实现

数据结构比较复杂的时候,可使用多级表头来展现数据的层次关系。

3.1 导入业务API对象

import truckAwaitLog from '@/api/HYReport/truckawaitlog'  // 停车数据业务操作对象
import truckAwaitLogType from '@/api/HYReport/truckawaitlogtype' // 停车事件业务操作对象```css
class Api extends BaseApi {GetReportDataSource(data) {return request({url: this.baseurl + 'CreateReportDataSourceWithUserQueryAsync',method: 'get',params: data})}
class Api extends BaseApi {  GetStopEventAreas() {return request({url: this.baseurl + 'GetTruckAwaitLogType',method: 'get'})}

3.2 vue 查询面板

查询面板值得是查询功能区布局,包含查询条件的组合,功能按钮等, 比如多条件下拉组合、时间选择、类型选择等。

       <pane min-size="10" max-size="20"><el-card class="box-card" style="background-color:#eef1f6"><div slot="header" class="clearfix" style="text-align:center"><span><i class="el-icon-s-grid" />异常停留类型查询面板<i class="el-icon-s-grid" /></span></div></el-card><el-card class="box-card" style="background-color:#eef1f6"><!--查询条件区域 --><el-form ref="searchForm" :model="searchForm" label-width="100px" :inline="true"><template><el-form-item label="统计时间"><el-date-picker v-model="searchForm.AddDate" type="daterange" align="right" unlink-panels range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" :picker-options="pickerOptions" /></el-form-item></template><template><div><el-radio-group v-model="radiorules"><el-radio-button label="按驾驶员" /><el-radio-button label="按车辆" /></el-radio-group></div></template></el-form></el-card><el-card class="box-card" style="background-color:#eef1f6"><template><!--功能操作按钮 --><el-row style="float:right;padding-bottom:10px"><el-button-group><el-button icon="el-icon-search" type="primary" size="mini" round @click="search()">查询</el-button><el-button icon="el-icon-refresh-left" type="warning" size="mini" round plain @click="resetSeachForm('searchForm')">重置</el-button></el-button-group><el-button-group><el-button icon="el-icon-download" :loading="downloadLoading" type="primary" size="mini" round @click="handleDownload()">导出</el-button></el-button-group></el-row></template></el-card></pane>

3.2 vue 查询数据展示区

实际的数据查询结果。
组合表头,列合并分组
嵌套实现组合
动态列表头的生成

StopEventArea 是通过import truckAwaitLogType from ‘@/api/HYReport/truckawaitlogtype’ // 停车事件业务操作对象获取的事件类型。

动态列表头的数据源关联获取

  <el-table-column v-for="(item,i) in StopEventArea" :key="i" :prop="item.typeId" :label="item.typeName" align="center"><el-table-column :key="item.typeId" :prop="`Numbers`+item.typeName" label="次数" :formatter="NumbersFun" /><el-table-column :key="item.typeId" :prop="`TotalDuration`+item.typeName" label="时长(分)" :formatter="TotalDurationFun" /></el-table-column>

:label=“item.typeName”
:prop=“Numbers+item.typeName”

完整代码

这里注意返回数据的结构, vue遍历的时候动态变量赋值问题。

<pane style="background-color:#fff" title="异常停留类型统计表"><!--表格列表信息 --><el-table v-loading="listLoading" :data="listSources" border fit stripe highlight-current-row :header-cell-style="{background:'#eef1f6',color:'#606266'}" @selection-change="selectionChange" @sort-change="sortChange"><el-table-column align="center" sortable="custom" prop="Name" :label="this.radioVal" width="155"><template slot-scope="scope"><router-link tag="a" :to="{path:'/orderDetail',query:{id:scope.row.NameID}}">{{ scope.row.Name }}</router-link></template></el-table-column><el-table-column v-for="(item,i) in StopEventArea" :key="i" :prop="item.typeId" :label="item.typeName" align="center"><el-table-column :key="item.typeId" :prop="`Numbers`+item.typeName" label="次数" :formatter="NumbersFun" /><el-table-column :key="item.typeId" :prop="`TotalDuration`+item.typeName" label="时长(分)" :formatter="TotalDurationFun" /></el-table-column></el-table><!--分页部分 --><div class="block" style="height:70px;"><el-pagination :current-page="pageinfo.pageindex" :page-size="pageinfo.pagesize" :total="pageinfo.total" :page-sizes="[10,20,30,40]" layout="total, sizes, prev, pager, next" @size-change="sizeChange" @current-change="currentChange" /></div></pane>

ABP 多模块关联查询、分组统计、列转行、Vue 复合表头动态列相关推荐

  1. oracle 动态sql列转行_SQL Server中动态列转行

    http://www.cnblogs.com/gaizai/p/3753296.html 一.本文所涉及的内容(Contents) 三.实现代码(SQL Codes) (一) 首先我们先创建一个测试表 ...

  2. 六、Abp Vnext 中Efcore的多模块关联查询

    abp框架提供了非常棒的模块开发体验,这些模块是可复用的,并且也适用于开发微服务:既然模块可以独立发布,那么它的数据库配置也是独立的,对于使用efcore的模块,每个模块中都包含一个不同的Dbcont ...

  3. jpa 去重_spring boot jpa 表关联查询分组 group by 去重

    使用jpa操作多张表进行关联查询时,有重复数据需要分组去重 1)确定主表:将有重复数据的表格作为主表,表明关系 public class AttendanceRuleTypeItem implemen ...

  4. PL/SQL编程,关联查询/分组查询

    以scott用户登录案例库,通过游标显示相关信息 Oracle,plsql编程,关联查询,分组查询 1.关联查询 3.21 –通过游标,循环输出某个部门员工信息(员工编号.员工名字.部门名称) --关 ...

  5. MySQL数据库基础(多表关联查询、内外全连接、复合条件查询、子查询)

    文章目录 一.笛卡尔积查询 二.内.外.全连接查询 三.复合条件查询 四.子查询 五.EXIST判断 本篇文章主要介绍MySQL里的多表关联查询,其中包括了笛卡尔积查询.内连接查询.外连接查询.全连接 ...

  6. 怎么给oracle数据库列转行,oracle数据库 行转列 列转行详解

    [一].行转列 1.1.初始测试数据 表结构:TEST_TB_GRADE create table TEST_TB_GRADE ( ID        NUMBER(10)notnull, USER_ ...

  7. oracle列转行求和,Oracle行转列和列转行

    一.行转列 1.1.初始测试数据 表结构:TEST_TB_GRADE Sql代码: 1    create table TEST_TB_GRADE 2    ( 3      ID        NU ...

  8. mysql 列转行union all_MySQL中的列转行 - osc_qheq8wav的个人空间 - OSCHINA - 中文开源技术交流社区...

    mysql中的列转行 在工作中遇到的一个MySQL列转行的统计: 场景 用户访问app时会跳出标签选择页面让用户选择喜欢的标签,在数据库中记录的是数组样式的字符串,数据样式大致如下: id user_ ...

  9. oracle列转行用法,oracle 行转列 列转行

    1.概述 最近论坛很多人提的问题都与行列转换有关系,所以我对行列转换的相关知识做了一个总结,希望对大家有所帮助,同时有何错疏,恳请大家指出,我也是在写作过程中学习,算是一起和大家学习吧! 行列转换包括 ...

最新文章

  1. 第2关:实现一个链接存储的栈
  2. 菜鸟崛起 DB Chapter 2 MySQL 5.6的概述与安装
  3. ElasticSearch 基础概念学习(未完)
  4. infor wms 中英文对照_【融合·君豪】新君豪中英文学校第十周食谱
  5. python-多继承
  6. 看了一些东西,发现一些用css实现一些东西的小技巧就记录下来
  7. 关于tomcat的思考
  8. python逐行读取txt文件readline_Python File readline() 方法
  9. 基于深度学习的单目人体姿态估计方法综述(一)
  10. Windows 7 安装Docker实践(2021.6.21)
  11. 线性回归线性检验r_R:首次尝试线性回归
  12. LeetCode刷题-中心对称数
  13. vue3.0 结合element ui 开发后台ui框架
  14. 关于Quartus ii 在计算机从有线网切换到无线状态下出现的问题
  15. Map集合遍历常用方法总结,记得收藏哦
  16. 东华oj系统 52 k倍区间
  17. python求长整数_python 长整数
  18. 【100个 Unity实用技能】☀️ | Unity中设置 允许的最大帧数,锁定游戏的最大帧率(游戏锁帧)
  19. 英语语法总结--动名词
  20. Python利用tcp_socket实现文件下载器

热门文章

  1. 简单了解一下LB(Load Balance)
  2. 教你几招:30句哄女孩的“霸道”温馨话,不看后悔!
  3. 如果你要达到目标,首先要学会扎根
  4. JAVASE的内、外部比较器Comparable和Comparator
  5. 条码打印机代码解读!
  6. 计算机课对小学生的作用,信息技术在小学教学中的重要性
  7. Python—Numpy学习之【meshgrid函数】
  8. JAVA学习总结十五
  9. 为什么Cookie泄露对“贱人”来说是要命的?
  10. fake-useragent Maximum amount of retries reached解决方案