在查询中使用MySQL用户变量作为table_name

时间:2016-08-17 12:39:44

标签: php mysql sql

我的MYSQL v5.7.9数据库中有三个表:

world1:
player_id | city_id | wood_max_level | wheat_max_level | gold_max_level | meat_max_level

world2:
player_id | city_id | wood_max_level | wheat_max_level | gold_max_level | meat_max_level

升级: world | player_id | city_id | building | level

内部升级
building包含一个字符串:' wood_max_level',' wheat_max_level',' gold_max_level'或者' meat_max_level'
world还包含一个字符串:' world1'或者' world2'。

我尝试做的是从升级中选择buildinglevel

然后,我想根据world1包含的内容更新world2world,并将level设置为构建中包含的列名。


以下是

的示例

我在upgrading内有一行看起来像这样:

  world   | player_id | city_id |     building    | level
 'world1' |    190    |     1   | 'wood_max_level'|   2

执行查询后,我会让表格world1受到影响,因为它已在upgrading内设置为列worldworld1会是这样的:

player_id | city_id | wood_max_level | wheat_max_level | gold_max_level | meat_max_level
   190    |    1    |        2       |        0        |        0       |       0

我已经有了一个有效的PHP版本'这个的。基本上我做了第一个查询然后返回一个数组和foreach元素我做了另一个查询。

修改

SELECT 
  @world := world,
  @building := building,
  @level := level FROM upgrading;
UPDATE @world
  SET @building = @level;

上面我已经定义了三个用户变量(它们的值来自表upgrading。在第二个语句中,我试图更新@world中包含的世界(world1或者world2)。在上面的示例中,它看起来像这样:@ world =' world1',@ building =' wood_max_level',@ level = 2

最后一行不正确,因为@world是一个字符串。我可以让我工作吗?

3 个答案:

答案 0 :(得分:0)

啊,因为你的表结构不同,你可能需要做一个Pivot / unpivot。或者,你可以像这样使用case语句;

UPDATE world
SET 
    world.wood_max_level = case when upgrading.building = 'wood_max_level' THEN world.wood_max_level + 1 else world.wood_max_level end,
    ... similar for other levels ...
FROM upgrading
INNER JOIN world1 
    on upgrading.world = world.world_id
WHERE completion_time > 0;

在编辑你的问题后,你似乎也需要使用Dynamic Sql,因为你不知道你想要更新的表的名称,直到运行时...这是可能的,但更先进,并从您的表的架构我建议您阅读关系数据库的基础知识,并尝试重新考虑您的架构,以便在创建复杂查询之前不需要这样做。一个提示是在单个世界表中有一个WorldId列,这将消除两个具有相同模式的不同表的需要(通常是您的设计错误的标志)。在尝试构建游戏之前,我会仔细阅读数据库设计,因为在此过程中更改数据库设计要比现在更难...

答案 1 :(得分:0)

不确定这是否是您正在寻找的,我相信有一种更优雅的方式来构建它,但我认为这至少会给你一个起点示例。

我首先声明我的变量,然后检索我需要在临时表中执行更新所需的信息。我从该表中提取出我想要的各个值,以形成我可以在动态sql查询中使用的变量。我定义了我的查询,并使用sp_executesql执行,然后删除我的临时表来清理。当然,您可以将所有这些都投入到程序中。这是代码:

declare @TargetTable varchar(50);
declare @TargetColumn varchar(50);
declare @ValueToUpdate int;

select 
    World, Player_Id, Building, [Level]
into 
    #Upgrades
from 
    dbo.Upgrading
where 
    Player_Id = 2;

set @TargetTable = (
    select World 
    from #Upgrades
    );
set @TargetColumn = (
    select Building 
    from #Upgrades
    );
set @ValueToUpdate = (
    select [Level] 
    from #Upgrades
    );

declare @Query nvarchar(max);
set @Query = 'update dbo.'+@TargetTable+' set '+@TargetColumn+'='+convert(nvarchar,@ValueToUpdate)+' where Player_Id = 2';

exec sp_executesql @Query;

drop table #Upgrades;

答案 2 :(得分:0)

我找到了一个解决方案,但它并不理想。我只想执行一个查询,最后我使用了更多。它也比SQL更多PHP ...

public function checkOnBuildingQueue()
{
    // SQL query and prepare the request
    $sql = 'SELECT world, player_id, city_id, building, level FROM upgrading WHERE completion_time < :time;
            DELETE FROM upgrading WHERE completion_time < :time;';
    $query = $this->db->prepare($sql);

    // prepare statements and execute query
    $params = array(
        'time' => time() + 2
    );
    $query->execute($params);

    // return selected rows in array
    $upgrades = $query->fetchAll();
    unset($sql, $params, $query);

    // $upgrade contains all finished upgrades
    foreach($upgrades as $upgrade)
    {
        $world = $upgrade['world'];
        $player_id = $upgrade['player_id'];
        $city_id = $upgrade['city_id'];
        $building = $upgrade['building'] . '_level';
        $level = $upgrade['level'];

        $sql = 'UPDATE '.$world.' SET '.$building.' = '.$level.' WHERE player_id = '.$player_id.' AND city_id = '.$city_id.'';
        $query = $this->db->query($sql);
    }

}