【问题标题】:MySQL - Insert multiple rows based on column valueMySQL - 根据列值插入多行
【发布时间】:2012-12-21 22:26:33
【问题描述】:

我的查询工作正常,只是想知道是否有更好的方法可以在没有游标/循环/php 端的情况下执行此操作。我做 DBA 已经 5 年多了,刚刚遇到 := 语句。很酷。

表格 (tblPeople) 包含人员 ID 和他们购买的门票数量。

PersonId  NumTickets
1         3  
2         1 
3         1

然后我想在一个新表 (tblTickets) 中为每个人分配单独的票,具体取决于他们购买了多少票。 TicketId 是一个键,自动递增列。

TicketId  PersonId
100       1
101       1
102       1 
103       2
104       3 

这里是代码。它一遍又一遍地循环遍历整个 tblPeople,增加一个名为 rowID 的新计算列。然后我根据他们在 WHERE 子句中购买的票数过滤掉这些行。我看到的问题是子查询很大,我拥有的人越多,子查询就越大。只是不确定是否有更好的方法来写这个。

INSERT INTO tblTickets (PersonId)
    SELECT PersonId
    FROM (
        SELECT s.PersonId, s.NumTickets,
            @rowID := IF(@lastPersonId = s.PersonId and @lastNumTickets = s.NumTickets, @rowID + 1, 0) AS rowID,
            @lastPersonId := s.PersonId,
            @lastNumTickets := s.NumTickets
        FROM tblPeople m,
            (SELECT @rowID := 0, @lastPersonId := 0, @lastNumTickets := 0) t
            INNER JOIN tblPeople s 
        ) tbl
    WHERE rowID < NumTickets

【问题讨论】:

  • 这似乎引用了一个奇怪的模式。是否根据汇总的票数信息在事后分配票证 ID?为什么您不创建应用程序添加的票证 ID(即用户购买 3 张票,并为每张票添加了三行唯一的 ID)?
  • 实际的ticketId数字与用户无关。他们只需要知道他们购买了 x 张票,而不是实际票号。每次我抽出一个数字时,我都会清理门票表,因为我每次都会根据不同的条件进行绘制,并且我不希望“增量键列”中有任何漏洞来保持 random() 公平。如果我有键 1、2、3、4、10,那么 random() 的工作方式就是这样。如果 random() 选择 5-9,它将舍入到 10,给出不公平的赔率。
  • 引用the docs:“作为一般规则,您永远不应该为用户变量赋值并在同一语句中读取该值。您可能会得到预期的结果,但这不能保证。涉及用户变量的表达式的求值顺序是未定义的,并且可能会根据给定语句中包含的元素而改变;此外,不保证此顺序在 MySQL 服务器的版本之间是相同的。”因此,您的查询可能会在升级后意外中断。

标签: mysql loops cursor


【解决方案1】:

我会添加一个实用程序表Numbers,其中包含从 1 到一个人可以购买的最大票数的所有数字。然后你可以这样做:

INSERT INTO tblTickets (PersonId)
SELECT s.PersonId
FROM tblPeople s, Numbers n
WHERE n.number <= s.NumTickets

【讨论】:

  • 非常感谢@MvG。由于主机的原因我无法创建触发器或sp,所以这个'所有查询'只是一个简单而完美的。我用循环和游标在我的脑海里让它变得更难了。再次非常感谢。
【解决方案2】:

以下存储过程将满足您的目的......

DELIMITER $$

USE <your database name> $$

DROP PROCEDURE IF EXISTS `update_ticket_value2`$$

CREATE PROCEDURE `update_ticket_value2`()
BEGIN
DECLARE index_value INT;
DECLARE loop_variable INT;  


SET @KeyValue = 100;
SET @LastPersonID = 0;
SET @TicketNum = 0;

SET @PersonIDToHandle = 0;

SELECT @PersonIDToHandle = PersonID, @TicketNum = NumTickets
FROM tblPeople
WHERE PersonId > @LastPersonID
ORDER BY PersonId
LIMIT 0,1;

WHILE @PersonIDToHandle IS NOT NULL
DO
    SET loop_variable = 0;

    WHILE(loop_variable < @TicketNum) DO
        INSERT INTO tblTickets(TicketId, PersonId) VALUES(@KeyValue + loop_variable, @PersonIDToHandle);
        SET loop_variable = loop_variable + 1;
    END WHILE;  

    SET @LastPersonID = @PersonIDToHandle;
    SET @PersonIDToHandle = NULL;
    SET @KeyValue = @KeyValue + @TicketNum;

    SELECT @PersonIDToHandle := PersonID, @TicketNum := NumTickets
    FROM tblPeople
    WHERE PersonId > @LastPersonID
    ORDER BY PersonId
    LIMIT 0,1;
END WHILE;

    END$$

DELIMITER ;

调用过程为:

CALL update_ticket_value2();

希望对你有帮助...

【讨论】:

  • 我的主机无法使用 sp。必须全部查询。 @MvG 发布了一个简单的设计。
猜你喜欢
  • 2016-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-03
  • 1970-01-01
  • 2021-12-20
相关资源
最近更新 更多