Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL INSERT INTO SELECT and Return the SELECT data to Create Row View Counts

Tags:

sql

php

mysql

So I'm creating a system that will be pulling 50-150 records at a time from a table and display them to the user, and I'm trying to keep a view count for each record.

I figured the most efficient way would be to create a MEMORY table that I use an INSERT INTO to pull the IDs of the rows into and then have a cron function that runs regularly to aggregate the view ID counts and clears out the memory table, updating the original one with the latest view counts. This avoids constantly updating the table that'll likely be getting accessed the most, so I'm not locking 150 rows at a time with each query(or the whole table if I'm using MyISAM).

Basically, the method explained here.

However, I would of course like to do this at the same time as I pull the records information for viewing, and I'd like to avoid running a second, separate query just to get the same set of data for its counts.

Is there any way to SELECT a dataset, return that dataset, and simultaneously insert a single column from that dataset into another table?

It looks like PostgreSQL might have something similar to what I want with the RETURNING keyword, but I'm using MySQL.

like image 479
Ecksters Avatar asked Aug 29 '15 00:08

Ecksters


People also ask

How do I get row count in SQL SELECT query?

To counts all of the rows in a table, whether they contain NULL values or not, use COUNT(*). That form of the COUNT() function basically returns the number of rows in a result set returned by a SELECT statement.

Can we insert data using views?

You can insert data through a single-table view if you have the Insert privilege on the view. To do this, the defining SELECT statement can select from only one table, and it cannot contain any of the following components: DISTINCT keyword. GROUP BY clause.

How do I insert data into a specific row in SQL?

To insert a row into a table, you need to specify three things: First, the table, which you want to insert a new row, in the INSERT INTO clause. Second, a comma-separated list of columns in the table surrounded by parentheses. Third, a comma-separated list of values surrounded by parentheses in the VALUES clause.

What is the difference between insert into to SELECT?

INSERT INTO SELECT statement in SQL Server is used to copy data from the source table and insert it into the destination table. The SELECT INTO statement in SQL Server is used to copy data from one (source) table to a new table. INSERT INTO SELECT requires the destination table to be pre-defined.


2 Answers

First of all, I would not add a counter column to the Main table. I would create a separate Audit table that would hold ID of the item from the Main table plus at least timestamp when that ID was requested. In essence, Audit table would store a history of requests. In this approach you can easily generate much more interesting reports. You can always calculate grand totals per item and also you can calculate summaries by day, week, month, etc per item or across all items. Depending on the volume of data you can periodically delete Audit entries older than some threshold (a month, a year, etc).

Also, you can easily store more information in Audit table as needed, for example, user ID to calculate stats per user.

To populate Audit table "automatically" I would create a stored procedure. The client code would call this stored procedure instead of performing the original SELECT. Stored procedure would return exactly the same result as original SELECT does, but would also add necessary details to the Audit table transparently to the client code.

So, let's assume that Audit table looks like this:

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

and your main SELECT looks like this:

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

To perform both INSERT and SELECT in one statement in SQL Server I'd use OUTPUT clause, in Postgres - RETURNING clause, in MySQL - ??? I don't think it has anything like this. So, MySQL procedure would have several separate statements.

MySQL

At first do your SELECT and insert results into a temporary (possibly memory) table. Then copy item IDs from temporary table into Audit table. Then SELECT from temporary table to return result to the client.

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 (just to tease you. this single statement does both INSERT and SELECT)

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, ...
;

You can leave Audit table as it is, or you can set up cron to summarize it periodically. It really depends on the volume of data. In our system we store individual rows for a week, plus we summarize stats per hour and keep it for 6 weeks, plus we keep daily summary for 18 months. But, important part, all these summaries are separate Audit tables, we don't keep auditing information in the Main table, so we don't need to update it.

Joe Celko explained it very well in SQL Style Habits: Attack of the Skeuomorphs:

Now go to any SQL Forum text search the postings. You will find thousands of postings with DDL that include columns named createdby, createddate, modifiedby and modifieddate with that particular meta data on the end of the row declaration. It is the old mag tape header label written in a new language! Deja Vu!

The header records appeared only once on a tape. But these meta data values appear over and over on every row in the table. One of the main reasons for using databases (not just SQL) was to remove redundancy from the data; this just adds more redundancy. But now think about what happens to the audit trail when a row is deleted? What happens to the audit trail when a row is updated? The trail is destroyed. The audit data should be separated from the schema. Would you put the log file on the same disk drive as the database? Would an accountant let the same person approve and receive a payment?

like image 174
Vladimir Baranov Avatar answered Oct 27 '22 18:10

Vladimir Baranov


You're kind of asking if MySQL supports a SELECT trigger. It doesn't. You'll need to do this as two queries, however you can stick those inside a stored procedure - then you can pass in the range you're fetching, have it both return the results AND do the INSERT into the other table.

Updated answer with skeleton example for stored procedure:

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 ;
like image 22
Jon Marnock Avatar answered Oct 27 '22 18:10

Jon Marnock