【问题标题】:Summing columns x through x+n in an SQL table对 SQL 表中的 x 到 x+n 列求和
【发布时间】:2018-08-06 17:38:34
【问题描述】:

我正在尝试对 SQL 表中的 x 到 x+n 列求和。本质上,我有多个表,其中包含成绩和 user_id。我想总结所有成绩以得出一个总成绩列,而不指定列名,因为每个表的名称和列数都会发生变化。例如,一个表可能有列(user_id、calculations、prelab、deductions),而另一个可能有(user_id、accuracy、precision、graphs、prelab、deductions)。

我可以重命名列 col1、col2、col3、col4、col5 等,但我不知道如何绕过不同数量的列。

【问题讨论】:

标签: php html mysql sql


【解决方案1】:

据我所知,如果不直接在 SQL 中实际指定列名,就无法对列组求和。在我看来,这是一个设计糟糕的架构,但这是一个单独的主题。

在任何情况下,您都需要在每个表中创建一个新列,其中包含该特定表中所有成绩的总和,例如称为total em>,然后,做这样的事情:

select user_id, sum(table1.total, table2.total, table3.total)
from table1, table2, table3
where table1.user_id = table2.user_id
and table2.user_id = table3.user_id 
group by user_id

【讨论】:

    【解决方案2】:

    1) 您可以编写一些 pl/sql 来访问数据字典并获取列,然后构造动态 sql 来完成正确添加它们的工作。

    2) 或者您可以在包含 user_id 和感兴趣列的总和的表上创建视图(视图本身可以通过编程方式构建 - 但这只需要发生一次,而不是每次您想要总数时)。

    但与简单地修复您的架构相比,上述任何一个都可能是过度杀伤。

    【讨论】:

      【解决方案3】:

      以下过程可能会奏效。

      它将在 INFORMATION_SCHEMA.COLUMNS 表中查找给定 tableName 的所有列名(不包括“userid” - 如果您使用的名称不同,这可能会发生变化)。
      该过程还创建了一个临时表(这也有待改进 - 如果在创建之前存在,则最好执行“删除”)以将总和存储到一个点。
      循环中的项目只是使用给定的 tableName 参数和来自游标的 columnName 构建一个 SQL UPDATE 语句并进行数学运算。 要对此进行测试(创建后):

      调用 myProcedure('tableName');

          DELIMITER //
      
          DROP PROCEDURE IF EXISTS myProcedure //
      
          CREATE PROCEDURE 
            myProcedure( tableName varchar(32) )
          BEGIN  
            DECLARE done INT DEFAULT FALSE;
            DECLARE columnName varchar(64);
            DECLARE cur1 CURSOR FOR SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = tableName and COLUMN_NAME <> 'userid';
            DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
      
            OPEN cur1;
      
            CREATE TEMPORARY TABLE intermediateresults(userid integer, sumOfScores integer);
            SET @st1 = CONCAT('INSERT INTO intermediateresults (SELECT DISTINCT userid, 0 FROM ',tableName,' )' );
            PREPARE stmt3 FROM @st1;
            EXECUTE stmt3;
      
            looping: LOOP
              FETCH cur1 into columnName;
              IF done THEN
                 LEAVE looping;
              END IF;
              SET @st1 = CONCAT('UPDATE intermediateresults set sumOfScores = sumOfScores + COALESCE( (SELECT ', columnName, ' FROM ',tableName, ' t WHERE t.userid=intermediateresults.userid) , 0)' );  
              PREPARE stmt3 FROM @st1;
              EXECUTE stmt3;
              DEALLOCATE PREPARE stmt3;
            END LOOP;
      
            CLOSE cur1;
            SELECT * FROM intermediateresults;
            DROP table intermediateresults;  
          END 
          //
      
          DELIMITER ;
      

      做这种事情时可能会感兴趣:
      INFORMATION_SCHEMA 还包含以下数据:
      DATA_TYPE:可用于测试特定列是否具有您期望的实际类型 - 可以将 DATA_TYPE='int' 等条件添加到游标定义以确保它实际上是一个 int(假设要求和的列实际上是 INT)
      ORDINAL_POSITION:如果您知道列的顺序,则可以使用它应该到达(例如,对于最后四个是内务处理的情况)
      TABLE_SCHEMA:上面的过程假定该表仅存在于当前默认模式中。使用它需要在过程中添加一个额外的参数,并在构造的 SQL 语句中稍作更改。

      【讨论】:

        猜你喜欢
        • 2021-12-15
        • 2016-05-21
        • 2018-05-17
        • 1970-01-01
        • 1970-01-01
        • 2022-06-10
        • 1970-01-01
        • 2016-02-27
        • 1970-01-01
        相关资源
        最近更新 更多