【问题标题】:Use a MySQL user variable as table_name in query在查询中使用 MySQL 用户变量作为 table_name
【发布时间】:2016-08-17 12:39:43
【问题描述】:

我的 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还包含一个字符串:'世界1'或'世界2'。

我要做的是从升级中选择buildinglevel

然后我想根据 world 包含的内容更新 world1world2,并将 level 设置为 building 中包含的列名。


这是一个例子

我在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 中包含的世界(world1world2)。在上面的例子看起来像这样:@world = 'world1', @building = 'wood_max_level', @level = 2

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

【问题讨论】:

  • sql 还不够!请用实际的 DBMS(供应商和版本)标记
  • 样本数据和预期结果对您的解释很有帮助。
  • 在 oracle 中,我们使用merge。在psqltsql 中,我们使用CTE 表达式。那你的方言是什么?
  • 我已添加:WAMP 上的 MySQL v5.7.9
  • 子查询。 UPDATE your_table SET var=(SELECT var2 from another_table WHERE ....) WHERE.....

标签: php mysql sql


【解决方案1】:

啊,由于您的表结构不同,您可能需要执行 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 列,这将消除两个具有相同架构的不同表的需要(通常表明您的设计是错误的)。在尝试围绕此构建游戏之前,我会认真阅读数据库设计,因为在此过程的后期更改数据库设计将比现在更困难......

【讨论】:

  • world 不是表格而是来自upgrading 的列
  • 第 1 行仍有UPDATE world
  • 所以你的表叫world1?你肯定知道我的意思......我提供了伪代码,因为从你提供的表模式中,两个表(world_id 等)之间甚至没有链接,所以我无法测试正确的查询,直到你发布你的实际的表定义。或者,如果您有 - 这将不起作用,因为您的架构是错误的......
  • player_idcity_id 是两个链接
【解决方案2】:

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

我首先声明我的变量,然后将执行更新所需的信息检索到临时表中。我从该表中提取出我想要的单个值,以形成可以在动态 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;

【讨论】:

    【解决方案3】:

    我找到了解决方案,但并不理想。我只想执行一个查询,最终使用了更多。而且它比 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);
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2012-11-20
      • 1970-01-01
      • 1970-01-01
      • 2013-07-26
      • 2013-05-15
      • 2020-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多