1

给定两张桌子,

  • A包含customerid, lastchange,的表internallink

  • B包含internallink,turnover

(我这里只是简单的把它改成一个通用的例子,实际的结构更复杂。SQL方言现在是mySQL。)

唯一独特的东西(每个表)是内部链接。A 中有几条记录具有相同的 customerID、不同的 lastchange 日期和不同的 internallink 值。还有其他与此相关的项目;我无法更改表格。

我需要来自 A 的记录 ID,它们是客户的最新记录(具有相同 customerID 的所有记录中的最高 lastchange 值),并且B 中与某个值条件匹配的条目链接到这些记录 ID。

我觉得

SELECT `internallink` FROM `B` WHERE (`turnover` > 10000) 

部分不是问题。

我做到了这一点:

SELECT `customerID`, MAX(`lastchange`)
  FROM `A` 
 WHERE `lastchange` IN (SELECT `internallink` FROM `B` 
                         WHERE `turnover` > 10000)
 GROUP BY `customerID`;

唉,该语句给出了错误的结果,因为上面将返回我最近的值不满足条件的客户 ID,但是一些较旧的值 - 它选择最旧的值,并返回这个。但是,如果最近的条目低于阈值,那么 customerID 根本不应该出现。

我哪里出错了,正确的方法是什么?

样本数据表 A

customerid lastchange 内部链接
         3 2010-02-11 11
         3 2010-09-04 12
         3 2010-10-22 13
         3 2010-11-23 14
         4 2010-05-05 15
         4 2010-12-01 16
         5 2010-11-28 17
         5 2010-11-29 18

表 B

内部链接周转
          11 47000
          12 11000
          13 8000
          14 15000
          15 17000
          16 23000
          17 50000
          18 10000

我的测试中的实际阈值是 12000。您可以看到 customerID 不应该在结果集中,因为最近的条目低于阈值。

结果集应该是 (3,2010-11-23)(4,2010-12-01) - 但目前它还包含 (5,2010-11-28),这是错误的。


靠近一点(在您的帮助下,谢谢!),这两个语句都有效:

SELECT customerID, MAX(lastchange), internallink FROM A GROUP BY customerID; SELECT internallink FROM B WHERE (营业额 > 12000);

现在我需要的是两者的交集......具有正确的逻辑!

4

3 回答 3

1

以下查询应该做你想做的事。这不是编写此类查询的最高效方式。但它使用标准 SQL,并且可以在任何数据库中执行。

工作原理如下:内部子查询查找所有客户 ID 以及最新的更改日期。对于每个这样的对(customerid, lastchange),我们在表 A 中找到原始行。在表 A 中找到一行后,我们使用内部链接在 B 中查找匹配记录,但前提是关联的营业额大于 10000。

drop table a;
drop table b;

create table a(
   customerid   int  not null
  ,lastchange   date not null
  ,internallink int  not null
);

create table b(
   internallink int not null
  ,turnover     int not null
);

insert into a values(3, date '2010-02-11', 11);
insert into a values(3, date '2010-09-04', 12);
insert into a values(3, date '2010-10-22', 13);
insert into a values(3, date '2010-11-23', 14);
insert into a values(4, date '2010-05-05', 15);
insert into a values(4, date '2010-12-01', 16);
insert into a values(5, date '2010-11-28', 17);
insert into a values(5, date '2010-11-29', 18);

insert into b values(11, 47000);
insert into b values(12, 11000);
insert into b values(13,  8000);
insert into b values(14, 15000);
insert into b values(15, 17000);
insert into b values(16, 23000);
insert into b values(17, 50000);
insert into b values(18, 10000);

select a.customerid
      ,a.lastchange
      ,a.internallink
      ,b.turnover
  from a
  join b on (a.internallink = b.internallink)
 where b.turnover > 10000
   and (a.customerid, a.lastchange) in(select customerid,max(lastchange)
                                         from a
                                     group by customerid);
于 2010-12-03T09:19:31.533 回答
0

经过大量测试和一些研究,我找到了这个解决方案,我发布这个以防其他人遇到类似的问题。

一个额外的表“缓存”保留了表 A 中最新条目的副本,从而大大降低了复杂性。它通过使用这样的触发器保持最新:

在 FOR EACH ROW 上插入后创建触发器 sync_a_insert
    插入缓存(`customerID`,`internallink`)值(NEW.`customerID`,NEW.`internallink`);
在每行更新后创建触发器 sync_a_update
    更新缓存 SET `internallink` = NEW.`internallink` WHERE (`customerID` = NEW.`customerID`);
在 FOR EACH ROW 上删除之前创建触发器 sync_a_delete
    从缓存中删除 `customerID` = OLD.`customerID`;

对于 INSERT 和 UPDATE,这些触发器在事后触发,因此表 a 中的条目在缓存更新之前是完整的。对于 DELETE,需要在原始条目消失之前更新缓存。

一旦到位,其他一切都变得简单:

从缓存中选择 `customerID` WHERE `internallink` IN
    (SELECT `internallink` FROM b WHERE (`turnover` > 10000));

对我来说,这是一个可行的解决方案,它甚至可以加快查找速度。当然,数据库大小是有代价的,但我认为整体性能要好得多——只要读取访问权限比写入访问权限多至少一次,就会有改进。

但是,您给出的答案对我很有帮助。我从他们那里学到了很多东西,并尝试遵循您的建议(甚至已经将其中一些用于其他地方)。感谢所有回答我问题的人!

于 2010-12-04T06:45:13.757 回答
0

这适用于 sql server - 我不确定 mySql 是否具有类似的排名功能。

select a.id, a.lastchange, b.turnover, a.rownumber from B b inner join 
(SELECT id, lastchange, internallink, ROW_NUMBER() OVER(PARTITION BY id ORDER BY lastchange DESC) AS 'rownumber'
FROM A) a on b.internallink = a.internallink
where a.rownumber = 1 and b.turnover > 5000

“ROW_NUMBER() OVER(PARTITION BY id ORDER BY lastchange DESC) AS 'rownumber'” 表示...

我想将所有相同的 id 组合在一起,并在计算每一行之后按 desc 的 lastchange 对它们进行排序。哦,并命名该列的行号。

id  lastchange    internallink  rownumber
1   2010-01-03    2           1
1   2010-01-02    1           2
1   2010-01-01    1           3
2   2010-01-04    2           1

选择行号为 1 的任何记录将返回 id 的最后修改记录。

于 2010-12-03T07:18:41.217 回答