【问题标题】:SQL INSERT INTO SELECT and Return the SELECT data to Create Row View CountsSQL INSERT INTO SELECT 并返回 SELECT 数据以创建行视图计数
【发布时间】:2015-08-29 00:24:00
【问题描述】:

因此,我正在创建一个系统,该系统将一次从表中提取 50-150 条记录并将它们显示给用户,并且我正在尝试为每条记录保留查看次数。

我认为最有效的方法是创建一个 MEMORY 表,我使用 INSERT INTO 将行的 ID 拉入,然后有一个定期运行的 cron 函数来聚合视图 ID 计数并清除内存表,用最新的视图计数更新原始表。这避免了不断更新可能被访问最多的表,因此我不会在每个查询中一次锁定 150 行(或者如果我使用 MyISAM,则锁定整个表)。

基本上,方法解释here

但是,我当然希望在提取记录信息以供查看的同时执行此操作,并且我希望避免运行第二个单独的查询,只是为了获取相同的数据集进行计数.

有什么方法可以选择一个数据集,返回该数据集,同时将该数据集中的一列插入另一个表?

看起来 PostgreSQL 可能有一些类似于我想要的 RETURNING 关键字的东西,但我使用的是 MySQL。

【问题讨论】:

  • INSERT INTO mytable (col1, col2,col3...) SELECT col1, col2, col3 FROM anotherTable
  • 该查询最终会返回 SELECT 语句中的所有列吗?我只想将 ID 列插入到另一个表中,然后将同一 SELECT 语句的所有其他列返回给 PHP。这就是 INSERT INTO 的工作原理吗?
  • 使用 MySQL 是不可能的。您必须使用两个查询。

标签: php mysql sql


【解决方案1】:

首先,我不会在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,我会在 Postgres 中使用 OUTPUT 子句 - 在 MySQL 中使用 RETURNING 子句 - ???我不认为它有这样的东西。因此,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 Server(只是为了取笑你。这条语句同时执行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 表中保留审计信息,因此我们不需要更新它。

Joe Celko 在SQL Style Habits: Attack of the Skeuomorphs 中解释得很好:

现在去任何 SQL 论坛文本搜索帖子。你会找到 包含名为 createdby 的列的数以千计的 DDL 帖子, createddatemodifiedbymodifieddate 行声明末尾的元数据。这是旧的磁带 用新语言编写的标题标签!似曾相识!

标题记录在磁带上只出现一次。但是这些元数据 值在表中的每一行上一遍又一遍地出现。主要之一 使用数据库(不仅仅是 SQL)的原因是为了消除冗余 从数据中;这只会增加更多冗余。但现在想想 当一行被删除时,审计跟踪会发生什么?会发生什么 更新行时的审计跟踪?小径被毁。这 审计数据应该与模式分开。你能把日志 与数据库在同一磁盘驱动器上的文件?会计会让 同一个人批准和接收付款?

【讨论】:

  • 很好的答案!我发现将额外信息组织成更多表格的想法非常有趣,很高兴您看到的超出了原始参数。我会等待更长的时间,看看是否有人有任何他们认为值得一提的答案,但这很可能会得到赏金:)
  • 不客气。我受到了 Joe Celko 的 article 的启发。我将在答案中添加相关引用。
  • 这是一个很好的答案,但我会将用户身份(即请求者)包含在审计数据中。虽然在上面的答案正文中提到了这一点,但我强烈建议您从第一天开始执行此操作(注意,您无法及时回过头来弄清楚是谁要求提供这些信息)。
【解决方案2】:

您是在问 MySQL 是否支持 SELECT 触发器。它没有。您需要将其作为两个查询来执行,但是您可以将它们粘贴在存储过程中 - 然后您可以传入您正在获取的范围,让它返回结果并将插入到另一个表中。

用存储过程的骨架示例更新答案:

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 ;

【讨论】:

  • 简洁,据我所知基本上是这里的核心回应。
  • 是的,对不起,我无法回答“哦,是的,有一个鲜为人知的功能可以完全满足您的需求” :( 令人讨厌的是,我认为 PostgreSQL 中实际上有类似的东西,“更新...返回”。postgresql.org/docs/9.1/interactive/sql-update.html
  • 哦,是的,我编辑了我的答案,以提供一个示例骨架存储过程来执行我和弗拉基米尔提议的事情。然后你的双重选择/更新变成CALL FetchRows(1, 7); 或其他。
猜你喜欢
  • 2012-01-23
  • 2014-04-23
  • 2023-02-09
  • 1970-01-01
  • 2015-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多