行转列--将多行数据转成多行多列的Table结构

这篇具有很好参考价值的文章主要介绍了行转列--将多行数据转成多行多列的Table结构。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

功能描述

21年做的一个功能,涉及到将行数据转化成列数据。边查边做,一点一点的尝试着做好。当时感觉有点吃力。完成之后本想记录,但一直拖延至今。最近再次接手与这个功能相关的业务,整理了之前写的代码,趁此机会记录下来。

功能界面

界面中是一个三级结构:L1级【Test Sample】, L2级【ABV, ABW,CO2,O2, pH】,L3级【白色表格中的数据:Date,Actual, Entered By】。

行转列--将多行数据转成多行多列的Table结构

数据表

为了实现页面显示的三级结构,表中添加了Parent ID字段存数据关系。L1级ParentID为NULL,L2级ParentID存的是L1级的ID,L3级ParentID存L2级ID。如果想更容易查询出L1 或 L2级数据,可以为它们单独添加标识符字段(项目中,我是单独设置了L1 & L2的标识字段,这里省略了)。

行转列--将多行数据转成多行多列的Table结构

以上是这个功能的界面和数据表。下面是这个功能的一次改进,也是这篇想要记录的内容。

改进:

现在想做的:在手机上依然显示左侧的效果。在PC和PAD大屏幕上显示右侧的效果。这就涉及到了行转列,将平面数据转成合并为多行多列Table表格数据。

行转列--将多行数据转成多行多列的Table结构

分析:

  1. 左侧 → 转化→ 右侧效果(重点)。
  • 对应关系:

    • L1 转化后对应Table标题

    • L2 转化后对应Table的多个列标题

    • L3 转化后作为数据填充到Table数据区域 【核心:时间 L3级每一行时间一致的会合并到Table中的同一行当中。不一致会分成多行】如下图:

行转列--将多行数据转成多行多列的Table结构

  1. 右侧Table 相关操作 (作为补充,可以忽略):
  • 右侧 → 转化 → 左侧: 只要ParentID正确就可以。

  • 表格中的操作 【重点】

    • 新增:每一行有多少列就需要保存多少条记录 【ParentID = 列标题.ID。这些记录的时间是一致的

    • 修改:不支持。【项目中是用来做Logs记录的不支持在界面中更改数据】

    • 删除:删除的一行是数据库中的多条记录,传多个ID,ids

    • 查询:只要保证1是正确的,刷新页面,数据就可以正常回显。

思路:

行转列--将多行数据转成多行多列的Table结构

如果我们可以将用到的所有数据查询出来,转化成一个可以画出Table的数据结构。前端页面获取到这个数据结构使用双层for循环将Table画出来。那么,这个问题是不就可以解决了呢?

  • 两个问题:

    1. 可以画出Table的数据结构长什么样呢?

    2. 如何转化构建这种数据结构呢?

问题1,结合上面的分析,好像容易想到数据结构长什么样。至少需要包括这么几点:Table名字、列标题列表List、时间列表List、数据字典【一个列标题 + 一个时间,可以从数据字典中查一个数据?】。如下图:

行转列--将多行数据转成多行多列的Table结构

问题2,如何转化构建这种数据结构呢?

  • Table名字:查询L1级数据

  • 列标题列表List:查询出L2级数据,列表 【使用ParentID = L1.ID查询】

  • 时间列表List:查询出L3级数据,GROUP BY Date,列表 【ParentID IN L2.IDs】

  • 数据字典: 查询出L3级数据,字典 【怎么转上图左侧中的Dict部分呢?】

实现:行转列-构建Table数据结构

下面是数据表,假设表名叫Logs

行转列--将多行数据转成多行多列的Table结构

后端:

核心代码,使用C#实现。删除了业务和敏感代码,只保留了核心的逻辑处理部分。

internal static Dictionary<string, object> Get_Data(int SampleID)
{
    Dictionary<string, object> ResultDict = new();
    Dictionary<int, object> DataDict = new();
    List<Dictionary<string, object>> DateList = new();

    // 1. 查询SQL。 两点:a,3级数据的关联关系; b, 先按列分组,再按行(时间)分组
    StringBuilder sqlB = new();
    sqlB.Length = 0;
    sqlB.AppendLine("SELECT ");
    sqlB.AppendLine("   MyDataLogs.ID ");
    sqlB.AppendLine(" , MyDataLogs.ParentID ");
    sqlB.AppendLine(" , MAX(MyDataLogs.Name) AS Name ");
    sqlB.AppendLine(" , MAX(MyDataLogs.ActualValue) AS ActualValue ");
    sqlB.AppendLine(" , MAX(MyDataLogs.Date) AS Date ");
    sqlB.AppendLine(" , MAX(MyDataLogs.UpdatedBy) AS UpdatedBy ");
    sqlB.AppendLine("FROM Logs AS MyDataLogs ");  // L3级数据 【数据】
    sqlB.AppendLine("INNER JOIN Logs AS MyColumnLogs ON MyDataLogs.ParentID = MyColumnLogs.ID "); // L3.ParentID = L2.ID 【数据 -> 列标题】
    sqlB.AppendLine("WHERE MyColumnLogs.ParentID = " + BC_Fmt.FDataInt(SampleID) + " "); // L2.ParentID = L1.ID 【列标题 -> Table】
    sqlB.AppendLine("GROUP BY ");
    sqlB.AppendLine("   MyDataLogs.ParentID ");  // 先横向按标题分组
    sqlB.AppendLine(" , MyDataLogs.Date "); // 再纵向按时间分组
    sqlB.AppendLine("ORDER BY ");
    sqlB.AppendLine("   MyDataLogs.ParentID ");
    sqlB.AppendLine(" , MyDataLogs.Date ");
    sqlB.AppendLine(" , MyDataLogs.ID ASC ");
    sqlB.AppendLine(";");
    BC_Recordset myLogRs = SQL2Rs(sqlB.ToString());

    // 2. 构建数据结构。 构建出Dictionary<列,Dictionary<时间行, 数据对象>>(JAVA:Map<列,Map<时间行, 数据对象>>)的数据结构 
    Dictionary<string, object> TempDateLogsDict = new();
    int PrevParentID = -1;
    while (!myLogRs.EOF())
    {
        int ParentID = myLogRs.ItemInt("ParentID");
        if (PrevParentID != ParentID)
        {
            // 2.2 新的一列开始,将上一列的<时间,数据>字典 放到 <列,<时间,数据>>字典中               
            if (PrevParentID != -1)
            {
                DataDict.Add(PrevParentID, TempDateLogsDict);
            }
            TempDateLogsDict = new();
        }

        /*
            2.1 将每一列的数据转化为 时间 -> 数据的形式
                列1:{
                        时间1: { 数据对象 },
                        时间2:{ 数据对象 },
                        ....
                    }
        */
        Dictionary<string, object> LogDict = new();
        string Date = myLogRs.Item("Date");
        LogDict.Add("ID", myLogRs.ItemInt("ID"));
        LogDict.Add("ParentID", myLogRs.ItemInt("ParentID"));
        LogDict.Add("DateDisplay", Date);
        LogDict.Add("ActualValue", myLogRs.Item("ActualValue"));
        LogDict.Add("EnteredBy", myLogRs.Item("UpdatedBy"));
        LogDict.Add("Name", myLogRs.Item("Name"));
        TempDateLogsDict.Add(Date, LogDict);

        PrevParentID = ParentID;
        myLogRs.MoveNext();

        if (myLogRs.EOF())
        {
            // 2.3 将最后一列的<时间,数据>字典 放到 <列,<时间,数据>>字典中 
            DataDict.Add(PrevParentID, TempDateLogsDict);
        }
    }
    myLogRs.Close();

    // 3. 构建返回数据结构
    ResultDict.Add("ColumnList", Get_ColumnList(SampleID));  // 获取列List数据
    ResultDict.Add("DataDict", DataDict);
    ResultDict.Add("SampleID", SampleID);
    ResultDict.Add("SampleName", SampleName);
    ResultDict.Add("DateList", Get_DateList(SampleID)); // 获取时间行List数据
    return ResultDict;
}

整合:可以将获取列List和时间行List的逻辑整合到上述SQL中。

思路:

  1. 时间数据SQL中已包含,只需在SQL中加上列信息。即MyColumnLogs相关的SELECT语句。

  2. 可以使用字典或Set对列数据和时间数据去重。

  3. 将去重后的数据转成List。

前端:

核心代码,使用到了Vue模板语法。使用双层for循环将table画出来即可。

<table >
    <thead>
        <tr>
            <input type="hidden" id="id" :value="id">
            <th></th>
            <th>Date</th>
            <!-- 横向循环填充列标题 -->
            <template v-for="myLog in Data.ColumnList">
                <th>
                    <input type="hidden" id="ID" name="ID" :value="myLog.ID">
                    <p>
                        <span>{{myLog.Name}}</span>
                    </p>
                </th>
            </template>
            <th>Entered By</th>
        </tr>
    </thead>
    <tbody>
        <!-- 纵向循环 每一行 -->
        <template v-for="myDate in Data.DateList">
            <tr>
                <td>
                    <span >Delete btn</span>
                </td>
                <td class="ecp-field" style="padding:3px 5px;">
                    {{myDate.DateDisplay}}
                </td>
                <!-- 横向循环 每一列 -->
                <template v-for="myColumn in Data.ColumnList">
                    <td>
                        <template v-if="Data.DataDict[myColumn.ID] && Data.DataDict[myColumn.ID][myDate.Date]">
                                <span>
                                    <!-- 使用 列 + 行 -> 取出每一个元素数据 -->
                                    {{(Data.DataDict[myColumn.ID][myDate.Date]).ActualValue}}
                                </span>
                        </template>
                    </td>
                </template>
                <td class="ecp-field" style="padding:3px 5px;">
                    {{myDate.EnteredBy}}
                </td>
            </tr>
        </template>
    </tbody>
</table>

总结:

行数据与列数据相互转化可能需要考虑两点:

  1. 对应关系

  2. 多行要合并成一行多列的数据,时间要一致。依照哪个字段转化,同为一行的哪个字段的值就需要一致。文章来源地址https://www.toymoban.com/news/detail-746545.html

到了这里,关于行转列--将多行数据转成多行多列的Table结构的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • vue elementui 实现从excel从复制多行多列后粘贴到前端界面el-table

    可以全部复制粘贴,也可以单独对某行、某列进行复制粘贴 从excel复制粘贴到前端页面的table上 html部分: js部分:

    2024年02月04日
    浏览(45)
  • chatgpt赋能python:Python行转列:如何高效地处理大数据集

    Python是一种广泛使用的编程语言,最初用于Web开发,如今已成为专业开发、科学计算和数据分析等领域的一种首选语言。Python非常方便,尤其是在处理大数据集时。本文将介绍如何使用Python将行数据转换成列数据,以及如何在这个过程中优化效率。 行转列指的是将一组数据从

    2024年02月06日
    浏览(39)
  • Hive的行列转换(行转多列、多列转行、行转单列、单列转行)

    在实际使用Hive的过程中,常常会涉及到行列转换,细分的话,有下面4种类型的行列转换,分别是: 行转多列 多列转行 行转单列 单列转行 下面我们通过样例介绍每种行列转换的实现方法。 样例表 班级成绩表: 姓名(name) 学科(subject) 成绩(score) 行列转换思路分析及实现 行转

    2024年02月15日
    浏览(71)
  • SQL实现一行数据分组后转多行多列

    在统计一些指标时,通常会有多个指标需要分组进行聚合,但是 数据源的粒度可能并非是指标分组的粒度 。举个例子,比如从访客表中提取访客的数据,每行数据有每个平台的首次访问时间;另外要做一个平台统计表,其中的一个指标统计的是各个平台近1天、7天、30天的新

    2024年02月14日
    浏览(30)
  • Hive SQL 中ARRAY或MAP类型数据处理:lateral view explode()/posexplode()——行转列函数

    前言:在对表数据进行批量处理过程中,常常碰上某个字段是一个array或者map形式的字段,一列数据的该字段信息同时存在多个值,当我们需要取出该数组中的每一个值实现一一对应关系的时候,可以考虑使用lateral view explode()/posexplode() 进行处理。 一、提要:explode()本身是

    2024年02月04日
    浏览(37)
  • sql 行转列

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 实现行转列的两种方式,case when 与piovt 函数的使用例子与比对 示例:如需要将左边的表格转换成右边的表格 首先,根据资产属性先将数据分成四列 代码如下:` 结果如下: I 这样看起来比较乱,需要根

    2024年02月09日
    浏览(33)
  • PostgreSQL如何行转列

    PostgreSQL如何行转列 方法一: group by + sum + case when 方法二: 用postgresql的crosstab交叉函数 方法三: group by + string_agg + split_part(分组,行转列,字符切割) group by + string_agg

    2024年02月11日
    浏览(41)
  • Mysql行转列函数

    group_concat() 例: select oid from Test;  select group_concat( oid ) from Test;

    2024年02月14日
    浏览(31)
  • greenplum行转列

    项目中需要将150w的数据转为1500列的大宽表数据。 最开始尝试了网上提供的两种方法: 实际业务中10行*1500列数据查询并插入需要25秒左右(测试服务器性能比较差) case when的问题是每个case when的语句都会把分组后的数据判断一下,时间复杂度为O²(O为行转列后的列数),非

    2024年02月03日
    浏览(32)
  • mysql 行转列

    以下是其中比较常见的几种方法: 使用GROUP_CONCAT函数 可以使用GROUP_CONCAT函数将多行数据合并为一行,并以逗号或其他分隔符进行分隔。通过SELECT语句和GROUP BY子句,可以将数据行转换为列。具体语法如下: 其中,id表示非透视列,status表示需要转换为列的字段,value表示需要

    2024年02月16日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包