【问题标题】:limiting the rows to where the sum a column equals a certain value in MySQL在MySQL中将行限制为列的总和等于某个值
【发布时间】:2013-02-15 08:09:09
【问题描述】:

我想编写一个查询,它返回所有行,直到其中一个列值的总和达到某个值。

例如下表:

           DATE             ETC      Meeting
    2013-02-01 00:00:00    85482        1
    2013-02-01 00:00:00    47228        2
    2013-02-02 00:00:00    12026        4
    2013-02-03 00:00:00    78927        6
    2013-02-04 00:00:00    85662        2
    2013-03-05 00:00:00    47978        1
    2013-08-07 00:00:00     8582        1

如果我想获取行,直到列 Meeting 的总和等于 7。

           DATE             ETC      Meeting
    2013-02-01 00:00:00    85482        1
    2013-02-01 00:00:00    47228        2
    2013-02-02 00:00:00    12026        4

如果我想获取行,直到列 Meeting 的总和等于 13。

     DATE                   ETC      Meeting
    2013-02-01 00:00:00    85482        1
    2013-02-01 00:00:00    47228        2
    2013-02-02 00:00:00    12026        4
    2013-02-03 00:00:00    78927        6

【问题讨论】:

  • 您使用的是哪种 RDBMS,MS SQL Server、MySQL、PostgreSQL...?你试过什么?发布一些有效的查询,结果是否不正确无关紧要,这是一个起点,也许您离解决方案不远。
  • 您似乎没有主键/无法确定要考虑的行的顺序

标签: mysql sql


【解决方案1】:

这是一种无需存储过程的方法:

SET @msum := 0;
SELECT t1.* 
FROM (
    SELECT m.*,  
          (@msum := @msum + m.meetings) AS cumulative_meetings
    FROM meetings m 
    ORDER BY m.date ASC
) t1 
WHERE t1.cumulative_meetings <= 7;

【讨论】:

  • 对于大量数据,这实际上是一种更好、更快的解决方案。谢谢。
  • 如果每一行的会议数超过 X,则此查询将返回 0 行。
【解决方案2】:

这是一种适用于 MySQL 的方法:

SELECT
  O.Id,
  O.Type,
  O.MyAmountCol,
  (SELECT
     sum(MyAmountCol) FROM Table1
   WHERE Id <= O.Id) 'RunningTotal'
FROM Table1 O
HAVING RunningTotal <= 7

它涉及计算运行总数并在运行总数小于或等于给定数字时选择记录,在本例中为7

SQL Fiddle

【讨论】:

  • id 是从哪里来的?
  • 请注意,这可能是数据库服务器上的 O(N^2) 查询,因为子选择在查询结束时增长,并且也没有提前停止,所有总和都将被评估。如果选择的范围很小,它的优点是是单个查询(因此不需要存储过程等)。
【解决方案3】:

这个比所有的都好。

SET @runningTotal=0;
SELECT
  O.Id,
  O.Type,
  O.MyAmountCol,
  @runningTotal + O.MyAmountCol as 'RunningTotal',
  @runningTotal := @runningTotal + O.MyAmountCol
FROM Table1 O
HAVING RunningTotal <=7;

SQL Fiddle

查看两个查询的执行计划。

【讨论】:

  • 谢谢。对于那些想使用WHERE查询的人,请在HAVING中使用AND
【解决方案4】:

Hemant 您没有说明使用的 RDBMS。这是 t-sql 中的一个脚本,您可以使用它来解决您的问题。

DECLARE @numberToReach INT;
SET @numberToReach = 10; --you can change this

DECLARE @date DATETIME;
DECLARE @etc VARCHAR(20);
DECLARE @meeting INT;
DECLARE @temp_sum INT;

CREATE TABLE #tempTable
    (
        Dates DATETIME,
        Etcs VARCHAR(20),
        Meeting INT,
    )

DECLARE tempcursor CURSOR FOR
        SELECT *
        FROM YourTABLENAME
OPEN tempcursor;
FETCH NEXT FROM tempcursor INTO @date, @etc, @meeting;

WHILE(@@FETCH_STATUS = 0)
BEGIN
    SET @temp_sum = @temp_sum + @meeting;
    IF @temp_sum < @numberToReach 
    BEGIN
        INSERT INTO #tempTable
        (
            Dates,
            Etcs,
            Meeting
        )
        VALUES
        (
            @date, 
            @etc, 
            @meeting
        )

        FETCH NEXT FROM tempcursor INTO @date, @etc, @meeting;
    END 
END

SELECT * FROM #tempTable

CLOSE tempcursor
DEALLOCATE tempcursor

DROP TABLE  #tempTable

【讨论】:

    【解决方案5】:

    由于没有给出 DBMS,以下是适用于各种 DBMS 的 ANSI SQL 解决方案:

    select *
    from (
        select date_column, 
               etc, 
               sum(Meeting) over (order by date_column asc) run_sum
        from meetings
    ) t
    where run_sum <= 7
    order by date_column asc;
    

    (我使用列名date_column而不是date,因为DATE是SQL中的保留字,不应该用作列名以避免出现问题)

    【讨论】:

    • 日期不是保留字,在提供的示例中日期不是唯一的
    • @Strawberry: 是的date 关键字(但不是保留关键字)。甚至 MySQL 也这么认为:dev.mysql.com/doc/refman/5.5/en/keywords.html 并且日期不必是唯一的才能工作
    【解决方案6】:

    这是一个丑陋的方式:

    SELECT *
    FROM meetings m1
    WHERE (SELECT SUM(m2.Meeting) 
           FROM meetings m2 
           WHERE m2.DATE < m1.DATE OR (m2.DATE = m1.DATE AND m2.ETC >= m1.ETC)) <= 7
    

    排序首先基于DATE,然后以降序排列ETC,因为这似乎是我们必须继续进行的。请注意,如果这不是唯一的,您将得到错误的结果

    【讨论】:

      【解决方案7】:

      在Oracle中,我认为你可以使用SUM解析函数。你可以参考这里:http://www.adp-gmbh.ch/ora/sql/analytical/sum.html

      【讨论】:

        【解决方案8】:

        如果您使用的是 SQL Server,请使用 CROSS APPLY

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-08-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多