在PHP/SQL中,查找给定多个数组中的一个项所在的数组,并且该项只存在于一个数组中

在PHP/SQL中,查找给定多个数组中的一个项所在的数组,并且该项只存在于一个数组中,php,mysql,sql,arrays,Php,Mysql,Sql,Arrays,我有一个电子商务网站,我已经建立了一个国家被分成不同的运输成本区 我有8个区域,这些都是国家代码数组,数组中不能有重复项,或者项目不能存在于多个数组中 然后我想计算一个给定国家的运输成本。所以我基本上想知道这个国家在哪个区域 我现在要做的是,通过项目供应商查询我的配送区域,以获取所有阵列,然后对每个阵列执行if(in_array()),如下所示: $params = [$supplier_id]; $sql = "SELECT * FROM shipping_zones WHERE suppli

我有一个电子商务网站,我已经建立了一个国家被分成不同的运输成本区

我有8个区域,这些都是国家代码数组,数组中不能有重复项,或者项目不能存在于多个数组中

然后我想计算一个给定国家的运输成本。所以我基本上想知道这个国家在哪个区域

我现在要做的是,通过项目供应商查询我的配送区域,以获取所有阵列,然后对每个阵列执行
if(in_array())
,如下所示:

$params = [$supplier_id];
$sql = "SELECT * FROM shipping_zones WHERE supplier_id=?";
$stmt = DB::run($sql,$params);
while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
    $z1 = unserialize($row['zone1']);
    $z2 = unserialize($row['zone2']);
    $z3 = unserialize($row['zone3']);
    $z4 = unserialize($row['zone4']);
    $z5 = unserialize($row['zone5']);
    $z6 = unserialize($row['zone6']);
    $z7 = unserialize($row['zone7']);
    $z8 = unserialize($row['zone8']);
}

if(in_array($country_code,$z1)){
    $shipping_zone = 'z1';
}else if(in_array($country_code,$z2)){
    $shipping_zone = 'z2';
}else if(in_array($country_code,$z3)){
    $shipping_zone = 'z3';
}else if(in_array($country_code,$z4)){
    $shipping_zone = 'z4';
}else if(in_array($country_code,$z5)){
    $shipping_zone = 'z5';
}else if(in_array($country_code,$z6)){
    $shipping_zone = 'z6';
}else if(in_array($country_code,$z7)){
    $shipping_zone = 'z7';
}else if(in_array($country_code,$z8)){
    $shipping_zone = 'z8';
}

必须有更好的方法来实现这一点,我认为在初始SQL查询中实现这一点可能更容易,但实际数组在DB中序列化。

从您的问题来看,装运区域的模式类似于以下内容:

CREATE TABLE shipping_zones (
  supplier_id INT,
  zone1 TEXT, -- Each of these contains a big serialized PHP array
  zone2 TEXT,
  zone3 TEXT,
  zone4 TEXT,
  zone5 TEXT,
  zone6 TEXT,
  zone7 TEXT,
  zone8 TEXT
);
CREATE TABLE shipping_zones (
  supplier_id  INT,
  zone         ENUM('z1','z2','z3','z4','z5','z6','z7','z8') NOT NULL,
  country_code CHAR(2) -- Not really sure what your codes actually look like...
);

CREATE UNIQUE INDEX idx_unique ON shipping_zones(supplier_id, country_code);
听起来你想在这里完成两件事:

  • 维护数据完整性(“阵列中不能有重复项,或者项目不能存在于多个阵列中”)
  • 使您的代码更简单/更易于维护(“必须有更好的方法来做到这一点…”)
  • 假设您可以完全控制应用程序和数据库,我建议您更改数据库模式,以便您的RDBMS可以为您做更多的工作。我建议使用一个更像这样的模式:

    CREATE TABLE shipping_zones (
      supplier_id INT,
      zone1 TEXT, -- Each of these contains a big serialized PHP array
      zone2 TEXT,
      zone3 TEXT,
      zone4 TEXT,
      zone5 TEXT,
      zone6 TEXT,
      zone7 TEXT,
      zone8 TEXT
    );
    
    CREATE TABLE shipping_zones (
      supplier_id  INT,
      zone         ENUM('z1','z2','z3','z4','z5','z6','z7','z8') NOT NULL,
      country_code CHAR(2) -- Not really sure what your codes actually look like...
    );
    
    CREATE UNIQUE INDEX idx_unique ON shipping_zones(supplier_id, country_code);
    
    这样,您就不会意外地将一个国家/地区放置在给定供应商的多个区域中,并且您为给定供应商获取正确代码的任务变得简单,如下查询所示:

    SELECT 
      zone 
    FROM 
      shipping_zones 
    WHERE 
      supplier_id = :supplier_id 
      AND country_code = :country_code;
    

    首先,您可以规范化
    shipping\u zone
    并创建一个表
    shipping\u zone\u supplier
    修改查询中的
    where
    子句,以查看国家代码的每一列。虽然这是一个粗糙的方法,但它应该是有效的。尽管如此,还是听从ka_lin的建议,将信息规范化。当你说“必须有更好的方法来实现这一点……但是实际的数组是在数据库中序列化的”时,你的意思是你需要一个不涉及更改数据库模式的解决方案吗?如果是这样的话,解决方案能否涉及更改序列化数据的形状?或者您正在试图找到一种干净的方法来检查不受控制的数据?像这样的模式显然违反了。如果可能的话,尝试将其重新构造为一对多关系结构,因为这将使您的代码更加简洁易懂,查询也会大大简化。即使您不能重新构造,也要学习如何使用循环来简化这样的代码。这里的重复令人震耳欲聋。为什么
    VARCHAR(5000)
    而不是
    TEXT
    ?没有特别的原因。如果你认为这能让答案读得更好的话,我会修改它。5000部分非常具体,并且对数据有多大做出了假设<默认情况下,代码>文本为65535,但如果需要,可以使用
    MEDIUMTEXT
    LONGTEXT
    。还可以尝试将值指示为占位符,如
    :供应商id
    。使用
    $supplier\u id
    会鼓励鲁莽的SQL注入。@tadman,占位符上的公平点。我已相应地更新了我的答案。