【问题标题】:Loop in column name MYSQL循环列名MYSQL
【发布时间】:2017-05-10 17:43:45
【问题描述】:

我正在使用 MYSQL。我的表包含列名称为 Revenue2000,Revenue2001,Revenue2002,....,Revenue 2016,Revenue 2017

传统方式(手动选择所有列):

select Revenue2005,
    Revenue2006,
    Revenue2007,
    Revenue2008,
    Revenue2009,
    Revenue2010
from table_name

想要的方式:

我想写一个动态选择语句。应该有 2 个变量“开始”和“结束”,这样我就可以使它成为动态的。用户可以选择指定开始年份和结束年份,并可以查看所需的结果。

在上述情况下,开始年份 =2005 结束年份=2010

【问题讨论】:

  • 嗯,我认为这只是说明了糟糕的数据库设计 会以何种方式帮助您
  • 你应该规范化设计。您可以将数据存储在两列 - 收入和年份。那么这将是一个简单的 where 子句。
  • 我同意@GurwinderSingh 如果您要重写查询,您不妨尽可能更改您的表模型。有两列,一列用于收入,一列用于年度,无需使用动态 SQL 即可解决所有问题。

标签: mysql sql


【解决方案1】:

是的,这是糟糕的数据库设计,最好的答案是“根本不要这样做,只需修复您的表即可。”不幸的是,有时你被别人做的东西卡住了,无论出于什么原因都无法改变它,但你仍然需要完成一些事情(欢迎来到我的生活)。我会这样做:

从用户输入中获取年份并将其转换为整数,以防有人输入一些愚蠢/顽皮的东西。不要依赖客户端验证。准备好的语句在这里对您没有帮助,因为它们将用作列名的一部分。

$start = (int) $_POST['start'];
$end = (int) $_POST['end'];

进行快速健全性检查以确保范围合理并且应该与数据库中的内容一起使用。

if ($start > $end
    || $start < $lowest_year_in_your_db
    || $end > $highest_year_in_your_db) {

    // quit with error
}

然后,您可以生成要在查询中使用的列列表。这是rangearray_map 的一种方式,但您也可以只使用for 循环构建一个字符串。

$columns = implode(', ', array_map(function($year) {
    return "Revenue$year";
}, range($start, $end)));

$sql = "SELECT $columns FROM table_name";

从理论上讲,最糟糕的情况应该是你会得到一个不存在的列,并且你的查询会失败。

但实际上,如果您对此有任何选择,不要这样做。按照人们在 cmets 中的说明规范您的数据库,或者找到不断向数据库添加更多年份列的人并让他们这样做。

【讨论】:

  • 无法更改数据库设计。您能告诉我如何在 MYSQL 中实现这一点(因为 implode 函数在 MYSQL 中不起作用)
  • 对不起,我回答时这是一个 PHP 问题。
【解决方案2】:

正如已经指出的那样,数据库设计很糟糕。你真的应该把它正常化,这是值得的。

但是,如果目前无法做到这一点,那么下面的代码应该完全符合您的需要:

// Connect to DB
$mysqli = new mysqli("localhost", "USERNAME", "PASSWORD", "DATABASE");

// Get column names
$columns = $mysqli->query('SHOW COLUMNS FROM revenue')->fetch_all();
$columnNames = array_column($columns, 0);

// Extract years from column names
$years = array_map(function($columnName) {
    return (int) substr($columnName, -4);
}, $columnNames);

// Get max and min year
$maxYear = max($years);
$minYear = min($years);

// Input year start and end
$start = (int) $_POST['start']; // User-input
$end = (int) $_POST['end']; // User-input

// Avoid wrong inputs
if($start > $end || $start < $minYear || $end > $maxYear) {
    die('Error');
}

// Create the SQL-query
$selectColumns = [];
for ($i = $start; $i <= $end; $i++) {
    $selectColumns[] = "revenue" . $i;
}
$queryString = "SELECT " . implode(", ", $selectColumns) . " FROM TABLE";

// Run the query
// ...

【讨论】:

  • 无法更改数据库设计。您能告诉我如何在 MYSQL 中实现这一点(因为 implode 函数在 MYSQL 中不起作用)
  • 当我写下我的答案时,这个问题被标记为 php,这就是答案的目的。不知道是不是只有mysql才有可能。
猜你喜欢
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 2019-03-28
  • 2017-09-12
  • 1970-01-01
  • 1970-01-01
  • 2016-11-06
  • 2020-04-04
相关资源
最近更新 更多