参数准备语句数量错误

时间:2017-02-08 02:27:52

标签: php sql performance prepared-statement phalcon

我正在使用预准备语句来改进我正在进行的查询,但它会生成错误:

  

参数数量错误

查询如下:

$start = new DateTime('first monday of January 2016');
$end   = new DateTime('last day of December 2016');

$sql = "SELECT ".$generalLand."
                         product AS product,
                         Week AS label,
                         ROUND(SUM(harvest)/SUM(production),2) AS value
                  FROM (
                          (
                              SELECT ".$fieldLand."
                                     pr_products.product,
                                     CONCAT(YEAR(:dates),'-', LPAD(WEEK(:dates1),2,'0')) AS Week,
                                     SUM(IF(sw_sowing.type = 'SW', sw_sowing.quantity,0)) AS PlantSowing,
                                     SUM(IF(ROUND(DATEDIFF(TIMESTAMPADD(DAY,(6-WEEKDAY(:dates2)),:dates3), sw_sowing.date)/7) >= pr_products.week_production AND sw_sowing.type = 'SW',sw_sowing.quantity,0)) AS production,
                                     0 AS Harvest
                              FROM (
                                      SELECT max(sw_sowing.id) AS id
                                      FROM sw_sowing
                                      WHERE sw_sowing.status != 0
                                      AND sw_sowing.date <= TIMESTAMPADD(DAY,(6-WEEKDAY(:dates4)),:dates5)
                                      GROUP BY sw_sowing.id_production_unit_detail
                                   ) AS sw
                              INNER JOIN sw_sowing ON sw_sowing.id = sw.id
                              INNER JOIN pr_products ON pr_products.id = sw_sowing.id_product
                              INNER JOIN pr_varieties ON sw_sowing.id_variety = pr_varieties.id
                              ".$innerSowing."
                              WHERE pr_varieties.code != 1
                              AND sw_sowing.id_product = 1
                              AND sw_sowing.status = 100
                              AND sw_sowing.id_tenant = :id_tenant
                              ".$consultSowing."
                              GROUP BY pr_products.product
                              HAVING plantSowing > 0
                              ORDER BY pr_products.product
                          )
                          UNION ALL
                          (
                              SELECT  ".$fieldLand."
                                      pr_products.product,
                                      CONCAT(YEAR(:dates6),'-', LPAD(WEEK(:dates7),2,'0')) AS Week,
                                      0 AS plantSowing,
                                      0 AS Production,
                                      SUM(pf_harvest.quantity) AS Harvest
                              FROM pf_harvest
                              INNER JOIN pr_products ON pr_products.id = pf_harvest.id_product
                              INNER JOIN pr_varieties ON pr_varieties.id = pf_harvest.id_variety
                              INNER JOIN pf_performance ON pf_performance.id = pf_harvest.id_performance
                              ".$innerHarvest."
                              WHERE pf_harvest.date BETWEEN TIMESTAMPADD(DAY,(0-WEEKDAY(:dates8)),:dates9)
                              AND TIMESTAMPADD(DAY,(6-WEEKDAY(:dates10)),:dates11)
                              AND pr_varieties.code != 1
                              AND pf_harvest.id_product = 1
                              AND pf_performance.status = 100
                              ".$consultHarvest."
                              AND pf_harvest.id_tenant = :id_tenant1
                              GROUP BY pr_products.product
                              ORDER BY pr_products.product
                              )
                          ) AS sc
                  GROUP BY product, label
                  ORDER BY label";

        $statement = $this->db->prepare($sql);
        $id_tenant = $this->getIdTenant();
        foreach($datePeriod AS $dates){

          $values = [
            ':dates'      => $dates->format('Y-m-d'),
            ':dates1'     => $dates->format('Y-m-d'),
            ':dates2'     => $dates->format('Y-m-d'),
            ':dates3'     => $dates->format('Y-m-d'),
            ':dates4'     => $dates->format('Y-m-d'),
            ':dates5'     => $dates->format('Y-m-d'),
            ':dates6'     => $dates->format('Y-m-d'),
            ':dates7'     => $dates->format('Y-m-d'),
            ':dates8'     => $dates->format('Y-m-d'),
            ':dates9'     => $dates->format('Y-m-d'),
            ':dates10'    => $dates->format('Y-m-d'),
            ':dates11'    => $dates->format('Y-m-d'),
            ':id_tenant'  => $id_tenant,
            ':id_tenant1' => $id_tenant

          ];

          $result = $this->db->executePrepared($statement , $values);

        }

我理解它是因为我在查询中的绑定数量。

每个:date都是相同的日期,但我输入了不同的值,因为变量无法重复。

我也在尝试改进我的查询,因为我使用了一个循环来显示一年中每个星期一的日期以及我在查询中添加的日期。

出于这个原因,我以这种方式进行了咨询

如果有人能给我一个建议我会很感激。

问候!

2 个答案:

答案 0 :(得分:0)

在你的foreach循环中:

foreach($datePeriod AS $dates){

          $values = [
            ':dates'      => $dates->format('Y-m-d'),
            ':dates1'     => $dates->format('Y-m-d'),
            ':dates2'     => $dates->format('Y-m-d'),
            ':dates3'     => $dates->format('Y-m-d'),
            ':dates4'     => $dates->format('Y-m-d'),
            ':dates5'     => $dates->format('Y-m-d'),
            ':dates6'     => $dates->format('Y-m-d'),
            ':dates7'     => $dates->format('Y-m-d'),
            ':dates8'     => $dates->format('Y-m-d'),
            ':dates9'     => $dates->format('Y-m-d'),
            ':dates10'    => $dates->format('Y-m-d'),
            ':dates11'    => $dates->format('Y-m-d'),
            ':id_tenant'  => $id_tenant,
            ':id_tenant1' => $id_tenant

          ];

          $result = $this->db->executePrepared($statement , $values);

}

$ date的格式化为11次。你意识到这是每次正确的相同日期吗?这可能是问题吗?

也许你的意思是这样的?

foreach ($datePeriod as $dates) {
  $dateHolder[] = $dates->format('Y-m-d')
}

$i = 0;

$values = [
  ':dates'      => $dateHolder[$i++],
  ':dates1'     => $dateHolder[$i++],
  ':dates2'     => $dateHolder[$i++],
  ':dates3'     => $dateHolder[$i++],
  ':dates4'     => $dateHolder[$i++],
  ':dates5'     => $dateHolder[$i++],
  ':dates6'     => $dateHolder[$i++],
  ':dates7'     => $dateHolder[$i++],
  ':dates8'     => $dateHolder[$i++],
  ':dates9'     => $dateHolder[$i++],
  ':dates10'    => $dateHolder[$i++],
  ':dates11'    => $dateHolder[$i++],
  ':id_tenant'  => $id_tenant,
  ':id_tenant1' => $id_tenant
];

$result = $this->db->executePrepared($statement , $values);

答案 1 :(得分:0)

我知道问题是什么:

当我使用executePrepared时,我需要使用三个参数,所以在我的情况下我需要使用它:

$start = new DateTime('first monday of January 2016');
$end   = new DateTime('last day of December 2016');

$sql = "SELECT ".$generalLand."
                         product AS product,
                         Week AS label,
                         ROUND(SUM(harvest)/SUM(production),2) AS value
                  FROM (
                          (
                              SELECT ".$fieldLand."
                                     pr_products.product,
                                     CONCAT(YEAR(:dates),'-', LPAD(WEEK(:dates1),2,'0')) AS Week,
                                     SUM(IF(sw_sowing.type = 'SW', sw_sowing.quantity,0)) AS PlantSowing,
                                     SUM(IF(ROUND(DATEDIFF(TIMESTAMPADD(DAY,(6-WEEKDAY(:dates2)),:dates3), sw_sowing.date)/7) >= pr_products.week_production AND sw_sowing.type = 'SW',sw_sowing.quantity,0)) AS production,
                                     0 AS Harvest
                              FROM (
                                      SELECT max(sw_sowing.id) AS id
                                      FROM sw_sowing
                                      WHERE sw_sowing.status != 0
                                      AND sw_sowing.date <= TIMESTAMPADD(DAY,(6-WEEKDAY(:dates4)),:dates5)
                                      GROUP BY sw_sowing.id_production_unit_detail
                                   ) AS sw
                              INNER JOIN sw_sowing ON sw_sowing.id = sw.id
                              INNER JOIN pr_products ON pr_products.id = sw_sowing.id_product
                              INNER JOIN pr_varieties ON sw_sowing.id_variety = pr_varieties.id
                              ".$innerSowing."
                              WHERE pr_varieties.code != 1
                              AND sw_sowing.id_product = 1
                              AND sw_sowing.status = 100
                              AND sw_sowing.id_tenant = :id_tenant
                              ".$consultSowing."
                              GROUP BY pr_products.product
                              HAVING plantSowing > 0
                              ORDER BY pr_products.product
                          )
                          UNION ALL
                          (
                              SELECT  ".$fieldLand."
                                      pr_products.product,
                                      CONCAT(YEAR(:dates6),'-', LPAD(WEEK(:dates7),2,'0')) AS Week,
                                      0 AS plantSowing,
                                      0 AS Production,
                                      SUM(pf_harvest.quantity) AS Harvest
                              FROM pf_harvest
                              INNER JOIN pr_products ON pr_products.id = pf_harvest.id_product
                              INNER JOIN pr_varieties ON pr_varieties.id = pf_harvest.id_variety
                              INNER JOIN pf_performance ON pf_performance.id = pf_harvest.id_performance
                              ".$innerHarvest."
                              WHERE pf_harvest.date BETWEEN TIMESTAMPADD(DAY,(0-WEEKDAY(:dates8)),:dates9)
                              AND TIMESTAMPADD(DAY,(6-WEEKDAY(:dates10)),:dates11)
                              AND pr_varieties.code != 1
                              AND pf_harvest.id_product = 1
                              AND pf_performance.status = 100
                              ".$consultHarvest."
                              AND pf_harvest.id_tenant = :id_tenant1
                              GROUP BY pr_products.product
                              ORDER BY pr_products.product
                              )
                          ) AS sc
                  GROUP BY product, label
                  ORDER BY label";

        $statement = $this->db->prepare($sql);
        $id_tenant = $this->getIdTenant();
        foreach($datePeriod AS $dates){

          $values = [
            ':dates'      => $dates->format('Y-m-d'),
            ':dates1'     => $dates->format('Y-m-d'),
            ':dates2'     => $dates->format('Y-m-d'),
            ':dates3'     => $dates->format('Y-m-d'),
            ':dates4'     => $dates->format('Y-m-d'),
            ':dates5'     => $dates->format('Y-m-d'),
            ':dates6'     => $dates->format('Y-m-d'),
            ':dates7'     => $dates->format('Y-m-d'),
            ':dates8'     => $dates->format('Y-m-d'),
            ':dates9'     => $dates->format('Y-m-d'),
            ':dates10'    => $dates->format('Y-m-d'),
            ':dates11'    => $dates->format('Y-m-d'),
            ':id_tenant'  => $id_tenant,
            ':id_tenant1' => $id_tenant

          ];

          $types = [
            ':dates'      => Column::BIND_PARAM_STR,
            ':dates1'     => Column::BIND_PARAM_STR,
            ':dates2'     => Column::BIND_PARAM_STR,
            ':dates3'     => Column::BIND_PARAM_STR,
            ':dates4'     => Column::BIND_PARAM_STR,
            ':dates5'     => Column::BIND_PARAM_STR,
            ':dates6'     => Column::BIND_PARAM_STR,
            ':dates7'     => Column::BIND_PARAM_STR,
            ':dates8'     => Column::BIND_PARAM_STR,
            ':dates9'     => Column::BIND_PARAM_STR,
            ':dates10'    => Column::BIND_PARAM_STR,
            ':dates11'    => Column::BIND_PARAM_STR,
            ':id_tenant'  => Column::BIND_PARAM_INT,
            ':id_tenant1' => Column::BIND_PARAM_INT

          ];

          $result = $this->db->executePrepared($statement , $values, $types);

        }

我加上$ types [],因此它无效!

我希望它可以帮助另一个人!