早上好。我在Responsys Interact工作,這是一個基於Oracle的電子郵件活動管理類型SAAS產品。我正在創建一個查詢,以基本篩選旨在針對我們的主電子郵件聯繫人列表的特定子集的電子郵件廣告系列的目標列表。下面是我創建了幾個星期前,似乎工作查詢:SQL查詢似乎適用於'AND T1.email_address_ IN(subquery)',但爲'AND T1.email_address_ NOT IN(子查詢)'返回0行'
/*
Table Symbolic Name
CONTACTS_LIST $A$
Engaged $B$
TRANSACTIONS_RAW $C$
TRANSACTION_LINES_RAW $D$
-- A Responsys Filter (Engaged) will return only an RIID_, nothing else, according to John @ Responsys....so,....let's join on that to contact list...
*/
SELECT
DISTINCT $A$.EMAIL_ADDRESS_,
$A$.RIID_,
$A$.FIRST_NAME,
$A$.LAST_NAME,
$A$.EMAIL_PERMISSION_STATUS_
FROM
$A$
JOIN $B$ ON $B$.RIID_ = $A$.RIID_
LEFT JOIN $C$ ON $C$.EMAIL_ADDRESS_ = $A$.EMAIL_ADDRESS_
LEFT JOIN $D$ ON $D$.TRANSACTION_ID = $C$.TRANSACTION_ID
WHERE
$A$.EMAIL_DOMAIN_ NOT IN ('none.com', 'noemail.com', 'mailinator.com', 'nomail.com') AND
/* don't include hp customers */
$A$.HP_PLAN_START_DATE IS NULL AND
$A$.EMAIL_ADDRESS_ NOT IN
(
SELECT
$C$.EMAIL_ADDRESS_
FROM
$C$
JOIN $D$ ON $D$.TRANSACTION_ID = $C$.TRANSACTION_ID
WHERE
/* Get only purchase transactions for certain item_id's/SKU's */
($D$.ITEM_FAMILY_ID IN (3,4,5,8,14,15) OR $D$.ITEM_ID IN (704,769,1893,2808,3013)) AND
/* .... within last 60 days (i.e. 2 months) */
$A$.TRANDATE > ADD_MONTHS(CURRENT_TIMESTAMP, -2)
)
;
這似乎是工作,因爲如果我不運行子查詢的查詢,我們得到720K行;如果我加回'AND NOT IN ...'子查詢,我們會得到大約700K行,根據我的用戶瞭解她的數據,這看起來是正確的。我(應該)用NOT IN子查詢處理的是篩選出客戶在過去60天內向我們購買了某些物品的任何電子郵件地址。
所以,現在我需要添加另一個約束。我們仍然不希望在過去60天內進行某些購買的客戶如上所述,但是現在我們也想要排除購買了其他特定項目的客戶,但現在在過去的12個月內。所以,我想我會添加另一個子查詢,如下所示。現在,這已經推出了幾個問題:
- 性能 - 查詢,歷時幾分鐘之前運行,現在需要相當幾分鐘運行 - 事實上,它似乎超時....
- 所以,我想知道是否有一個問題有兩個子查詢,但在我考慮替代它之前,我決定通過臨時刪除第一個子查詢來測試我的新子查詢,這樣我只有一個類似於上面的子查詢,但新項目= 11,並在過去12個月的邏輯。這樣,查詢在幾分鐘後終於返回,但是零行。
- 試圖找出原因,我試圖簡單地將AND NOT IN(子查詢)更改爲AND IN(子查詢),並且工作正常,因爲它按照預期返回了幾千行。
- 那麼,爲什麼會使用AND IN(子查詢)「工作」時,相同的SQL,但完全相同的SQL簡單地改爲AND NOT IN(子查詢)返回零行,而不是我所期望的那將是我的700 thousdand加上行,少於幾千個子查詢結果封裝的?
- 此外,什麼是最好的,最高效的方式來完成我想要做的事情,這是通過在一個日期範圍內進行的一些購買過濾,以及在不同日期範圍內進行的一些其他購買?
下面是修改的版本:
SELECT
DISTINCT $A$.EMAIL_ADDRESS_,
$A$.RIID_,
$A$.FIRST_NAME,
$A$.LAST_NAME,
$A$.EMAIL_PERMISSION_STATUS_
FROM
$A$
JOIN $B$ ON $B$.RIID_ = $A$.RIID_
LEFT JOIN $C$ ON $C$.EMAIL_ADDRESS_ = $A$.EMAIL_ADDRESS_
LEFT JOIN $D$ ON $D$.TRANSACTION_ID = $C$.TRANSACTION_ID
WHERE
$A$.EMAIL_DOMAIN_ NOT IN ('none.com', 'noemail.com', 'mailinator.com', 'nomail.com') AND
/* don't include hp customers */
$A$.HP_PLAN_START_DATE IS NULL AND
$A$.EMAIL_ADDRESS_ NOT IN
(
SELECT
$C$.EMAIL_ADDRESS_
FROM
$C$
JOIN $D$ ON $D$.TRANSACTION_ID = $C$.TRANSACTION_ID
WHERE
/* Get only purchase transactions for certain item_id's/SKU's */
($D$.ITEM_FAMILY_ID IN (3,4,5,8,14,15) OR $D$.ITEM_ID IN (704,769,1893,2808,3013)) AND
/* .... within last 60 days (i.e. 2 months) */
$C$.TRANDATE > ADD_MONTHS(CURRENT_TIMESTAMP, -2)
)
AND
$A$.EMAIL_ADDRESS_ NOT IN
(
/* get purchase transactions for another type of item within last year */
SELECT
$C$.EMAIL_ADDRESS_
FROM
$C$
JOIN $D$ ON $D$.TRANSACTION_ID = $C$.TRANSACTION_ID
WHERE
$D$.ITEM_FAMILY_ID = 11 AND $C$.TRANDATE > ADD_MONTHS(CURRENT_TIMESTAMP, -12)
)
;
感謝您的任何想法/見解。我可能會錯過或錯誤地記住一些基本的SQL概念 - 如果有的話,請幫助我!此外,Responsys Interact運行在Oracle之上 - 這是一款Oracle產品 - 但我不知道哪種版本/風格。謝謝!
您確實需要查看各種查詢的執行計劃,以查看正在使用的連接順序,索引和過濾器。除非您可以針對基礎表運行查詢,否則這可能會在中間層棘手。我猜''trandate'對於12個月的範圍是不夠有選擇性的,並且'item_id'或'item_family_id'沒有編入索引(你是否在新過濾器中使用了正確的那個?)。但是......你已經離開了加入'$ D $',那麼你需要再次加入子查詢嗎? – 2014-10-30 16:51:05
感謝您的回覆,Alex。在12個月的範圍內,你的關於trandate沒有足夠選擇性的觀點實際上是我第一次想到當我第一次運行修改後的查詢。但瞭解這些數據,我很確定我們在過去的12個月內購買了這個產品。因此,爲了測試這一點,我擺脫了第一個原始子查詢,只關注新子查詢,並將「NOT IN」更改爲「IN」,以確定在過去的12個月內是否真的會讓零客戶購買該項目... – JMoll 2014-10-30 17:03:02
...(繼續上面的評論)這返回了總計2683行,符合預期。但是當我把它從'IN'改回'NOT IN'時,我得到零行。我預計會得到700k減去2683 ....所以這是我沒有看到正確的所有這些...... – JMoll 2014-10-30 17:03:33