MySQL选择组和一对多关系条件

时间:2018-01-24 13:14:53

标签: mysql

例如有这样的结构:

CREATE TABLE clicks
    (`date` varchar(50), `sum` int, `id` int)
;
CREATE TABLE marks
    (`click_id` int, `name` varchar(50), `value` varchar(50))
;

其中点击可以有很多标记

示例数据:

INSERT INTO clicks
    (`sum`, `id`, `date`)
VALUES
    (100, 1, '2017-01-01'),
    (200, 2, '2017-01-01')
    ;
INSERT INTO marks
    (`click_id`, `name`, `value`)
VALUES
    (1, 'utm_source', 'test_source1'),
    (1, 'utm_medium', 'test_medium1'),
    (1, 'utm_term', 'test_term1'),
    (2, 'utm_source', 'test_source1'),
    (2, 'utm_medium', 'test_medium1')
    ;

我需要获得按date分组的点击值,其中包含所有选定的值。 我提出要求:

select 
  c.date,
  sum(c.sum)
from clicks as c
left join marks as m ON m.click_id = c.id
where 
(m.name = 'utm_source' AND m.value='test_source1') OR
(m.name = 'utm_medium' AND m.value='test_medium1') OR
(m.name = 'utm_term' AND m.value='test_term1')
group by date

并获得2017-01-01 = 700,但我想获得100,这意味着只有点击1有所有标记。 或者如果条件是

(m.name = 'utm_source' AND m.value='test_source1') OR
(m.name = 'utm_medium' AND m.value='test_medium1')

我需要300而不是600

我找到了通过第一个查询得到明显的click_id,然后按条件whereIn对日期和日期进行求和的答案,但是对于非常大且具有id作为uuid的真实数据库,此请求执行时间过长。任何建议如何让它正常工作?

3 个答案:

答案 0 :(得分:1)

您可以使用以下查询来实现: 当有三个条件时,您必须通过HAVING count(*) >= 3

SELECT cc.DATE
    ,sum(cc.sum)
FROM clicks AS cc
INNER JOIN (
    SELECT id
    FROM clicks AS c
    LEFT JOIN marks AS m ON m.click_id = c.id
    WHERE (
            m.NAME = 'utm_source'
            AND m.value = 'test_source1'
            )
        OR (
            m.NAME = 'utm_medium'
            AND m.value = 'test_medium1'
            )
        OR (
            m.NAME = 'utm_term'
            AND m.value = 'test_term1'
            )
    GROUP BY id
    HAVING count(*) >= 3
    ) AS t ON cc.id = t.id
GROUP BY cc.DATE

当有三个条件时,您必须通过HAVING count(*) >= 2

SELECT cc.DATE
    ,sum(cc.sum)
FROM clicks AS cc
INNER JOIN (
    SELECT id
    FROM clicks AS c
    LEFT JOIN marks AS m ON m.click_id = c.id
    WHERE (
            m.NAME = 'utm_source'
            AND m.value = 'test_source1'
            )
        OR (
            m.NAME = 'utm_medium'
            AND m.value = 'test_medium1'
            )
    GROUP BY id
    HAVING count(*) >= 2
    ) AS t ON cc.id = t.id
GROUP BY cc.DATE

演示:http://sqlfiddle.com/#!9/fe571a/35

希望这对你有用......

答案 1 :(得分:1)

您获得700,因为联接会为不同的ID生成多行。 mark表格中有3行ID=1sum=100,并且有两行ID=2sum=200。在执行join时,其中3行sum = 100,2行sum = 200,所以添加这些和得到700.要解决这个问题,你必须在click_id上聚合,如下图所示:

select 
  c.date,
  sum(c.sum)
from clicks as c
inner join (select * from marks where (name = 'utm_source' AND     
    value='test_source1') OR (name = 'utm_medium' AND value='test_medium1')  
    OR (name = 'utm_term' AND value='test_term1')
    group by click_id) as m
ON m.click_id = c.id
group by c.date;

<强> DEMO SQL FIDDLE

答案 2 :(得分:1)

我自己找到了正确的方法,它可以处理大量数据 主要目标是使请求生成一个包含子查询(条件)的表,这些表不依赖于结果中的数据量,因此最好的方法是:

exp(c * ln(b))

因此,我们需要根据我们的许多条件进行多次连接