【问题标题】:Select rows until a total amount is met in a column (mysql)选择行,直到在列中满足总金额(mysql)
【发布时间】:2023-03-07 08:40:01
【问题描述】:

我在 SF 中看到过这个问题,但我是一个菜鸟,我无法让我的大脑在他们周围出现问题。如果这感觉像是重复,请原谅我。

我的样本表

-------------------------- 身份证 |供应商 |数量 -------------------------- 1 1 2 2 1 2 3 2 5 4 3 2 5 1 3 6 2 4

我需要获取行“UNTIL”,对于特定供应商 ID,“QTY”的累积总数等于或大于 5(按降序排列)。

在本例中,对于供应商 1,它将是 ID 为 5 和 2 的行。

Id - 唯一主键 供应商 - 外键,供应商信息还有另一个表。 数量 - 双

【问题讨论】:

    标签: mysql sql conditional


    【解决方案1】:

    标准 SQL 没有“我要达到什么行号”的概念,因此只能使用称为游标的东西来实现。使用游标编写代码就像在其他语言中使用 for 循环编写代码一样。

    这里有一个如何使用游标的例子:

    http://dev.mysql.com/doc/refman/5.0/en/cursors.html

    【讨论】:

    • 您好 Patashu,谢谢您的回复。对不起,如果我的问题令人困惑。但是,我不需要获取行号。只是整行的所有内容。就像在一个典型的查询中一样。 IE:我需要运行查询“SELECT * FROM mytable WHERE supplier=1,直到总数量 >= 5 按 DESC 订购。类似的东西。只是不知道如何获取所有记录,直到总数 >= 5。抱歉,如果我让它更混乱了
    • 这个表有一个顺序键(它是一个自动递增的整数,但也可以很容易地是在日期/时间戳和供应商 ID 上形成的复合键),所以我们不限于游标在这种情况下。
    【解决方案2】:

    这个怎么样?使用两个变量。

    SQLFIDDLE DEMO

    查询:

    set @tot:=0;
    set @sup:=0;
    
    select x.id, x.supplier, x.ctot
    from (
    select id, supplier, qty,
    @tot:= (case when @sup = supplier then
    @tot + qty else qty end) as ctot,
    @sup:=supplier
    from demo
    order by supplier asc, id desc) x
    where x.ctot >=5
    ;
    
    | ID | SUPPLIER | CTOT |
    ------------------------
    |  2 |        1 |    5 |
    |  1 |        1 |    7 |
    |  3 |        2 |    5 |
    

    【讨论】:

    • @ElaBuwa 看看 thsi 和评论,order by id desc 在匹配cumulative total >=5 方面不是很清楚
    • 嗨,B,感谢您不厌其烦地设置 sqlfiddle。我需要它采用 DESC 格式,因为这是与库存/库存相关的表。如果我需要获取 1 个供应商的行,这会起作用吗?整个“@”的东西有点新,现在做一些谷歌搜索。 :D。再次非常感谢您。一定会检查并更新线程
    • 如果您想达到5 的累计总数,那么它可以跟踪相关的ids。否则嗯...顺便说一句,以@ 开头的每个单词都是一个变量:)
    • @ElaBuwa 看来你需要得到<=5 表示ID 降序排列最多5 个,然后ID 5, 2supplier 1 选中,请玩家稍微评论一下.顺便说一句,以@ 开头的每个单词都是variable :) 然后您可以过滤掉任何没有max total of 5 的供应商
    • 是否有可能获得总和数量 5 交叉记录和未交叉总和供应商记录的最大值记录,就像我在这个截图中提到的那样? nimb.ws/FVSyeW
    【解决方案3】:

    这是一个关于光标的粗略演示,可能会有所帮助。

    CREATE TABLE #t
    (
        ID       INT IDENTITY,
        Supplier INT,
        QTY      INT
    );
    
    
    TRUNCATE TABLE #t;
    
    INSERT  INTO #t (Supplier, QTY)
    VALUES         (1, 2),
    (1, 2),
    (2, 5),
    (3, 2),
    (1, 3);
    
    DECLARE @sum AS INT;
    
    DECLARE @qty AS INT;
    
    DECLARE @totalRows AS INT;
    
    DECLARE curSelectQTY CURSOR
        FOR SELECT   QTY
            FROM     #t
            ORDER BY QTY DESC;
    
    OPEN curSelectQTY;
    
    SET @sum = 0;
    
    SET @totalRows = 0;
    
    FETCH NEXT FROM curSelectQTY INTO @qty;
    
    WHILE @@FETCH_STATUS = 0
        BEGIN
            SET @sum = @sum + @qty;
            SET @totalRows = @totalRows + 1;
            IF @sum >= 5
                BREAK;
        END
    
    SELECT   TOP (@totalRows) *
    FROM     #t
    ORDER BY QTY DESC;
    
    CLOSE curSelectQTY;
    
    DEALLOCATE curSelectQTY;
    

    【讨论】:

    • 是上面的存储过程只检索那些大于或等于5的记录吗?
    【解决方案4】:
    SELECT x.* 
      FROM supplier_stock x 
      JOIN supplier_stock y  
        ON y.supplier = x.supplier 
       AND y.id >= x.id 
     GROUP 
        BY supplier
         , id 
    HAVING SUM(y.qty) <=5;
    

    【讨论】:

    • 这几乎可以工作。目标是获得数量 >= 5。
    【解决方案5】:

    它并不漂亮,但我认为它可以做到,也许它可以成为不那么麻烦的东西的基础。请注意,我使用“假”INNER JOIN 只是为了第一次初始化一些变量——它没有其他作用。

    SELECT ID,
           supplier,
           qty,
           cumulative_qty
    FROM
    (
        SELECT
            ID,
            supplier,
            qty,
            -- next line keeps a running total quantity by supplier id
            @cumulative_quantity := if (@sup <> supplier, qty, @cumulative_quantity + qty) as cumulative_qty,
            -- next is 0 for running total < 5 by supplier, 1 the first time >= 5, and ++ after
            @reached_five := if (@cumulative_quantity < 5, 0, if (@sup <> supplier, 1, @reached_five + 1)) as reached_five,
            -- next takes note of changes in supplier being processed
            @sup := if(@sup <> supplier, supplier, @sup) as sup
        FROM
        (
            --this subquery is key for getting things in supplier order, by descending id
            SELECT *
            FROM `sample_table`
            ORDER BY supplier, ID DESC
         ) reverse_order_by_id
        INNER JOIN
        (
            -- initialize the variables used to their first ever values
            SELECT @cumulative_quantity := 0, @sup := 0, @reached_five := 0
        ) only_here_to_initialize_variables
    ) t_alias
    where reached_five <= 1 -- only get things up through the time we first get to 5 or above.
    

    【讨论】:

    • 另外,请注意,您可以删除最外层的选择以查看包含所有变量的 SELECT 正在执行的操作。看到它会有所帮助。
    猜你喜欢
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-17
    • 1970-01-01
    相关资源
    最近更新 更多