当前位置: 首页 > 知识库问答 >
问题:

基于联接的高级查询

东门令
2023-03-14

我的架构如下所示:

SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));


create table ads(
  ad_id int,
  ad_name varchar(10)
);

create table ads_insight(
   id int,
   ad_id int,
   date date, 
   ad_clicks int
 );
create table products(
    id int,
    name varchar(10)
);
create table products_insight(
    id int,
    product_id int, 
    sale int, 
    date date
);
create table ads_products(
    ad_id int,
    product_id int
);
                                    

                                    
insert into ads(ad_id, ad_name) values
  (1,'ad1'),
  (2,'ad2'),
  (3,'ad3');
 
 
insert into ads_insight(id, ad_id, date, ad_clicks) values
    (1, 1, '2021-04-25', 1),
    (3, 1, '2021-04-23', 2),
    (4, 1, '2021-04-22', 8),
    (5, 2, '2021-04-25', 6),
    (6, 2, '2021-03-03', 7);


insert into products(id, name) values
    (1,'prod1'),
    (2,'prod2'),
    (3,'prod3'),
    (4,'prod4'),
    (5,'prod5');
                                        
insert into ads_products (ad_id, product_id) values 
    (1, 1),
    (1, 2),
    (2, 3),
    (2, 4),
    (2, 2),
    (3, 1);
insert into products_insight(id, product_id, sale, date) values
    (1, 1, 10, '2021-04-25'),
    (2, 1, 13, '2021-04-24'),
    (3, 1, 15, '2021-04-23'),
    (4, 1, 14, '2021-04-22'),
    (5, 1, 17, '2021-04-21'),
    (6, 1, 15, '2021-04-20'),
    (7, 1, 13, '2021-04-19'),
    (8, 2, 15, '2021-04-25');

这是你的小提琴

图式的快速解释:我有广告:

  1. 每个广告都有洞察力,这些洞察力告诉我们某个广告何时处于活动状态(=>ad_clicks必须>0)。
  2. 每个ad都有产品(MANY2MONE-ADS_Products表)。每个产品都有products_insight,它告诉我们该产品在某一天产生了多少销售额。

现在,我想获取时间范围2021-04-20-2021-04-25的所有广告,这些广告的ad_clicks>0(我已经做了),并计算每个广告在活动时产生了多少销售额。因此,只有当广告的ad_insight和ad_clicks大于0时,才计算销售。

我的查询如下所示:

SET @from_date = '2021-04-20';
SET @to_date = '2021-04-25';

SELECT 
    ads.ad_name, 
    IFNULL(ad_clicks, 0) AS clicks, 
    IFNULL(product_sale, 0) AS product_sale, 
    IFNULL(products, '') AS products
FROM ads
LEFT JOIN (
    SELECT ad_id, SUM(ad_clicks) AS ad_clicks
    FROM ads_insight
    WHERE date BETWEEN @from_date AND @to_date
    GROUP BY ad_id
) AS ai ON ai.ad_id = ads.ad_id
LEFT JOIN (
    SELECT ad_id, SUM(sale) AS product_sale
    FROM ads_products AS ap
    LEFT JOIN products_insight AS pi ON pi.product_id = ap.product_id
    WHERE date BETWEEN @from_date AND @to_date
    GROUP BY ad_id
) AS pi ON pi.ad_id = ads.ad_id
LEFT JOIN (
    SELECT ap.ad_id, GROUP_CONCAT(DISTINCT p.name) AS products
    FROM ads_products AS ap 
    JOIN products AS p ON ap.product_id = p.id
    GROUP BY ap.ad_id
) AS p ON ads.ad_id = p.ad_id 
WHERE ad_clicks>0;

并生成以下结果:

| ad_name | clicks | product_sale | products          |
| ------- | ------ | ------------ | ----------------- |
| ad1     | 11     | 99           | prod1,prod2       |
| ad2     | 6      | 15           | prod2,prod3,prod4 |

但我希望这样(在PRODUCT_SALEL列中有区别)

| ad_name | clicks | product_sale | products          |
| ------- | ------ | ------------ | ----------------- |
| ad1     | 11     | 54           | prod1,prod2       |
| ad2     | 6      | 15           | prod2,prod3,prod4 |

54因为它只计算products_insight中id为1,3,4的行,因为在这些日子里id为1的ad处于活动状态。(活动表示ads_insight表中有一行。

共有1个答案

杜浩壤
2023-03-14

您可以在pi子查询中添加相同的日期conition。将有效地使其内部连接

..
    (SELECT ap.ad_id, sum(pi.sale) AS product_sale
    FROM ads_products AS ap
    JOIN ads_insight AS ai ON ai.ad_id = ap.ad_id
        AND date BETWEEN @from_date AND @to_date
    JOIN products_insight AS pi ON pi.product_id = ap.product_id AND pi.date = ai.date 
    GROUP BY ap.ad_id) as pi ..

整个查询,其余的都是从原来的一个

SET @from_date = '2021-04-20';
SET @to_date = '2021-04-25';

SELECT 
    ads.ad_name, 
    IFNULL(ad_clicks, 0) AS clicks, 
    IFNULL(product_sale, 0) AS product_sale, 
    IFNULL(products, '') AS products
FROM ads
LEFT JOIN (
    SELECT ad_id, SUM(ad_clicks) AS ad_clicks
    FROM ads_insight
    WHERE date BETWEEN @from_date AND @to_date
    GROUP BY ad_id
) AS ai ON ai.ad_id = ads.ad_id
LEFT JOIN (
    SELECT ap.ad_id, sum(pi.sale) AS product_sale
    FROM ads_products AS ap
    JOIN ads_insight AS ai ON ai.ad_id = ap.ad_id
        AND date BETWEEN @from_date AND @to_date
    JOIN products_insight AS pi ON pi.product_id = ap.product_id AND pi.date = ai.date 
    GROUP BY ap.ad_id
) AS pi ON pi.ad_id = ads.ad_id
LEFT JOIN (
    SELECT ap.ad_id, GROUP_CONCAT(DISTINCT p.name) AS products
    FROM ads_products AS ap 
    JOIN products AS p ON ap.product_id = p.id
    GROUP BY ap.ad_id
) AS p ON ads.ad_id = p.ad_id 
WHERE ad_clicks>0;

小提琴

 类似资料:
  • 我想从short_name(国家名称)、name(州表)或region_name的任何可用数据中选择post_id。对region_name而不是short_name(国家名称),name(州表)执行以下查询,结果为真。 请告诉我,我哪里弄错了!

  • 快捷查询 快捷查询方式是一种多字段相同查询条件的简化写法,可以进一步简化查询条件的写法,在多个字段之间用|分割表示OR查询,用&分割表示AND查询,可以实现下面的查询,例如: Db::table('think_user') ->where('name|title','like','thinkphp%') ->where('create_time&update_time','>',0

  • 本文向大家介绍基于vue2.0实现的级联选择器,包括了基于vue2.0实现的级联选择器的使用技巧和注意事项,需要的朋友参考一下 基于Vue的级联选择器,可以单项,二级, 三级级联,多级级联 web开发中我们经常会遇到级联选择器的问题,尤其是在表单中,无外乎几种情况: 单个级联 (下拉选择框,单选) 单个级联 (多项选择) 二级联动 (省份和城市联动) 三级联动 (省市区联动) 在jquery中有

  • 我想用OpenCV fullbody Haar Cascades检测图像中的人体。这是我的代码: 结果如下: 后果 如您所见,我的代码没有检测到图像中的整个人体。 顺便说一句,我是OpenCv的新手,这是我在这里的第一个问题,所以如果我做错了什么,请纠正我,我希望有人能帮助我纠正我的代码。 抱歉英语不好;)。

  • 问题内容: 我在SQL中有两个表,并且我需要能够基于早于或等于表A中的时间戳的表B中的时间戳进行联接。 因此,这是两个表和所需输出的一些虚假数据: 结案案例(表A) 分类(表B) 所需结果 因此,我知道代码需要如下所示,我只是想不出该如何处理部分($ 1和$ 2是将要传入的变量): 我知道我可以使用子选择,但这将在至少几千行,甚至可能更多的行上进行,我需要它真的要快。所以我希望有一个简单的子句可以

  • ORM 以 QuerySeter 来组织查询,每个返回 QuerySeter 的方法都会获得一个新的 QuerySeter 对象。 基本使用方法: o := orm.NewOrm() // 获取 QuerySeter 对象,user 为表名 qs := o.QueryTable("user") // 也可以直接使用对象作为表名 user := new(User) qs = o.QueryTab