如何在MySQL中使用准备好的语句创建动态列?

如何在MySQL中使用准备好的语句创建动态列?,mysql,sql,pivot,prepared-statement,dynamic-pivot,Mysql,Sql,Pivot,Prepared Statement,Dynamic Pivot,我有4张相互关联的桌子 CREATE TABLE `location` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; INSERT INTO `

我有4张相互关联的桌子

CREATE TABLE `location` (
  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO `location` (`id`, `name`) VALUES
(1, 'Dallas'),
(2, 'Boston'),
(3, 'Houston');

CREATE TABLE `item` (
 `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
 `brand` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO `item` (`id`, `brand`) VALUES
(1, 'Nissan Almera M/T 2009-2015'),
(2, 'Toyota Corolla A/T 2005-2012'),
(3, 'Nissan Terra A/T 2010-2017'),
(4, 'Suzuki Esteem M/T 1980-1990'),
(5, 'Toyota Fortuner A/T 2014-2020');

CREATE TABLE `item_in` (
  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `location_id` bigint(20) UNSIGNED NOT NULL,
  `item_id` bigint(20) UNSIGNED NOT NULL,
  `quantity` int(11) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO `item_in` (`id`, `location_id`, `item_id`, `quantity`) VALUES
(1, 1, 1, 1000),
(2, 1, 2, 500),
(3, 2, 2, 200),
(4, 2, 2, 300),
(5, 3, 3, 300),
(6, 1, 3, 800),
(7, 3, 5, 300),
(8, 3, 4, 400);

CREATE TABLE `item_out` (
  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `location_id` bigint(20) UNSIGNED NOT NULL,
  `item_id` bigint(20) UNSIGNED NOT NULL,
  `quantity` int(11) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO `item_out` (`id`, `location_id`, `item_id`, `quantity`) VALUES
(1, 1, 2, 20),
(2, 1, 1, 25),
(3, 2, 2, 25),
(4, 3, 3, 25),
(5, 3, 5, 10),
(6, 3, 4, 15),
(7, 1, 1, 200),
(8, 2, 2, 50);
使用动态SQL,我能够根据每个项目的位置和项目(项目数量减去项目数量)获得每个项目的单个剩余数量,并将位置名称作为列。(见下面的代码):

结果

Item                           | Dallas | Boston | Houston
Nissan Almera M/T 2009-2015          775        0         0                           
Toyota Corolla A/T 2005-2012         480      425         0
Nissan Terra A/T 2010-2017           800        0       275
Suzuki Esteem M/T 1980-1990            0        0       385
Toyota Fortuner A/T 2014-2020          0        0       290
我的问题是,由于用户可以随时添加新位置,我如何更改代码,以便动态显示位置名称列,而不是在查询中手动硬编码它们?如果有人能看一下我的代码,我会非常感谢你的帮助。我遇到的唯一问题是如何不硬编码这些行并动态执行它们:

IFNULL(item_in.Dallas, 0) - IFNULL(item_out.Dallas, 0) AS Dallas, IFNULL(item_in.Boston, 0) - IFNULL(item_out.Boston, 0) AS Boston, IFNULL(item_in.Houston, 0) - IFNULL(item_out.Houston, 0) AS Houston

例如,考虑下面的内容,使用PHP和MySQL语言API。(我使用了过程代码,但dbo会更有效)

或者您可以在
$new_数组[$v['city'][$v['item']]=$v['total']中交换城市和项目,以获取:

Array
(
    [Toyota Corolla A/T 2005-2012] => Array
        (
            [Boston] => 425
            [Dallas] => 480
        )

    [Nissan Almera M/T 2009-2015] => Array
        (
            [Dallas] => 775
        )

    [Nissan Terra A/T 2010-2017] => Array
        (
            [Dallas] => 800
            [Houston] => 275
        )

    [Suzuki Esteem M/T 1980-1990] => Array
        (
            [Houston] => 385
        )

    [Toyota Fortuner A/T 2014-2020] => Array
        (
            [Houston] => 290
        )

)

考虑在应用程序代码中处理数据显示的问题不要跟随…我认为MySQL是用来存储和检索关系数据的。如何将数据呈现给最终用户是应用程序代码的工作(例如PHP,我之所以提到它,是因为它是我唯一知道如何编码的应用程序代码)@AndyWong。如果您想要可变的列数或从数据中分配列值,则需要动态SQL。否则,将数据分为三列,
位置
品牌
数量
。@草莓我修改了我的帖子,使其更具可读性和简洁性。现在还增加了一个MRE。如果你能看一看,我将不胜感激。谢谢
<?php

/*
DROP TABLE IF EXISTS location;

CREATE TABLE `location` (
  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (id)
);

INSERT INTO `location` (`id`, `name`) VALUES
(1, 'Dallas'),
(2, 'Boston'),
(3, 'Houston');

DROP TABLE IF EXISTS item;
CREATE TABLE `item` (
 `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
 `brand` varchar(255) DEFAULT NULL,
  PRIMARY KEY (id)
);

INSERT INTO `item` (`id`, `brand`) VALUES
(1, 'Nissan Almera M/T 2009-2015'),
(2, 'Toyota Corolla A/T 2005-2012'),
(3, 'Nissan Terra A/T 2010-2017'),
(4, 'Suzuki Esteem M/T 1980-1990'),
(5, 'Toyota Fortuner A/T 2014-2020');

DROP TABLE IF EXISTS item_in;
CREATE TABLE `item_in` (
  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `location_id` bigint(20) UNSIGNED NOT NULL,
  `item_id` bigint(20) UNSIGNED NOT NULL,
  `quantity` int(11) DEFAULT NULL,
  PRIMARY KEY (id)
);

INSERT INTO `item_in` (`id`, `location_id`, `item_id`, `quantity`) VALUES
(1, 1, 1, 1000),
(2, 1, 2, 500),
(3, 2, 2, 200),
(4, 2, 2, 300),
(5, 3, 3, 300),
(6, 1, 3, 800),
(7, 3, 5, 300),
(8, 3, 4, 400);

DROP TABLE IF EXISTS item_out;
CREATE TABLE `item_out` (
  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `location_id` bigint(20) UNSIGNED NOT NULL,
  `item_id` bigint(20) UNSIGNED NOT NULL,
  `quantity` int(11) DEFAULT NULL,
  PRIMARY KEY (id)
);

INSERT INTO `item_out` (`id`, `location_id`, `item_id`, `quantity`) VALUES
(1, 1, 2, 20),
(2, 1, 1, 25),
(3, 2, 2, 25),
(4, 3, 3, 25),
(5, 3, 5, 10),
(6, 3, 4, 15),
(7, 1, 1, 200),
(8, 2, 2, 50);

*/

require('path/to/connect.ion');

$query = "
SELECT l.name city
     , i.brand item
     , SUM(x.quantity) total
  FROM
     ( SELECT location_id,item_id,'in' type, quantity FROM item_in
        UNION ALL
       SELECT location_id,item_id,'out',quantity*-1 FROM item_out
     ) x
  JOIN location l
    ON l.id = x.location_id
  JOIN item i
    ON i.id = x.item_id
 GROUP
    BY item
     , city
 ORDER
    BY city
     , item
";

$result = mysqli_query($db,$query);

$array = array();

while($row = mysqli_fetch_assoc($result)){
$array[] = $row;
}

foreach($array as $v){
$new_array[$v['city']][$v['item']] = $v['total'];
}


print_r($new_array);
?>
Array
(
    [Boston] => Array
        (
            [Toyota Corolla A/T 2005-2012] => 425
        )

    [Dallas] => Array
        (
            [Nissan Almera M/T 2009-2015] => 775
            [Nissan Terra A/T 2010-2017] => 800
            [Toyota Corolla A/T 2005-2012] => 480
        )

    [Houston] => Array
        (
            [Nissan Terra A/T 2010-2017] => 275
            [Suzuki Esteem M/T 1980-1990] => 385
            [Toyota Fortuner A/T 2014-2020] => 290
        )

)
Array
(
    [Toyota Corolla A/T 2005-2012] => Array
        (
            [Boston] => 425
            [Dallas] => 480
        )

    [Nissan Almera M/T 2009-2015] => Array
        (
            [Dallas] => 775
        )

    [Nissan Terra A/T 2010-2017] => Array
        (
            [Dallas] => 800
            [Houston] => 275
        )

    [Suzuki Esteem M/T 1980-1990] => Array
        (
            [Houston] => 385
        )

    [Toyota Fortuner A/T 2014-2020] => Array
        (
            [Houston] => 290
        )

)