MYSQL通过Salesman和Weeks

时间:2017-08-01 13:16:19

标签: mysql left-join

我目前有一个跟踪销售团队销售情况的数据库。我有一个查询,将拉动每个推销员及其相关的总数,但我希望按周分解,然后如果可能的话,在一周内汇总显示。

我目前使用的查询是:

SELECT ROUND(SUM(n.newBalance), 2) AS newB, u.username
  FROM (
    SELECT 
        j.leadid AS custid, 
        WEEK(j.convertdate) AS weeks,
        j.price / (SELECT count(*) FROM assignmentstbl a WHERE a.custid=j.leadid) AS newBalance
    FROM jobbooktbl j
    WHERE j.convertdate BETWEEN '2017-01-02' AND '2017-07-31' 
    AND j.status IN (4,6,7,8,11)
    ) n
    JOIN assignmentstbl a USING (custid)
    JOIN usertbl u USING (userid)
    GROUP BY a.userid

返回以下内容(由Salesman分组):

+-----------+-------------+
| salesman  | Sales Total |
+-----------+-------------+
| salesman1 |    1850     |
| salesman2 |    1170     |
+-----------+-------------+

我希望完成的是按周分解并返回以下内容(按星期分组然后由销售员分组):

+-----------+--------+-------------+
| salesman  | weekNo | sales total |
+-----------+--------+-------------+
| salesman1 |   1    |      0      |
| salesman2 |   1    |      0      |
| salesman1 |   2    |     100     |
| salesman2 |   2    |     100     |
| salesman1 |   3    |    1300     |
| salesman2 |   3    |      0      |
| salesman1 |   4    |     450     |
| salesman2 |   4    |    1070     |
| salesman1 |   5    |      0      |
| salesman2 |   5    |      0      |
+-----------+--------+-------------+

如果可能的话,聚合也是这样的(由销售人员按周运行总计/聚合分组):

+-----------+--------+-------------+
| salesman  | weekNo | sales total |
+-----------+--------+-------------+
| salesman1 |   1    |      0      |
| salesman2 |   1    |      0      |
| salesman1 |   2    |     100     |
| salesman2 |   2    |     100     |
| salesman1 |   3    |    1400     |
| salesman2 |   3    |     100     |
| salesman1 |   4    |    1850     |
| salesman2 |   4    |    1170     |
| salesman1 |   5    |    1850     |
| salesman2 |   5    |    1170     |
+-----------+--------+-------------+

到目前为止,这是架构:

CREATE TABLE weekstbl
  (`weekNo` int, `weekStart` date)
;

INSERT INTO weekstbl
  (`weekNo`, `weekStart`)
VALUES
  (1, '2017-01-02'),
  (2, '2017-01-09'),
  (3, '2017-01-16'),
  (4, '2017-01-23'),
  (5, '2017-01-30')
;

CREATE TABLE jobbooktbl
  (`leadid` int, `convertdate` date, `price` int, `status` int)
;

INSERT INTO jobbooktbl
  (`leadid`, `convertdate`, `price`, `status`)
VALUES
  (1, '2017-01-16', 500, 4),
  (2, '2017-01-24', 620, 6),
  (3, '2017-01-17', 800, 7),
  (4, '2017-01-26', 900, 11),
  (5, '2017-01-10', 200, 4)
;


CREATE TABLE assignmentstbl
    (`custid` int, `userid` int)
;

INSERT INTO assignmentstbl
    (`custid`, `userid`)
VALUES
    (1, 1),
    (2, 2),
    (3, 1),
    (4, 2),
    (4, 1),
    (5, 1),
    (5, 2)
;

CREATE TABLE usertbl
    (`userid` int, `username` varchar(25))
;

INSERT INTO usertbl
    (`userid`,`username`)    
VALUES
    (1,'salesman1'),
    (2,'salesman2')
;

以下是SQLFIDDLE,其中包含上述所有信息。

我试过LEFT JOIN这两张桌子,但无济于事。我真的是SQL的初学者,所以这有点离开我的轮子。我也是因为我不知道如何在没有任何销售员价值的几个星期内返回0来创建周末,这可能没有必要。

试验:

试验1

SELECT ROUND(SUM(n.newBalance), 2) AS newB, weeks, u.username
  FROM (
    SELECT 
        j.leadid AS custid, 
        w.weekno AS weeks,
        j.price / (SELECT count(*) FROM assignmentstbl a WHERE a.custid=j.leadid) AS newBalance
    FROM jobbooktbl j
    LEFT JOIN weekstbl w on w.weekNo=WEEK(j.convertdate) 
    AND j.convertdate BETWEEN '2017-01-02' AND '2017-07-31'
    AND j.status IN (4,6,7,8,11)
    ) n
    JOIN assignmentstbl a USING (custid)
    JOIN usertbl u USING (userid)
    GROUP BY weeks, a.userid

这返回了以下结果集,其中不包括第3周(对于salesman2)或5的0:

+-----------+--------+-------------+
| salesman  | weekNo | sales total |
+-----------+--------+-------------+
| salesman1 |   2    |     100     |
| salesman2 |   2    |     100     |
| salesman1 |   3    |    1300     |
| salesman1 |   4    |     450     |
| salesman2 |   4    |    1070     |
+-----------+--------+-------------+

试验2

SELECT ROUND(SUM(n.newBalance), 2) AS newB, weeks, u.username
  FROM (
    SELECT 
        j.leadid AS custid, 
        w.weekno AS weeks,
        j.price / (SELECT count(*) FROM assignmentstbl a WHERE a.custid=j.leadid) AS newBalance
    FROM jobbooktbl j
    join weekstbl w on j.convertdate between weekstart and date(weekstart + interval 6 day )
    WHERE j.convertdate BETWEEN '2017-01-02' AND '2017-07-31' 
    AND j.status IN (4,6,7,8,11)
    ) n
    JOIN assignmentstbl a USING (custid)
    JOIN usertbl u USING (userid)
    GROUP BY weeks, a.userid

这返回了以下结果集(第1,3周(针对salesman2)或5)不包括0:

 +-----------+--------+-------------+
 | salesman  | weekNo | sales total |
 +-----------+--------+-------------+
 | salesman1 |   2    |     100     |
 | salesman2 |   2    |     100     |
 | salesman1 |   3    |    1300     |
 | salesman1 |   4    |     450     |
 | salesman2 |   4    |    1070     |
 +-----------+--------+-------------+

试验3:

SELECT * FROM (
 SELECT ROUND(SUM(n.newBalance), 2) AS newB, u.username,weeks
      FROM (
        SELECT 
            j.leadid AS custid, 
            WEEK(j.convertdate) AS weeks,
            j.price / (SELECT count(*) FROM assignmentstbl a WHERE a.custid=j.leadid) AS newBalance
        FROM jobbooktbl j
        WHERE j.convertdate BETWEEN '2017-01-02' AND '2017-07-31' 
        AND j.status IN (4,6,7,8,11)
        ) n
        JOIN assignmentstbl a USING (custid)
        JOIN usertbl u USING (userid)
        GROUP BY a.userid,n.weeks
        ORDER BY newB DESC
    )INNERTABLE
    LEFT JOIN weekstbl CL ON CL.weekNo=INNERTABLE.weeks

这返回了以下结果集(第1,3周(针对salesman2)或5)不包括0:

 +-----------+--------+-------------+
 | salesman  | weekNo | sales total |
 +-----------+--------+-------------+
 | salesman1 |   2    |     100     |
 | salesman2 |   2    |     100     |
 | salesman1 |   3    |    1300     |
 | salesman1 |   4    |     450     |
 | salesman2 |   4    |    1070     |
 +-----------+--------+-------------+

试验4:

与此相近一点

SELECT 
    w.weekNo, COALESCE(ROUND(SUM(n.newBalance), 2),0) AS newB, n.username
FROM 
    weekstbl w
LEFT JOIN (
  SELECT 
      j.leadid AS custid,
      j.convertdate AS sold,
      u.username AS username,
      j.price / (SELECT count(*) FROM assignmentstbl a WHERE a.custid=j.leadid) AS newBalance
  FROM 
      jobbooktbl j
  JOIN assignmentstbl a ON j.leadid = a.custid
  JOIN usertbl u ON u.userid = a.userid
) n 
ON 
    w.weekNo = WEEK(n.sold)
GROUP BY
    n.username, w.weekNo
ORDER BY 
    w.weekNo

这返回了以下结果集(第1周和第5周返回0,但没有识别推销员,并且在第3周没有为salesman2返回0):

 +-----------+--------+-------------+
 | salesman  | weekNo | sales total |
 +-----------+--------+-------------+
 |  (null)   |   1    |      0      |
 | salesman1 |   2    |     100     |
 | salesman1 |   2    |     100     |
 | salesman1 |   3    |    1300     |
 | salesman1 |   4    |     450     |
 | salesman2 |   4    |    1070     |
 |  (null)   |   5    |      0      |
 +-----------+--------+-------------+

2 个答案:

答案 0 :(得分:1)

我在weekstbl中添加了一个联接。你可以查看下面的查询。我希望这有帮助。

SELECT ROUND(SUM(n.newBalance), 2) AS newB, weeks, u.username
  FROM (
    SELECT 
        j.leadid AS custid, 
        w.weekno AS weeks,
        j.price / (SELECT count(*) FROM assignmentstbl a WHERE a.custid=j.leadid) AS newBalance
    FROM jobbooktbl j
    join weekstbl w on j.convertdate between weekstart and date(weekstart + interval 6 day )
    WHERE j.convertdate BETWEEN '2017-01-02' AND '2017-07-31' 
    AND j.status IN (4,6,7,8,11)
    ) n
    JOIN assignmentstbl a USING (custid)
    JOIN usertbl u USING (userid)
    -- WHERE a.userid=5
    GROUP BY weeks, a.userid
    ORDER BY newB DESC

这是一个更新的答案。

select userid, username, week, year, fvalue
from ( select sub3.*, 
if(@previous = userid, @value1 := @value1 + value, @value1 := value ) fvalue,
@previous := userid
from (select distinct ut.userid, ut.username, 
week(date) as week,year(date) as year ,coalesce(sub2.newB,0) as value
from ( SELECT (CURDATE() - INTERVAL c.number DAY) AS date
FROM (SELECT singles + tens + hundreds number FROM 
( SELECT 0 singles
UNION ALL SELECT   1 UNION ALL SELECT   2 UNION ALL SELECT   3
UNION ALL SELECT   4 UNION ALL SELECT   5 UNION ALL SELECT   6
UNION ALL SELECT   7 UNION ALL SELECT   8 UNION ALL SELECT   9
) singles JOIN 
(SELECT 0 tens
UNION ALL SELECT  10 UNION ALL SELECT  20 UNION ALL SELECT  30
UNION ALL SELECT  40 UNION ALL SELECT  50 UNION ALL SELECT  60
UNION ALL SELECT  70 UNION ALL SELECT  80 UNION ALL SELECT  90
) tens  JOIN 
(SELECT 0 hundreds
UNION ALL SELECT  100 UNION ALL SELECT  200 UNION ALL SELECT  300
UNION ALL SELECT  400 UNION ALL SELECT  500 UNION ALL SELECT  600
UNION ALL SELECT  700 UNION ALL SELECT  800 UNION ALL SELECT  900
) hundreds
ORDER BY number DESC) c  ) abc 
cross join usertbl ut
left join (
  SELECT ROUND(SUM(n.newBalance), 2) AS newB, weeks, years,a.userid, u.username
  FROM (
    SELECT 
        j.leadid AS custid, 
        w.weekno AS weeks,
    year(weekstart) as years,
        j.price / (SELECT count(*) FROM assignmentstbl a WHERE a.custid=j.leadid) AS newBalance
    FROM jobbooktbl j
    join weekstbl w on j.convertdate between weekstart and date(weekstart + interval 6 day )
    WHERE j.convertdate BETWEEN '2017-01-02' AND '2017-07-31' 
    AND j.status IN (4,6,7,8,11)
    ) n
    JOIN assignmentstbl a USING (custid)
    JOIN usertbl u on u.userid = a.userid
    GROUP BY weeks, a.userid
) sub2 on sub2.userid = ut.userid 
and weeks = week(date)
and years = year(date)
where date between '2017-01-02' AND '2017-07-31' 
order by userid,year(date), week(date) ) sub3 ) sub4
order by year, week, userid

注意:我建议创建dim_time表,它存储日期的所有相关信息。

说明:

1)子查询名称:abc 这将根据您的输入生成周和年。之后用usertbl交叉加入你的结果。你想要的那么多行 最终输出。现在我们根据您的要求添加值。

2)子查询名称:sub2
这会产生您所需的结果,但它没有显示0值。

3)现在1离开加入2 这会给你结果(按星期分组然后由销售员分组)。更改order by子句只是为了获得预期的输出 这成为你的sub3。这是必要的,因为我们必须将前一个值加到下一个值。

4)创建varialbe @previous和@ value1 因为我们已根据用户标识对结果进行了排序。现在第一行来了,它检查下面的条件。然后它转到其他部分,因为它不匹配, 将用户标识存储在@previous中。现在它会占用第二行,它会将前一个值添加到下一行,因为条件已满足。相似它会添加 你的结果,直到新用户ID来。

Condtion:

MySQL (@previous = userid,  @value1 := @value1 + value ,@value1 := value)

if @previous = userid 
then @value1 := @value1 + value 
else @value1 := value; 

我希望这会有所帮助。

答案 1 :(得分:0)

SELECT * FROM (
 SELECT ROUND(SUM(n.newBalance), 2) AS newB, u.username,weeks
      FROM (
        SELECT 
            j.leadid AS custid, 
            WEEK(j.convertdate) AS weeks,
            j.price / (SELECT count(*) FROM assignmentstbl a WHERE a.custid=j.leadid) AS newBalance
        FROM jobbooktbl j
        WHERE j.convertdate BETWEEN '2017-01-02' AND '2017-07-31' 
        AND j.status IN (4,6,7,8,11)
        ) n
        JOIN assignmentstbl a USING (custid)
        JOIN usertbl u USING (userid)
        GROUP BY a.userid,n.weeks
        ORDER BY newB DESC
    )INNERTABLE
    LEFT JOIN CALENDAR CL ON CL.WEEK=INNERTABLE.weeks

您可以尝试以上查询。

现在使用Calendar Table创建一个日历表。

使用上面的查询并使用日历表进行连接,您可以实现您想要的效果。表示该周没有条目的记录的0值。