在SQL

时间:2015-12-25 19:14:11

标签: sql sql-server sql-insert

我有一个简化的表格如下:

group   index    value
1       1        text 1
1       2        text 2
1       3        text 3
2       1        text 4
2       2        text 5
2       3        text 6

Group是一个外键,也用于对表中的项目进行分组。

索引是用于对组内项目进行排序的内部索引。

文字只是一个价值。

然后,如果我执行插入或运行存储过程来执行插入

INSERT INTO Table VALUES (1, 2, 'new text')

我想更新组1项的索引,因此表格如下所示:

group   index    value
1       1        text 1
1       2        new text (inserted)
1       3        text 2   (index updated)
1       4        text 3   (index updated)
2       1        text 4
2       2        text 5
2       3        text 6

(在MS SQL-Server 2008上运行)

2 个答案:

答案 0 :(得分:3)

这是您可以使用的商店程序。取3个参数,grp,idx和value:

while (true) {
    //manage multiple connections
    $changed = $clients;
    //returns the socket resources in $changed array
    socket_select($changed, $null, $null, 0, 10);

    //check for new socket
    if (in_array($socket, $changed))
    {
        $socket_new = socket_accept($socket); //accept new socket
        $clients[] = $socket_new; //add socket to client array

        $starting_coordinate_x = rand(100,400);
        $starting_coordinate_y = rand(100,400);

        $header = socket_read($socket_new, 1024); //read data sent by the socket
        perform_handshaking($header, $socket_new, $host, $port); //perform websocket handshake

        socket_getpeername($socket_new, $ip); //get ip address of connected socket

        //make room for new socket
        $found_socket = array_search($socket, $changed);
        unset($changed[$found_socket]);

        $new_player = new Player();
        $new_player->player_number = $number_of_players;
        $new_player->x_coordinate = $starting_coordinate_x;
        $new_player->y_coordinate = $starting_coordinate_y;

        $array_of_players[] = $new_player;

        $number_of_players++;

        $response_text = mask(json_encode(array('type'=>'new_player','starting_coordinate_x'=>$starting_coordinate_x,
                              'starting_coordinate_y'=>$starting_coordinate_y, 'player_number'=>($number_of_players-1))));
        send_message($response_text); //send data
    }

    //loop through all connected sockets
    foreach ($changed as $changed_socket) 
    {           
        //check for any incomming data
        while(socket_recv($changed_socket, $buf, 1024, 0) >= 1)
        {
            $received_text = unmask($buf); //unmask data
            $tst_msg = json_decode($received_text); //json decode 

            if($tst_msg->type === 'player_position')
            {
                $x_coordinate = $tst_msg->x_coordinate;
                $y_coordinate = $tst_msg->y_coordinate;
                $player_number = $tst_msg->player_number;

                //prepare data to be sent to client
                $response_text = mask(json_encode(array('type'=>'player_position', 'player_number'=>$player_number,
                'x_coordinate'=>$x_coordinate, 'y_coordinate'=>$y_coordinate)));
                send_message($response_text); //send data
            }
            else if($tst_msg->type === 'request_for_existing_players')
            {
                //prepare data to be sent to client
                $response_text = mask(json_encode(array('type'=>'request_for_existing_players','number_of_players'=>$number_of_players)));
                send_message($response_text); //send data

                for($a = 0; $a != $number_of_players; ++$a)
                {
                    //$text = mask(json_encode(array('type'=>'player_position', 'player_number'=>$a,
                                 //'x_coordinate'=>($array_of_players[$a]->x_coordinate), 'y_coordinate'=>($array_of_players[$a]->y_coordinate))));

                    //send_message($text); //send data
                }
            }

            break 2; //exits this loop
        }

        $buf = @socket_read($changed_socket, 1024, PHP_NORMAL_READ);
        if ($buf === false) { // check disconnected client
            // remove client for $clients array
            $found_socket = array_search($changed_socket, $clients);
            socket_getpeername($changed_socket, $ip);
            unset($clients[$found_socket]);

            --$number_of_players;
            //notify all users about disconnected connection
            $response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' disconnected')));
            send_message($response);
        }
    }
}

用法:

CREATE PROCEDURE ReIndex
@grp int,
@idx int,
@value nvarchar(30)
AS
IF NOT EXISTS(SELECT 1 FROM [tbl] WHERE grp = @grp and idx =@idx)
INSERT INTO tbl VALUES (@grp, @idx, @value)
else
update tbl
set idx = idx+1
where
grp =@grp and
idx >= @idx

INSERT INTO tbl VALUES (@grp, @idx, @value)

sqlfiddle:http://sqlfiddle.com/#!3/3323d/11

答案 1 :(得分:0)

在这个答案中,我假设第一列名称是 grp idx ,因为 group index 是SQL中的保留字。

您可以使用MAX(idx)+1公式使用下一个可用的 idx 值,如下所示:

INSERT INTO t1(grp, idx, value)
SELECT 1, IFNULL(MAX(idx),0)+1, 'new text'
FROM   t1
WHERE  grp = 1;

但是这样两个大约在同一时间插入的记录可能会得到相同的 idx 值。为避免这种情况,您可以在插入记录时锁定表格。您可以通过使用表锁定/解锁语句包装上述语句来实现此目的:

LOCK TABLES t1;
...
UNLOCK TABLES;

但是,此方法不能在程序中使用。解决方案涉及创建交易和SELECT ... FOR UPDATE。请注意,您需要InnoDB Storage

CREATE PROCEDURE ins_val(IN pgrp int, IN pvalue varchar(200)) 
BEGIN
    DECLARE newidx INT;
    START TRANSACTION;

        SELECT IFNULL(MAX(idx),0)+1
        INTO   newidx
        FROM   t1
        WHERE  grp = pgrp;
        FOR UPDATE;

        INSERT INTO t1(grp, idx, value)
        VALUES (pgrp, newidx, pvalue);

    COMMIT;
END;

请注意,如果您稍后删除记录,这些将在 idx 编号中留下间隙,这些间隔将不会被上述方法再次填充。另一方面,如果删除具有最高 idx 值的记录,则下一个插入的记录将重新使用该 idx 值。