MYSQL通过Sales和Group按Sales和weeks加入weeks表

MYSQL通过Sales和Group按Sales和weeks加入weeks表,mysql,left-join,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 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
这将返回以下内容(按销售人员分组):

我希望能做到的是,这一点将按周列出,并返回以下内容(按周分组,然后按销售人员分组):

如果可能的话,还有一个类似这样的汇总(按销售人员按周分组,包含运行总计/汇总):

以下是迄今为止的模式:

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')
;
下面是一个包含上述所有信息的示例

我试着把两张桌子合在一起,但没有用。我真的是SQL的初学者,所以这有点不合我的口味。我还创建了weekstbl,只是因为我不知道如何在不包含任何销售人员值的周内返回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
这返回了以下结果集,其中不包括第1周、第3周(对于salesman2)或第5周的0:

试验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):

试验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):

试验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周未返回销售人员2的0):

您可以尝试上面的查询

现在使用创建一个日历表


使用上述查询并与日历表进行联接,您可以实现所需的功能。表示该周没有条目的记录的0值。

我已在weekstbl中添加了一个join。您可以在下面的查询中进行检查。我希望这有帮助

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_时间表,其中存储日期的所有相关信息

说明:

1) 子查询名称:abc 这将根据您的输入生成周和年。然后将结果与usertbl交叉连接。您希望在应用程序中有多少行 最终输出。现在我们已经根据您的要求添加了值

2) 子查询名称:sub2
这将生成所需的结果,但不会显示0值

3) 现在1左加入2 这会将结果显示为(按周分组,然后按销售人员分组)。更改order by子句只是为了获得预期的输出。
这将成为您的sub3。这是必要的,因为我们必须将上一个值和下一个值相加

4) 创建varialbe@previous和@value1 因为我们已经根据userid对结果进行了排序。现在,第一行来检查以下条件。然后它转到其他部分,因为它不匹配, 将userid存储在@previous中。它现在执行第二行,它将把上一个值添加到下一行,因为条件满足。同样,它也会增加 直到新的用户ID出现,您的结果才会显示出来

条件:

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

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

我希望这会有所帮助

连接是给我带来麻烦的部分,我需要帮助。此查询返回按周分组的值,但不返回我缺少的0值。谢谢Sagar。@CraigHowell我知道你只需要做一个日历表,并将整个查询加入其中。查看此问题以创建日期范围。@SagarGangwal这里有一个sqlfiddle-显示您的代码,但我仍然显示一个没有0的结果,我缺少什么?这是返回
[['salesman 1',100],'salesman 2',100],'salesman 1',1300],'salesman 2',1070],'salesman 1',450]
这缺少0。这是返回
[[salesman 1',100],[salesman 2',100],[salesman 1',1300],[salesman 2',1070],[salesman 1',450]]
这缺少0。这意味着它应该显示所有的周值。对于您选择的输入,应该有多少个0。我已更新了问题,以包含一个更好的结果集,显示0'初始检查看起来不错,可能信息太多,但我会看一看now@CraigHowell我加了解释,请看一下。你可以投票并打勾我的回答是正确的。
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
 +-----------+--------+-------------+
 | salesman  | weekNo | sales total |
 +-----------+--------+-------------+
 | salesman1 |   2    |     100     |
 | salesman2 |   2    |     100     |
 | salesman1 |   3    |    1300     |
 | salesman1 |   4    |     450     |
 | salesman2 |   4    |    1070     |
 +-----------+--------+-------------+
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
 +-----------+--------+-------------+
 | 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      |
 +-----------+--------+-------------+
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
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
MySQL (@previous = userid,  @value1 := @value1 + value ,@value1 := value)

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