我有一个查询,我试图找出客户ID之间的链关系。目前约有8万条记录。 7分钟。你能否提出一些其他改进方法?
样本格式如下所示。在这里,我们基于具有它们之间关系的记录进行分组(a = b = c)
Create table #chaintable
(
CustID int,
MatchCustID int,
FN varchar(10),
LN varchar(10),
PhoneNo int,
Email varchar(50),
dtAppointment int
)
insert into #chaintable
Select 1,2,'Global','Chain',123,'',1
union all
Select 2,3,'Global','Chain',123,'a@a.com',2
union all
Select 3,2,'Global','Chain',567,'a@a.com',3
union all
Select 4,5,'Global1','Chain1',123,'a@a.com',1
union all
Select 5,4,'Global1','Chain1',123,'a@a.com',2
Select distinct
A.CustID, A.MatchCustID, A.GroupID
from
(select
c1.CustID, c1.MatchCustID, C1.dtAppointment,
case
when C1.CustID = C2.MatchCustID and C1.MatchCustID <> C2.CustID
then C1.CustID
when C1.CustID <> C2.MatchCustID and C1.MatchCustID = C2.CustID
then c1.MatchCustID
when C1.CustID = C2.MatchCustID and C1.MatchCustID = C2.CustID
then
case
when c1.CustID < C1.MatchCustID
then c1.CustID
else c1.MatchCustID
end
end GroupID
from
#chaintable C1, #chaintable C2
where
c1.CustID = c2.MatchCustID
or c1.MatchCustID = c2.CustID) A
输出:
CustID MatchCustID FN LN PhoneNo Email dtAppointment
---------------------------------------------------------
1 2 Global Chain 123 1
2 3 Global Chain 123 a@a.com 2
3 2 Global Chain 567 a@a.com 3
4 5 Global1 Chain1 123 a@a.com 1
5 4 Global1 Chain1 123 a@a.com 2
答案 0 :(得分:0)
首先,在不知道执行计划的情况下,无法帮助提高查询的性能。
这里有一些我不明白的问题。例如,为什么要连接到表本身,所有输出都是第一个表的值。加入真的有必要吗?或者仅仅是为了测试?
我建议以下&#34;在逻辑上等同于&#34;在不使用JOIN中的OR
的情况下重写查询的方法,以及更少的工作来理解对人的查询(如果计算机感觉相同,那么它可能会改进)。
SELECT DISTINCT c1.CustID, c1.MatchCustID,
CASE WHEN (C1.MatchCustID <> c2.CustID)
OR (c1.CustID < c1.MatchCustID) THEN c1.CustID
ELSE c1.MatchCustID END AS GroupID
FROM #chaintable C1 JOIN #chaintable C2
ON c1.CustID = c2.MatchCustID
UNION
SELECT c1.CustID, c1.MatchCustID,
c1.MatchCustID AS GroupID
FROM #chaintable C1 JOIN #chaintable C2
ON c2.CustID = c1.MatchCustID AND C1.CustID<>C2.MatchCustID
答案 1 :(得分:0)
首先,在向表中添加行时尝试坚持标准。虽然UNION ALL
可能足以处理您的简单行,但对于您提到的大量插入,它似乎相当冗长。但是,为此,请确保将它们视为关系数据集,并避免不必要的步骤。
此外,CARTESIAN JOIN
是旧的SQL语法,今天的OUTER
和INNER JOIN
更加精通,因此这种旧的连接方式只适用于特殊情况。这不是其中之一。
查看您的表格和结果,会发现以下有关您的表格结构的信息:
那么,解决方案可能如下:
Create table #chaintable
(
CustID int, MatchCustID int, FN varchar(10), LN varchar(10)
, PhoneNo, Email varchar(50), dtAppointment int
)
INSERT INTO #chaintable
VALUES (1,2,'Global','Chain',123,'',1)
, (2,3,'Global','Chain',123,'a@a.com',2)
, (3,2,'Global','Chain',567,'a@a.com',3)
, (4,5,'Global1','Chain1',123,'a@a.com',1)
, (5,4,'Global1','Chain1',123,'a@a.com',2)
SELECT CustID
,MatchCustID
,dtAppointment
, FN
, LN
, DENSE_RANK() OVER (ORDER BY FN + LN DESC ) AS GroupID
FROM #chaintable
Resuls:
CustID MatchCustID dtAppointment FN LN GroupID
1 2 1 Global Chain 1
2 3 2 Global Chain 1
3 2 3 Global Chain 1
4 5 1 Global1 Chain1 2
5 4 2 Global1 Chain1 2
这里唯一的问题是如何使用唯一ID。在此示例中,由于我没有唯一标识事件链的值,因此我使用FN + LN来恢复订单。
这有几个好处:
Cartesian JOIN
。 GROUPID
决赛桌中每个小组的内容始终相同。DECLARE @GROUPID = (SELECT MAX(GROUPID) FROM <SourceTable> )
然而,这也有缺点:
实施例
SELECT FN + LN FROM #chaintable A
WHERE NOT EXISTS (SELECT 1
FROM #chaintable
WHERE A.FN = FN
AND A.LN = LN)
在运行insert语句之前添加我们之前在insert语句中检查的前置值:
DECLARE @GROUPID = (SELECT ISNULL(MAX(GROUPID), 0) FROM <SourceTable> )
INSERT INTO FINAL_TABLE (CustID, MatchCustID, FN, LN, PhoneNo, Email, dtAppointment)
SELECT CustID
, MatchCustID
, FN
, LN
, PhoneNo
, Email
, dtAppointment
, @GROUPID + DENSE_RANK() OVER (ORDER BY FN + LN DESC ) AS GroupID
FROM #chaintable_sub
这将始终导致下一个GROUPID的数量大于之前的条目。
最后,我建议您按原样处理这些数据:Dirty Data
。你必须对它进行ETL
转换,特别是因为你有一个带有复合ID密钥的持久密钥......所以基本上是一个FACT表。