我有一个像这样的表DATA
+--------+--------+----------+------+
| TranID | CustID | TransSeq | Type |
+--------+--------+----------+------+
| 1 | 100 | 1 | A |
| 2 | 100 | 2 | A |
| 3 | 100 | 3 | B |
| 4 | 200 | 1 | A |
| 5 | 200 | 2 | B |
| 6 | 200 | 3 | A |
| 7 | 200 | 4 | A |
| 8 | 200 | 5 | A |
+--------+--------+----------+------+
我想获取Type B
之前的所有记录。因此,我的输出将是这样
+--------+--------+----------+------+
| TranID | CustID | TransSeq | Type |
+--------+--------+----------+------+
| 1 | 100 | 1 | A |
| 2 | 100 | 2 | A |
| 4 | 200 | 1 | A |
+--------+--------+----------+------+
我能想到的一种方法是
步骤1-创建存储CustID和TransSeq的临时表,其中类型== B
CREATE TABLE TEMP AS
select CustID, TransSeq as TransSeq_B from DATA
where Type = "B"
第1步的输出如下所示
+--------+------------+------+
| CustID | TransSeq_B | Type |
+--------+------------+------+
| 100 | 3 | B |
| 200 | 2 | B |
+--------+------------+------+
第2步-使用CustID将TEMP与DATA合并
CREATE TABLE DATA_NEW AS
select D.TranID, D.CustID, D.TransSeq, D.Type, T.TransSeq_B
from DATA inner join TEMP on D.CustID = T.CustID
第2步的输出如下所示
+--------+--------+----------+------+------------+
| TranID | CustID | TransSeq | Type | TransSeq_B |
+--------+--------+----------+------+------------+
| 1 | 100 | 1 | A | 3 |
| 2 | 100 | 2 | A | 3 |
| 3 | 100 | 3 | B | 3 |
| 4 | 200 | 1 | A | 2 |
| 5 | 200 | 2 | B | 2 |
| 6 | 200 | 3 | A | 2 |
| 7 | 200 | 4 | A | 2 |
| 8 | 200 | 5 | A | 2 |
+--------+--------+----------+------+------------+
第3步-从第2步查询此新表,并保留所有TransSeq都小于TransSeq_B的记录
select * from DATA_NEW
where TransSeq < TransSeq_B
有很多记录(> 20M)
,有什么有效的方法吗?答案 0 :(得分:2)
一种方法使用EXISTS
查询。下面的EXISTS
子句为表中的每个记录检查具有相同CustID
值的所有其他记录,以检查是否存在类型为B
的较早记录。如果没有,那么该记录将被添加到结果集中。
SELECT *
FROM DATA d1
WHERE
d1.Type = 'A' AND
NOT EXISTS (SELECT 1 FROM DATA d2
WHERE d1.CustID = d2.CustID AND d2.TranID < d1.TranID AND
d2.Type = 'B');
答案 1 :(得分:2)
基本上,您的想法很正确-唯一需要做的就是代替创建新表,而将相关查询用作JOIN
中的Views:
SELECT
beforeB.*
FROM
Table1 AS beforeB
INNER JOIN (
SELECT
CustID,
MIN(TransSeq) AS TransSeq
FROM Table1
WHERE Type='B'
GROUP BY CustID
) AS theB
ON beforeB.CustID=theB.CustID
WHERE
beforeB.TransSeq<theB.TransSeq
强制性SQLfiddle here。
说明:theB
视图从表中为每个客户过滤B型事件。它与作为选择器的客户ID上的交易表连接,仅保留具有较低TransSqq
的行。
与EXISTS
相比,这可能更有效,因为如果可以将JOIN
ed视图保留在RAM中,则根据结果集的大小和索引,无需为每行运行子查询。在查询期间。
答案 2 :(得分:0)
可能会自行加入表格。下面的查询对于类型A的行具有别名 A,对于类型B的行具有别名(同时仍使用相同的实际表DATA)。通过对A进行分组,您可以使用集合函数 min(B.TransSeq)
来获取该客户的最低B序列。这样,您就可以获取所有在min(B)之前的A。
我打算提出第二种解决方案,并在子选择上加入联接,但这基本上就是Eugen Rieck提出的方案,因此我会坚持使用这一方案,并让您测试哪种方案最适合您的方案。总体思路是一样的。
我不知道这是比其他解决方案快还是慢。我认为此查询绝对可以从(CustId,Type)和/或(CustId,Type,TransId)的组合索引中受益。如果是这样,它可能会更高效,因为它先连接然后是组(以便更好地使用索引),或者效率可能更低,因为它必须使用更大的中间数据集。因此,这取决于各种因素,包括您拥有的索引,硬件配置以及是否要为一小部分客户或整个表查询此问题。
select
A.*
from
DATA A
inner join DATA B on B.custid = A.custID and B.Type = 'B'
where
A.Type = 'A'
-- and A.CustId = 100 -- if you like to filter by customer
group by
A.TranId
having
A.TransSeq < min(B.TransSeq);