【问题标题】:How to transform a normalised data set using PHP?如何使用 PHP 转换标准化数据集?
【发布时间】:2015-11-30 16:58:04
【问题描述】:

这是我的桌子:

用户表

id   |   name  
1    |   john  
2    |   lucy  

user_accounts 表

id   |   user_id    |   account_name
1          2             lucy_lu
2          1             johndoe

account_parameters 表

id   |  account_id  |  parameter_id   |  value
1           1              10             4000
2           1              11             1450
3           2              10             5000
4           2              11             1150

参数表

id   |   parameter_value  |  parameter_name
10          height               Height
11          max_score            Max Score

我想得到结果:

user_id | user_name | account_name |  Height  |  Max Score
1          john        johndoe        5000       1150
2          lucy        lucy_lu        4000       1450

我搜索了“mysql generate columns with data”之类的,找到了很多针对 1 或 2 个表的解决方案,但我不知道如何在这里实现这些。我知道如何选择带有连接的静态字段,但我不知道如何在此示例中选择“高度”和“最高分数”。

【问题讨论】:

  • GROUP BY 怎么样?
  • 我认为 user_id 1 的高度也应该是 4000 和其他数据
  • @AnkitBajpai - account_id = 1 映射到 user_id = 2 映射到 name = lucy => Lucy 的 user_id 为 2,高度为 4000。
  • @Alex,是的,在这种情况下是 PHP (laravel)。 .@MatBailie 我以这种方式考虑过,但仍在考虑特定的 PHP 方式来做到这一点......
  • @wast - 然后将其标记为 PHP 并询问如何使用 PHP 转换标准化数据集?

标签: php mysql pivot normalization


【解决方案1】:

由于我做了类似的事情,所以这里是开始的:

$parameters = array(
       array("id" => 10, "parameter_value" => "height", "parameter_name" => "Height"),
       array("id" => 11, "parameter_value" => "max_score", "parameter_name" => "Max Score")
); //fetch all parameters from your parameters table

//specify the table where the values are stored
$tableName = 'account_parameters';
//specify the column name in this table where the identifier for your data lies
$dataIdColumnName = 'account_id';

//set the first column up, which holds your datakey
$selectPivotFields = array("`".$tableName."`.`".$dataIdColumnName."`");

//loop over all parameters  
if(is_array($parameters))
    for($i=0;$i<count($parameters);$i++)
    {
        //build a part of your pivot query
        $selectPivotFields[] = sprintf("MAX(IF(`%1$s`.`parameter_id` = '%2$d', `%1$s`.`value`, NULL)) AS `%3$s`", $tableName, $parameters[$i]['id'], $parameters[$i]['parameter_value']);
    }

    //build the actual query for readability i simplified it a little bit
    $sql = sprintf("
              SELECT
                %1$s
               FROM
                `%2$s`
               WHERE
                `%2$s`.`%3$s` = '%4$d'
               GROUP BY
                `%2$s`.`%3$s`
              ", implode(", ", $selectPivotFields), $tableName, $dataIdColumnName, $dataId);

     //and execute your query with the prefered class
     $result = execute($sql);

基本上和MatBailie的回答背景一样

【讨论】:

    【解决方案2】:

    如果您必须使用 SQL 执行此操作,那么使用编写 SQL 的 PHP 似乎是最不紧密耦合的方法。

    首先,查询您的参数表并存储在一个数组中。

    然后将您的查询字符串分为三部分,中间部分是动态创建的。

    SELECT
        user_accounts.user_id          AS user_id,
        user.name                      AS user_name,
        user_accounts.account_name     AS account_name,
    


    对数组中的每条记录重复此操作(来自parameters

        SUM(
            CASE WHEN account_parameters.parameter_id = @param_id
                 THEN account_parameters.value
            END
        )   AS @param_name,
    

    使用 PHP 替换 @param_id 和 @param_name 值。

    (注意逗号,不要在最后一行 SQL 中使用逗号。)


    FROM
        account_parameters
    INNER JOIN
        user_accounts
            ON  user_accounts.id = account_parameters.account_id
    INNER JOIN
        user
            ON  user.id = user_accounts.user_id
    GROUP BY
        user_accounts.user_id,
        user.name,
        user_accounts.account_name
    

    注意:在 MySQL 中你只需要GROUP BY user_accounts.user_id,但我一般不建议ab使用该功能。


    执行动态构建的查询应该会为您调整结果。

    您可能需要一些上下文敏感性来确定您希望哪些参数包含在您的最终结果中,哪些不希望包含在您的最终结果中(使用这种结构,您似乎并不总是需要所有参数)

    【讨论】:

    • 这是有效的。但是,我使用 MAX 而不是 SUM。因为使用 SUM 我无法获取字符串值。谢谢。
    猜你喜欢
    • 2019-10-22
    • 1970-01-01
    • 1970-01-01
    • 2015-12-11
    • 2017-06-03
    • 1970-01-01
    • 2017-11-10
    • 2022-01-11
    • 1970-01-01
    相关资源
    最近更新 更多