我有兩張表...一張用于注冊用戶,一張用于簽入用戶。用戶將始終在注冊表中具有單個條目,但用戶可能在簽入表中具有 0 個或多個條目。對于抽獎選擇器,我撰寫了一個查詢,該查詢從注冊表中選擇 1 個條目,然后從簽入表中選擇 1 個條目 - 只要存盤抽獎的第三個表中不存在該用戶 ID,每個子查詢都會選擇一個隨機條目贏家。回傳兩個條目后,它隨機選擇兩個回傳條目之一作為獲勝者。
但是,我相信應該有一種更有效的方式來撰寫這個,所以它只選擇一個條目......而不是選擇兩個條目然后選擇兩個條目中的一個。
我花了很長時間才弄清楚如何正確撰寫以下查詢,因為我根本不精通 mysql。查詢作業并且似乎有效地作業,但我相信應該有更好的撰寫方式,也可以合并查詢代碼的數量。
希望這里有人可以提供幫助或建議。
表注:clubusers/clubHistory 有多個重疊列,但表不一樣:
register = clubUsers
checkins = clubHistory
winners = clubRaffleWinners
SELECT * FROM (
(SELECT ch.user_ID,ch.clID FROM clubHistory AS ch
LEFT OUTER JOIN clubRaffleWinners AS cr1 ON
ch.user_ID=cr1.user_ID
AND cr1.cID=1157
AND cr1.rafID=18
AND cr1.crID=1001
AND cr1.ceID=1167
AND cr1.chDate1='2022-06-04'
WHERE
ch.cID=1157
AND ch.crID=1001
AND ch.ceID=1167
AND ch.chDate='2022-06-04'
AND cr1.user_ID IS NULL
GROUP BY ch.user_ID ORDER BY RAND() LIMIT 1
)
UNION
(SELECT cu.user_ID,cu.clID FROM clubUsers AS cu
LEFT OUTER JOIN clubRaffleWinners AS cr2 ON
cu.user_ID=cr2.user_ID
AND cr2.cID=1157
AND cr2.rafID=18
AND cr2.crID=1001
AND cr2.ceID=1167
AND cr2.chDate1='2022-06-04'
WHERE
cu.cID=1157
AND cu.crID=1001
AND cu.ceID=1167
AND cu.calDate<='2022-06-04'
AND cr2.user_ID IS NULL
GROUP BY cu.user_ID ORDER BY RAND() LIMIT 1
)
) AS foo order by RAND() LIMIT 1 ;
更新:
正如@JettoMartinez 在下面指出的那樣,我當前的查詢實際上可以從每個表中隨機回傳相同的用戶,因此最終回傳的條目將只是相同的用戶。我沒有意識到這一點只是為了讓上述查詢起作用。因此,我最初的 OP 要求進行更優化的查詢,只需從兩個表中選擇一個隨機條目(該用戶尚未在獲勝者表中),還有另一個原因是適用的。
uj5u.com熱心網友回復:
我可以想到兩種方法(請注意,由于我不完全理解表格,因此我沒有使用您在JOIN陳述句中使用的所有條件,這意味著它可能需要更多作業):
使用獨占子查詢:
SELECT
cu.user_ID,
cu.clID,
ch.cID
FROM
clubUsers cu
LEFT JOIN clubHistory ch ON ch.user_ID = cu.user_ID
WHERE user_ID NOT IN (
SELECT
user_ID
FROM
clubRaffleWinners
WHERE
-- other conditions
)
ORDER BY RAND() LIMIT 1;
按照您的要求使用 a LEFT "OUTER" JOIN:
SELECT
cu.user_ID,
cu.clID,
ch.cID -- Or any relevant field from clubHistory, really
FROM
clubUsers cu
LEFT JOIN clubHistory ch ON ch.user_ID = cu.user_ID
LEFT JOIN clubRaffleWinners cr ON cr.user_ID = cu.user_ID
AND ... -- other conditions to ensure uniqueness
AND ... -- that could also be in the WHERE part
WHERE
cr.user_ID IS NULL -- this will filter out the INNER part of the JOIN
ORDER BY RAND() LIMIT 1;
我沒有資料集來正確測驗這個查詢,所以請把它們當作一個概念。我也沒有詢問,clubHistory因為我真的不明白這樣做的意義。插值clubRaggleWinners對clubUsers我來說似乎足夠了。
編輯
由于user_IDinclubHistory與抽獎活動相關,因此我在其中添加了 aLEFT JOIN并在陳述句中從所述表中添加了一個欄位SELECT,以便user_id每個條目重復一次 inclubHistory加上 的行clubUsers,這意味著每個用戶都有1 number of entries / number of users number of entries - number of winners機會獲勝。
這個邏輯也可以應用于帶有子查詢的第一個查詢,如果添加的欄位需要輸出,則可以將查詢包裝在 CTE 或子查詢中。
uj5u.com熱心網友回復:
根據您的描述,我想確保我理解。
每個注冊人都有資格參加 1 次。
但是,每次他們簽入時,他們每次簽入都會獲得 1 個條目。因此,對于已注冊但從未簽入的人,他們會獲得 1 個條目。但是,如果有人注冊并簽到 3 次,他們總共會得到他們簽到的 3 次,而僅僅注冊了 4 次。
無論誰有可能,您都想排除所有已經在抽獎中獲勝的人。
你應該能夠從下面得到結果。由于這些列似乎對 cID、crID、ceID 和日期進行了相同的過濾,因此我擁有基于注冊的 clubUsers 的主要 FROM。
從那時起,左加入 clubHistory 將允許該人的 ID 僅回傳一次(如果僅注冊),或者根據示例中檢查的時間多次回傳。
從給定的用戶,我也直接以相同的標準左連接到抽獎中獎歷史。如果它與俱樂部歷史加入的標準相同,并且與抽獎的標準相同(除了rafID = 18),似乎表明正在抽獎的特定抽獎,如果找到此人,則排除最終 WHERE 帳戶如果它是單個條目,或通過 IS NULL 測驗的多個條目。
該查詢將回傳所有單個或多個條目,這些條目尚未按 RAND() 限定符的順序獲勝,并應用單個 LIMIT 1 以獲得最終獲勝者。我不知道當你只關心誰贏了,而不考慮是否是俱樂部歷史條目時,你為什么需要看似俱樂部 ID 的東西。
SELECT
cu.user_ID
FROM
clubUsers AS cu
LEFT JOIN clubHistory ch
on cu.user_ID = ch.user_ID
AND cu.cID = ch.cID
AND cu.crID = ch.crID
AND cu.ceID = ch.ceID
AND ch.chDate = '2022-06-04'
LEFT JOIN clubRaffleWinners AS crw
ON cu.user_ID = crw.user_ID
AND cu.cID = crw.cID
AND cu.crID = crw.crID
AND cu.ceID = crw.ceID
AND crw.chDate1 = '2022-06-04'
AND crw.rafID = 18
WHERE
cu.cID = 1157
AND cu.crID = 1001
AND cu.ceID = 1167
AND cu.calDate <= '2022-06-04'
AND crw.user_id IS NULL
order by
RAND()
LIMIT 1
出于性能目的,我將確保以下索引
table index
clubUsers ( cid, crID, ceID, calDate, user_id )
clubHistory ( user_id, cID, crID, ceID, chDate )
clubRaffleWinners ( user_id, cID, crID, ceID, chDate1, rafID )
uj5u.com熱心網友回復:
(只是一個評論,但需要格式化。)
我會首先嘗試將這 4 個值放在一個表中,而不是在 3 個表中重復:
cu.cID=1157
AND cu.crID=1001
AND cu.ceID=1167
AND cu.calDate<='2022-06-04'
請提供SHOW CREATE TABLE每張桌子;然后我可以評估推薦的索引是否有意義。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/497108.html
