【问题标题】:Dynamic SQL Inserts for JSON data [PHP]JSON 数据的动态 SQL 插入 [PHP]
【发布时间】:2021-08-06 21:44:41
【问题描述】:

几乎每天我的任务是通过 PHP 将 JSON 数据插入到关系数据库中,就像 JSON 数据一样,有些记录具有某些列,而另一些则没有,这在插入表时往往会成为问题。

如果我要插入数千名学生,一条记录可能看起来像

{"name": "Billy Jackson", "Height": 172, "DOB" : "2002-08-21"}

但是不确定是否在任何记录中设置了高度和/或 DOB,我目前所做的是类似于

<?php
  foreach($records as $json){
      $name = addslashes($json['name']);
      if(isset($json['Height']){
          $height = $json['Height'];
      }
      else{
          $height = "NULL"
      }
      if(isset($json['DOB']){
          $dob = $json['DOB'];
      }
      else{
          $dob = "NULL"
      }
 }
 $db->query("INSERT INTO table (name, height, dob) VALUES ('$name', $height, '$dob')");

您可能会看到这并不优雅,也不适用于多种类型,DOB 等字段不接受 NULL,枚举也不接受。

是否有更优雅的内置解决方案,仅尝试插入到 JSON 中存在值的列中。

这是准备好的语句处理的吗?

编辑

假设上面的示例记录没有设置 DOB,插入语句看起来像

"INSERT INTO table (name, height, dob) VALUES ('Billy Jackson', 172, 'NULL')"

如果将 $dob 设置为 null ($dob = null) 则失败,如果未设置,则插入语句如下所示

"INSERT INTO table (name, height, dob) VALUES ('Billy Jackson', 172, '')"

失败了

为什么还要包含 dob 列?因为有些记录确实有 dob,我希望它们包含在插入中

【问题讨论】:

  • DOB 字段可以接受空值,检查这个stackoverflow.com/questions/1691117/…
  • 你为什么不使用这样的表:ID | DATA:ID 是索引(此处无关紧要)| DATA:JSON 编码字段,您可以在其中放置您想要的所有内容,当您阅读此字段时,您只需将 [KEY] 更改为表 Header | [VALUE] 作为它的价值
  • “像 DOB 这样的字段不接受 NULL” 这并不是您的代码或数据的问题,而是您的数据库架构的问题。您必须使该列可以为空或丢弃缺少该字段的行。
  • @BilalAhmad 的问题是如何将变量设置为 null ,如图所示,如果我说 $dob = null 插入看起来像 Values ('Billy Jackson', 172, '')确实会引发错误
  • @AlexandroGiles 这就是我最初的做法,但不仅仅是存储数据,而是尽可能轻松地对其进行查询,我想通过一个查询轻松找到最高的学生,以及其他不太可能将所有 json 存储在一列中的示例

标签: php sql


【解决方案1】:

空字符串''null 不同。字符串"null" 也不是。由于您的查询明确引用了$dob 变量的内容,因此您引用了字符串null,使其变为"null",这绝对不为空。 :)

为避免混淆引号(和 SQL 注入),您需要使用准备好的语句,如下所示:

$db->prepare('INSERT INTO table (name, height, dob) VALUES (?, ?, ?)');

然后当你绑定值时,PHP 会自动处理哪些字段需要引号,哪些不需要。

另请注意,您可以使用以下快捷方式:

if (isset($json['Height']){
    $height = $json['Height'];
} else {
    $height = "NULL"
}

就这样吧:

$height = $json['Height'] ?? null;

这会消除你的一堆代码并使你的绑定变成这样:

$stmt->bind_param(
    'sis',
    $json['name'],
    $json['Height'] ?? null,
    $json['dob'] ?? null
);

【讨论】:

  • 再次感谢,缩短我的代码的小窍门也能救命!
【解决方案2】:

您应该从解决表格设计中的问题开始。

所有必须包含数据的列都应设置为NOT NULL,并在适当的情况下设置默认值。例如,为User Name 设置默认值可能不合适,因此请不要设置。

所有可能包含数据的列都应设置为接受NULL,并根据需要设置默认值。如果没有数据,那么正确的值通常应该是NULL,并且应该设置为默认值。

请注意,如果配置正确,DATEENUM 列都可以接受 NULL

一旦您的列定义正确,您就可以根据您在 JSON 文件中找到的实际值生成一个 INSERT 查询。您在表定义中设置的数据完整性规则将确保为创建时缺少值的任何行输入适当的值,或者如果缺少“必须拥有”数据,则不会创建该行。

这会导致一些类似这样的代码,基于 PDO 准备语句:

$json = '{"name": "Billy Jackson", "Height": 172, "DOB" : "2002-08-21"}';

$columnList = [];
$valueList = [];

$j = json_decode($json);
foreach($j as $key=>$value) {
    $columnList[] = $key;
    // interim processing, like date conversion here:
    // e.g if $key == 'DOB' then $value = reformatDate($value);
    $valueList[] = $value;

}
// Now create the INSERT statement
// The column list is created from the keys in the JSON record
// An array of values is assembled from the values in the JSON record
// This is used to create an INSERT query that matches the data you actually have

$query = "INSERT someTable (".join(',',$columnList).") values (".trim(str_repeat('?,',count($valueList)),',').")";
// echo for demo purposes
echo $query; // INSERT someTable (name,Height,DOB) values (?,?,?)

// Now prepare the query
$stmt = $db->prepare($query);

// Execute the query using the array of values assembled above.
$stmt->execute($valueList);

注意:您需要扩展它以处理从 JSON 键到列名的映射、日期字段中的格式更改等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-12
    • 1970-01-01
    • 2013-11-01
    相关资源
    最近更新 更多