SQL查询帮助GROUPing和嵌套查询

时间:2010-12-03 06:37:27

标签: sql group-by nested grouping query-help

给出两个表,

  • 包含Acustomeridlastchange

  • 的表internallink
  • 包含Binternallink

  • 的表turnover

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

唯一的独特之处(每个表)是internallink。 A中有几条记录具有相同的customerID,lastchange中的不同日期以及不同的internallink值。 还有其他与此相关的项目;我无法改变这些表格。

我需要来自A的记录ID,它是客户的最新记录(具有相同customerID的所有客户ID的最高更改值),B中的条目与某个值匹配条件是相互联系的。

我认为

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`;

唉,这个陈述给出了错误的结果,因为上面会给我返回最近的值不符合标准的customerID,但是有些旧的 - 它会选择最早的那个,然后返回。但是如果最近的条目低于阈值,则customerID根本不应该出现。

我哪里出错了,对此有什么正确的解决方法?

示例数据 表A

customerid   lastchange   internallink
         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

internallink  turnover
          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);

现在我所需要的只是两者的交集......用正确的逻辑!

3 个答案:

答案 0 :(得分:1)

以下查询应该执行您想要的操作。 是编写此类查询的最佳方式。但它使用的是标准SQL,并且可以在任何数据库中执行。

这样的工作:内部子查询找到所有customerid以及最新的更改。对于每个这样的对(customerid,lastchange),我们在表A中找到原始行。在表A中找到一行后,我们使用internallink在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);

答案 1 :(得分: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命令它们。哦,并列出列rownumber。

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

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

答案 2 :(得分:0)

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

附加表“cache”保留表A中最新条目的副本,大大降低了复杂性。它通过使用这样的触发器保持最新:

CREATE TRIGGER sync_a_insert AFTER INSERT ON a FOR EACH ROW 
    INSERT INTO cache (`customerID`, `internallink`) VALUES (NEW.`customerID`,NEW.`internallink`);
CREATE TRIGGER sync_a_update AFTER UPDATE ON a FOR EACH ROW 
    UPDATE cache SET `internallink` = NEW.`internallink` WHERE (`customerID` = NEW.`customerID`);
CREATE TRIGGER sync_a_delete BEFORE DELETE ON a FOR EACH ROW 
    DELETE FROM cache WHERE `customerID` = OLD.`customerID`;

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

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

SELECT `customerID` FROM cache WHERE `internallink` IN 
    (SELECT `internallink` FROM b WHERE (`turnover` > 10000));

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

但是,你给出的答案对我很有帮助。我从他们那里学到了很多东西,并试图遵循你的建议(甚至把它的一部分用于其他地方)。感谢所有回答我问题的人!