SQL计数和分组

时间:2012-06-07 17:06:14

标签: mysql sql

好的,我正在使用嵌套的SQL语句:

我想查询我们的销售人员撰写的最新120份提案。我正在使用嵌套查询从系统中获取最后120个提案,然后根据状态等过滤它们......

我遇到的问题是如何获得每个推销员的提案数量?

SQL显然是错误的,但这就是我被困住的地方。

SELECT 
   CASE userId 
    WHEN '4' THEN 'AT'
    WHEN '3' THEN 'EO'
    WHEN '11' THEN 'CT'
    WHEN '13' THEN 'MH'
    ELSE userId
END AS Salesman,
SUM(contractAmt) as 'Contract Total',
AVG(DATEDIFF(contractDate, proposalDate)) AS averageDays,
SUM(proposalAmt) as pTot,
Count(*) as Contracts,
Count(A.proposalAmt) as Proposals,
(SUM(contractAmt) / SUM(proposalAmt)) AS 'Hit Rate $s',
(Count(*) / Count(A.proposalAmt)) AS 'Hit Rate #s'
FROM
( /* Get the last 120 proposals not in Lead or Proposal status*/
SELECT contractAmt, proposalAmt, contractDate, status, userId, 
    CASE WHEN proposalDate = '0000-00-00'   
        THEN CAST(contractDate as Date)
        else CAST(proposalDate as Date)
    END as proposalDate
FROM project
WHERE (status != 'proposal' and status != 'lead')
/*GROUP BY id*/
ORDER BY contractDate DESC
LIMIT 0, 120) A
WHERE status = 'contract' or status = 'complete'
GROUP BY userId

“计算(A.proposalAmt)作为提案,”这给了我过滤的记录数。 (只有合同和已完成的订单)

在嵌套位中,查询不希望返回包含100个单独记录的一行计数。如果我按userId分组,我会按用户计算提案数,但现在我没有单独的记录供以后过滤。

我可以通过几种方式来解决这个问题,但所有这些方法都很糟糕。我可以做另一个查询,但这不够优雅,并且对我的输出效果不佳。

数据库是MySql。

工作流程,以防我没有正确解释:

For each user ID
Get the last 100 proposals
Count # of proposals by salesman
Total proposal $ amount by salesman
Count # of contract or complete proposals
Total $ amount of contract and complete jobs
# proposals / # contracts = Hit Rate #'s
$ proposals / $ contracts = Hit Rate $'s
AVERAGE(contract date - proposal date) = Average # days in process

输出应类似于:

   Salesman  Avg Days  ProposalTot  ContractTot  HR $'s  Prop #  Con #  HR#'s
   --------------------------------------------------------------------------------------
   EO       |   29.27 |  $30,000  |    $15,000  |  50%  |   30  |   15 | 50%

编辑:添加架构

Table project
=============
id, userId, clientId, contactId, projectName, status, description, creationDate, shipDate, estimateAmt, leadAmt, reestimateAmt, proposalAmt, contractAmt, completeAmt, type, subType, estDate, reestDate, proposalDate, contractDate, completeDate, lostDate, onHoldDate, estShip, reestShip, proposalShip, contractShip, completeShip, casperLink, statusChangeTS
-------------
id               int(11) PK
userId           int(11)
clientId         int(11)
contactId        int(11)
projectName      varchar(255)
status           enum('lead','proposal','contract','complete','onHold','lost')
description      text
creationDate     date
shipDate         date
estimateAmt      int(11)
leadAmt          int(11)
reestimateAmt    int(11)
proposalAmt      int(11)
contractAmt      int(11)
completeAmt      int(11)
type             varchar(100)
subType          varchar(100)
estDate          date
reestDate        date
proposalDate     date
contractDate     date
completeDate     date
lostDate         date
onHoldDate       date
estShip          date
reestShip        date
proposalShip     date
contractShip     date
completeShip     date
casperLink       varchar(20)
statusChangeTS   date

1 个答案:

答案 0 :(得分:1)

试试这个:

SELECT 
    Count(*) as 'Total Proposals',
    SUM(CASE WHEN status = 'complete' or status = 'contract' THEN 1 ELSE 0 END) as 'Total Contracts',
    CASE userId 
        WHEN '4' THEN 'AT'
        WHEN '3' THEN 'EO'
        WHEN '11' THEN 'CT'
        WHEN '13' THEN 'MH'
        ELSE userId
    END AS Salesman,
    SUM(CASE WHEN status = 'complete' or status = 'contract' THEN contractAmt ELSE 0 END) as 'Contract Total',
    AVG(DATEDIFF(contractDate, proposalDate)) AS averageDays,
    SUM(proposalAmt) as pTot,
    (SUM(CASE WHEN status = 'complete' or status = 'contract' THEN contractAmt ELSE 0 END) / SUM(proposalAmt)) AS 'Hit Rate $s',
    (SUM(CASE WHEN status = 'complete' or status = 'contract' THEN 1 ELSE 0 END) / Count(*)) AS 'Hit Rate #s'
FROM
    (/* This inner loop only selects the top 100 records */
    select * FROM project
    WHERE (status != 'proposal' and status != 'lead') and userId = '13'
    order by contractDate DESC
    LIMIT 0, 30) A
GROUP BY userId 

我能够设计的答案是不使用WHERE子句进行过滤,而是使用CASE子句过滤具有契约的记录。您需要在需要合同总额的情况下执行此操作,并且您必须仅将具有您的状态的合同金额过滤掉。 (除非你的数据库已经处理过这个问题。)

Total Proposals | Total Contracts | Salesman | Contract Total | averageDays | pTot   | Hit Rate $s | Hit Rate #s
30                15                MH         160496           46.8          324122   0.4952        0.5