2015-08-29 63 views
8

因此,我創建的系統將一次從表中拉出50-150條記錄並將它們顯示給用戶,並且我正在嘗試爲每個記錄保留一個視圖。SQL INSERT INTO SELECT並返回SELECT數據以創建行視圖計數

我想最有效的方法是創建一個MEMORY表,我使用INSERT INTO將行的ID拉入,然後定期運行一個cron函數來聚合視圖ID計數並清除內存表,用最新的查看次數更新原始內存表。這樣可以避免不斷更新可能最多訪問的表,所以我沒有每次查詢150行(或者如果使用MyISAM,整個表)。

基本上,該方法解釋爲here

但是,我當然希望在我將記錄信息用於查看的同時執行此操作,並且我希望避免運行第二個單獨的查詢,以便爲其獲取相同的一組數據計數。

有什麼辦法來選擇一個數據集,返回該數據集,並同時從該數據集插入一列到另一個表?

看起來PostgreSQL可能有類似於我想要的RETURNING關鍵字,但我使用的是MySQL。

+0

INSERT INTO mytable(col1,col2,col3 ...)SELECT col1,col2,col3 FROM anotherTable – bksi

+0

該查詢是否會在最後返回SELECT語句的所有列?我只想將ID列插入到另一個表中,然後返回到同一個SELECT語句的所有其他列。那是INSERT INTO的工作原理嗎? – Ecksters

+2

這是不可能與MySQL。你將不得不使用兩個查詢。 – rjdown

回答

4

首先,我不是一個計數器列到Main表添加。我將創建一個單獨的Audit表,該表將保存來自Main表的項目的ID以及當請求該ID時至少添加時間戳。實質上,Audit表將存儲請求的歷史記錄。在這種方法中,您可以輕鬆生成更多有趣的報告。您可以隨時計算每件商品的總計總額,並且還可以按日期,星期,月份等計算每件商品或所有商品的彙總。根據數據量的不同,您可以定期刪除比某個閾值(一個月,一年等)更早的審計條目。

此外,您可以根據需要輕鬆地在Audit表中存儲更多信息,例如用戶ID來計算每個用戶的統計信息。

要自動填充Audit表我會創建一個存儲過程。客戶端代碼將調用此存儲過程,而不是執行原始的SELECT。存儲過程將返回與原始SELECT完全相同的結果,但也會向客戶端代碼透明地向Audit表添加必要的詳細信息。

所以,讓我們假設Audit表看起來像這樣:

CREATE TABLE AuditTable 
(
    ID int 
    IDENTITY -- SQL Server 
    SERIAL -- Postgres 
    AUTO_INCREMENT -- MySQL 
    NOT NULL, 
    ItemID int NOT NULL, 
    RequestDateTime datetime NOT NULL 
) 

和你的主SELECT看起來是這樣的:

SELECT ItemID, Col1, Col2, ... 
FROM MainTable 
WHERE <complex criteria> 

要在一個語句在SQL Server中我同時執行INSERTSELECT 'd使用OUTPUT子句,在Postgres - RETURNING子句中,在MySQL中?我不認爲它有這樣的事情。所以,MySQL程序會有幾個單獨的語句。

MySQL的

起初做你SELECT並插入結果爲temporary(可能是內存)表。然後將臨時表中的物料ID複製到Audit表中。然後從臨時表中將SELECT返回給客戶端。

CREATE TEMPORARY TABLE TempTable 
(
    ItemID int NOT NULL, 
    Col1 ..., 
    Col2 ..., 
    ... 
) 
ENGINE = MEMORY 
SELECT ItemID, Col1, Col2, ... 
FROM MainTable 
WHERE <complex criteria> 
; 

INSERT INTO AuditTable (ItemID, RequestDateTime) 
SELECT ItemID, NOW() 
FROM TempTable; 

SELECT ItemID, Col1, Col2, ... 
FROM TempTable 
ORDER BY ...; 

SQL服務器(只是爲了逗你。這一個說法確實都INSERTSELECT

MERGE INTO AuditTable 
USING 
(
    SELECT ItemID, Col1, Col2, ... 
    FROM MainTable 
    WHERE <complex criteria> 
) AS Src 
ON 1 = 0 
WHEN NOT MATCHED BY TARGET THEN 
INSERT 
    (ItemID, RequestDateTime) 
VALUES 
    (Src.ItemID, GETDATE()) 
OUTPUT 
    Src.ItemID, Src.Col1, Src.Col2, ... 
; 

你可以離開Audit表作爲它,或者你可以設置cron來概括它定期。這實際上取決於數據量。在我們的系統中,我們將單個行存儲一週,並且我們每小時彙總統計數據並保留6周,並且我們每日彙總18個月。但是,重要的是,所有這些總結都是獨立的Audit表,我們不保留Main表中的審計信息,所以我們不需要更新它。

喬·塞科在SQL Style Habits: Attack of the Skeuomorphs解釋非常好:

現在去任何SQL論壇文本搜索的帖子。您會發現有數千個包含DDL的帖子,其中包括名爲createdby, createddate,modifiedbymodifieddate的列,並且在行聲明結尾處包含該特定的 元數據。這是舊的磁帶 標題標籤用新的語言寫的! Deja Vu!

標題記錄只在磁帶上出現一次。但是,這些元數據 值在表格中的每一行都會反覆出現。使用數據庫(不僅僅是SQL)的主要原因之一是從數據中刪除冗餘 ;這只是增加了更多的冗餘。但現在想想 行被刪除時審計跟蹤會發生什麼?當行更新時,審計線索 會發生什麼變化?小道被毀壞。審計數據應與模式分離。你會把日誌 文件放在與數據庫相同的磁盤驅動器上嗎?會計師是否讓 同一個人批准並收到付款?

+0

好的答案! 我發現額外信息被組織到更多表中的想法非常有趣,很高興你看起來超出了原始參數 我會等待更長的時間,看看是否有人有任何他們認爲值得一提的答案,但這很可能會帶來賞金:) – Ecksters

+0

不客氣。我受到了Joe Celko的這篇文章(https://www.simple-talk.com/opinion/opinion-pieces/sql-style-habits-attack-of-the-skeuomorphs/)的啓發。我將在答案中添加相關的引用。 –

+0

這是一個很好的答案,但我會在審計數據中包含用戶身份(即請求者)。雖然在上面的答案中提到了這個問題,但我強烈建議你從第1天開始做這件事(不然,你不能回溯到找出誰要求提供信息)。 –

3

你有點問MySQL是否支持SELECT觸發器。它沒有。您需要將其作爲兩個查詢來完成,但是您可以將這些查詢粘貼到存儲過程中 - 然後您可以傳入您要提取的範圍,讓它們返回結果並將INSERT插入另一個表中。

更新的答案與存儲過程的骨架例如:

所有的
DELIMITER $$ 
CREATE PROCEDURE `FetchRows`(IN StartID INT, IN EndID INT) 
BEGIN 
    UPDATE Blah SET ViewCount = ViewCount+1 WHERE id >= StartID AND id <= EndID; 
    #^Assumes counts are stored in the same table. If they're in a seperate table, do an INSERT INTO ... ON DUPLICATE KEY UPDATE ViewCount = ViewCount+1 instead. 
    SELECT * FROM Blah WHERE id >= StartID AND id <= EndID; 
END$$ 
DELIMITER ; 
+1

簡潔,基本上就是我可以說的核心反應。 – Ecksters

+0

是的,對不起,我無法回答「哦,是的,有這個小的已知功能,正是你想要的」(令人討厭的是,實際上PostgreSQL中有這樣的東西,我想,「更新...返回」。 http://www.postgresql.org/docs/9.1/interactive/sql-update.html –

+0

哦,是的,我編輯了我的答案,以提供一個示例框架存儲過程,以完成我和弗拉基米爾提出的任務,然後雙重選擇/ update會變成一個'CALL FetchRows(1,7);'或其他任何東西。 –