繁体   English   中英

尝试消除临时表MYSQL,并在可能的情况下将进程合并为一条语句

[英]Trying to eliminate Temporary Tables MYSQL and combine process into one statement if possible

我有一个可跟踪11位销售员销售情况的应用程序。 这是一个非常简单的过程,除了可以在销售员之间共享销售之外,这可以将销售价值减少一半。 这意味着,如果两个推销员共享一份价值100美元的工作,那么每个推销员自己只能算出50美元的销售价值。 以下是我目前用于完成此过程的代码,但看起来很笨拙,而性能对于我的品味却有些迟钝。 是否可以将其合并为一个流程并消除对临时表的需求(我还看到您不应该在生产中使用临时表的地方)

$sql = "DROP TEMPORARY TABLE IF EXISTS newbalancetbl" ;
  mysqli_query ($db, $sql ) or ( "Error " . mysqli_error () ) ;

  $newBalances = "
    CREATE TEMPORARY TABLE newbalancetbl (
      `custid` int NOT NULL,
      `assigned` int NOT NULL,
      `newBalance` double,
      PRIMARY KEY(custid)
    )
  ";

   mysqli_query($db, $newBalances) or die ("Sql error : ".mysqli_error());

  $year = date("Y");
  $start = "01/01/".$year;
  $today = date("Y-m-d");
  $first = $year."-01-01";

  $assignments = "SELECT leadid, price
                  FROM jobbooktbl 
                  WHERE convertdate >= '".$first."' AND convertdate<='".$today."' AND (status=4 OR status=6 OR status=7 OR status=8 OR status=11)";
  $assignmentsqry = mysqli_query($db,$assignments);
  while ($row = mysqli_fetch_array($assignmentsqry)) {
    $custid = $row["leadid"];
    $price = $row["price"];

    $statement = $db->prepare("INSERT INTO newbalancetbl (custid, newBalance) VALUES (?,?)");
    $statement->bind_param('id', $custid, $price);
    $statement->execute();
  }

  $sqlnewbal = "SELECT a.custid, COUNT(a.custid) AS assCnt
                  FROM assignmentstbl a, newbalancetbl b
                  WHERE a.custid=b.custid
                  GROUP BY a.custid";
  $qrynewbal = mysqli_query($db,$sqlnewbal);
  while ($row = mysqli_fetch_array($qrynewbal)) {
    $custid = $row['custid'];
    // $paid = $row["sumAmnt"];
    $assigned = $row['assCnt'];

    $usqlUpdate = $db->prepare("UPDATE newbalancetbl SET assigned=? WHERE custid=?");
    $usqlUpdate->bind_param('ii',$assigned,$custid);
    $usqlUpdate->execute();
  }

  $sqlnewbal = "SELECT *
                  FROM newbalancetbl";
  $qrynewbal = mysqli_query($db,$sqlnewbal);
  while ($row = mysqli_fetch_array($qrynewbal)) {
    $custid = $row['custid'];
    $assigned = $row['assigned'];
    $newBalance = $row['newBalance'];
    $newBal = $newBalance/$assigned;
    $newBal - number_format($newBal,2);

    $usqlUpdate = $db->prepare("UPDATE newbalancetbl SET newBalance=? WHERE custid=?");
    $usqlUpdate->bind_param('di',$newBal,$custid);
    $usqlUpdate->execute();
  }

  $salesArray = [];

  $tesql = "SELECT SUM(n.newBalance) AS newB, u.username
            FROM newbalancetbl n
            INNER JOIN assignmentstbl a 
              ON a.custid=n.custid 
            INNER JOIN usertbl u 
              ON a.userid=u.userid 
            -- WHERE u.salesman=1
            GROUP BY a.userid
            ORDER BY newB DESC";
  $teresult = mysqli_query($db,$tesql);
  while ($row = mysqli_fetch_array($teresult)) {
    $user = $row['username'];
    $sales = $row['newB'];

    array_push($salesArray, [$user,floatval($sales)]);
  }

  $arrayCount = count($salesArray);

  $total_sales = 0;
  $total_sales = array_sum( array_map(function($element){
                  return $element[1];
                }, 
             $salesArray));
  $pretotal_sales = number_format($total_sales, 2);
  $total_sales = '$' . number_format($total_sales, 2);

表格架构:

工作簿 在此处输入图片说明

作业 在此处输入图片说明

我将遍历代码以了解其功能,并在此过程中提出修改建议。

CREATE TEMPORARY TABLE newbalancetbl (
  custid     int NOT NULL,
  assigned   int NOT NULL,
  newBalance double,
  PRIMARY KEY(custid)
) ENGINE=Memory

好。 该表似乎很小,因此您可能要使用ENGINE = Memory使其更快。 另外,请考虑使用DECIMAL类型而不是DOUBLE。 这不是强制性的,但可以避免舍入错误。

无论如何。 您的第一个查询。 使用php while()循环填充表很慢,而且没有必要。 只需做:

INSERT INTO newbalancetbl (custid, newBalance)
SELECT leadid, price
FROM jobbooktbl 
WHERE convertdate BETWEEN '$first' AND '$today' 
AND status IN (4,6,7,8,11);

注意使用IN()更具可读性。 另外,在之间。 INSERT INTO SELECT将比遍历php中的查询结果快得多。 另外,我在插入的列中看不到“ assigned”和“ newBalance”,但是该表未指定任何默认值。 您应该使默认值明确。

现在,下一个查询是:

SELECT custid, COUNT(*) AS assCnt
FROM assignmentstbl a JOIN newbalancetbl b USING (custid)
GROUP BY custid

我用正确的语法更改了丑陋的旧JOIN语法(大约从1999年开始)。 另外,COUNT(col)对“ col”不为空的行进行计数。 因此,COUNT(a.custid)表示“ a.custid”实际上可以为null。 既然不能,那么这种语法只会让人感到困惑。 我用count(*)代替它。

然后,您查看PHP中的结果,然后执行“ UPDATE newbalancetbl SET SET == $ assCnt WustE custid =?”。

您应该决定使用名称“ assCnt”还是“ assigned”。 我比较喜欢第一个,因为这很重要,所以名称中的“ cnt”使其不那么混乱。 现在,此循环是不必要的,我们可以将单个UPDATE与JOIN一起使用,或者更好的是,从一开始就将值构建到Rable。 因此,第一个查询变为:

INSERT INTO newbalancetbl (custid, newBalance, assigned)
SELECT j.leadid, j.price, 
    (SELECT count(*) FROM assignmentstbl a WHERE a.custid=j.leadid) AS assigned
FROM jobbooktbl j
WHERE j.convertdate BETWEEN '$first' AND '$today' 
AND j.status IN (4,6,7,8,11);

我使用了子选择。 随意使用JOIN代替。

下一个查询。 我将忽略“ $ newBal-number_format($ newBal,2);” 由于您使用“-”而不是“ =“ ...,所以没有任何作用。这可以通过使用NUMERIC格式解决,或者仅使用以下方法即可:

UPDATE newbalancetbl 
SET newBalance=ROUND(newBalance/assigned, 2)

消除了另一个php循环。 但是我们可以消除更新,也可以消除临时表。

SELECT 
    j.leadid AS custid, 
    ROUND( j.price / (SELECT count(*) FROM assignmentstbl a WHERE a.custid=j.leadid), 2) AS newBalance
FROM jobbooktbl j
WHERE j.convertdate BETWEEN '$first' AND '$today' 
AND j.status IN (4,6,7,8,11);

这应该得到与临时表包含的结果完全相同的结果,减去“ assigned”列,该列在其余代码中都未使用,因此我们可以将其删除。 现在,让我们将其插入下一个查询中...

SELECT ROUND(SUM(n.newBalance), 2) AS newB, u.username
FROM (
    SELECT 
        j.leadid AS custid, 
        j.price / (SELECT count(*) FROM assignmentstbl a WHERE a.custid=j.leadid) AS newBalance
    FROM jobbooktbl j
    WHERE j.convertdate BETWEEN '$first' AND '$today' 
    AND j.status IN (4,6,7,8,11)
    ) n
    JOIN assignmentstbl a USING (custid)
    JOIN usertbl u USING (userid)
    -- WHERE u.salesman=1
    GROUP BY a.userid
    ORDER BY newB DESC

这应该做您想要的。 我在外部查询中移动了ROUND。

假设始终有某人分配给该工作 ,而该问题中隐含着许多其他人,则单个查询可能是:

SELECT SUM(n.newBalance) AS newB, u.username, u.userid
FROM 
    (SELECT 
        j.leadid as custid,
        (j.price / COUNT(*)) as newBalance
    FROM jobbooktbl j
    INNER JOIN assignmentstbl a 
      ON a.custid = j.leadid
    WHERE j.convertdate >= ? 
      AND j.convertdate <= ? 
    GROUP BY 1
    ) n
INNER JOIN assignmentstbl a 
  ON a.custid=n.custid 
INNER JOIN usertbl u 
  ON a.userid=u.userid 
GROUP BY u.userid
ORDER BY newB DESC;

n子查询计算平均价格

如果他们是该工作上的唯一推销员,并且该工作是200美元,那么如果他们与另一个推销员分担工作,则他们将被记入200美元(200/1 = 200),这意味着分配了两个推销员,那么他们将只被记入贷方$ 100(200/2 = 100)

假设有4个推销员分配给同一份工作,则每个推销员可获得50美元。

只是一点刺

SELECT name,SUM(
     SELECT  (
         SELECT price/
         (SELECT COUNT(1) FROM jobs WHERE job.ID = Assignments.jobId) 
               FROM jobs WHERE 
                   (SELECT COUNT(1) FROM assignment WHERE salesman.ID = assignment.salesmanId) > 0)
      )
    ) AS commission 
    FROM salesman.

正确,因此选择所有推销员,从他所参与的所有工作中获取价格。 用这个价格除以工作人数。 该表可能已更改名称,但总的来说,我认为这就是您要使用的名称。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM