Scheduled spesific time queries - php

I have a table which is i showed on picture below.
Flight Table
MYSQL TABLE
[Id], [flightCode], [TailId], [DepartureFrom], [DepartureDate],
[ArrivedTo], [ArrivalDate], [Status]
VALUES
[*1], [TK161], [TC-AAS], [DLM], [04.03.2021 15:00], [IST], [04.03.2021
16:02], [2]
I want to run mysql query for update Status from "2" to "3" after reach to ArrivalDate in real system time.
Which method I should to use?

What you really want is to have status be a computed column or query and compute that column on the fly. https://dev.mysql.com/doc/refman/5.7/en/create-table-generated-columns.html doing continuous updates across a database is VERY processor intensive and unnecessary.
so instead of SELECT * FROM TABLE you could do
SELECT *,
CASE WHEN NOW() >= ArrivalDate THEN 3 ELSE 2 END AS `Status`
FROM TABLE
This query will give you the correct status at query time. So the work to compute it only happens when it is needed. I assume that there are other conditions for status but you can nest them into the case or have an outer case for those

Related

Whats better; mysql scheduler or php script and crontab?

I have 1 mysql table where it has thousands of rows. I use this as a transaction history for my users. I also query this table on the same page for a sum of earnings per product. here are my two mysql calls;
$earnperproduct = mysqli_query($con,"SELECT product, SUM(amount) AS totalearn FROM wp_payout_history WHERE user=$userid GROUP BY product");
$result = mysqli_query($con,"SELECT * FROM wp_payout_history WHERE user=$userid ORDER BY date DESC");
my fear is that as the table grows, the $earnperproduct call will become too intensive and slow down page loading. Therefore instead of doing a sum command every time the page loads, i think it would be easier to update a summary (example wp_summary_table) whenever wp_payout_history is changed to replace past values with new SUM(AMOUNT)values per user and product; and thus query something like this;
$earnperproduct = mysqli_query($con,"SELECT * FROM wp_payout_summary_table WHERE user=$userid ORDER BY product DESC");
TL;DR
What is the best method to go about updating a table using the $earnedperproduct style call? would I be better using mysql event scheduler or a php script with a crontab? Is there any tutorials that can help me create either option for my needs?
Both the control mechanisms you mention use time as the trigger for an action. But your description says that you really want to trigger an action when the data changes. And in a relational database the best way to trigger an action when data is changed is with a ....trigger. Which makes your question a duplicate of this.
Arguably it may be more efficient to snapshot the transactions, then something like....
[INSERT INTO summary_table (user, total_amount, last_id) ]
SELECT
user, SUM(amount), MAX(id)
FROM (
SELECT a.user, a.total_amount AS amount, a.last_id
FROM summary_table a
WHERE a.user=$user_id
AND last_id=(SELECT MAX(b.last_id)
FROM summary_table b
WHERE b.user=$user_id)
UNION
SELECT h.user, h.amount, h.id
FROM wp_payout_history h
WHERE h.user=$user_id
AND h.id>(SELECT MAX(c.last_id)
FROM summary_table c
WHERE c.user=$user_id)
) ilv
GROUP BY user;
...then it doesn't really matter what you use to refresh the history - the query will always give you an up to date response. If you go down this route then add a dummy integer column in the summary table and add 0 as unaggregatedrows to the second SELECT and SUM(1) to the 4th SELECT to work out when it will be most efficient to update the summary table.

Get Last Payment From A User in SQL

I have this table
I am trying to get the sum of principal + interest from the last transaction date. Column 4. is the last transaction performed - [No column name] is the transaction date
What I have tried so far:
select sum(h.principal+h.interest) as amt_paid, MAX(h.trx_date)
from Loanhist h WHERE h.ac_no = '$id' and h.trx_type='LP'
GROUP BY principal, interest
The test data generation is for Oracle, but you should easily be able to adapt it. The actual query will work on SQL server. You'll need to use an approach like this if the account can post more than one transaction in a day. Otherwise the 'LIMIT/TOP 1' approaches in the other answers will work fine.
CREATE GLOBAL TEMPORARY TABLE balances
( ac_no CHAR(100),
principal FLOAT,
interest FLOAT,
tranDate DATE
)
ON COMMIT PRESERVE ROWS;
INSERT INTO balances VALUES (1,123.123,.456,DATE '2017-01-01');
INSERT INTO balances VALUES (1,100,.456,DATE '2017-01-02');
INSERT INTO balances VALUES (1,200,.1,DATE '2017-01-02');
INSERT INTO balances VALUES (2,200,.1,DATE '2017-01-02');
INSERT INTO balances VALUES (2,300,.1,DATE '2017-01-02');
SELECT SUM
( CASE WHEN tranDate = max_tran_date
THEN principal + interest
ELSE 0
END
) AS tranSum
FROM (SELECT sub.*,
MAX(tranDate) OVER() AS max_tran_date
FROM balances sub
) BAL;
Your question is not really clear. But if you just want to get the last transaction performed by the user, the best thing to do will be to rely on IDs instead of dates.
SELECT TOP 1 * FROM Loanhist h WHERE h.trx_type='LP' ORDER BY h.ac_no DESC
try to use LIMIT keyword.For Example, Select * from table name where condition LIMIT 1.It will return first row
Try this:
SELECT TOP 1 sum(h.principal+h.interest) as amt_paid, h.trx_date
FROM Loanhist h WHERE h.ac_no = '$id' AND h.trx_type='LP'
ORDER BY h.ac_no DESC;

MYSQL Select MAX COUNT in DATE RANGE

I was looking to a lot of examples, but I couldn't find an answer. What I need to do is check if there is free space for new orders. In one time I can have maximum 5 customers. Order duration is not limited, customers just selects date-time range in picker.
For example my DB records are:
`id` `start` `end`
`1` `2017/06/10 10:00` `2017/06/15 08:00`
`2` `2017/06/11 10:00` `2017/06/16 08:00`
`3` `2017/06/12 10:00` `2017/06/17 08:00`
`4` `2017/06/13 10:00` `2017/06/18 08:00`
`5` `2017/06/14 10:00` `2017/06/19 08:00`
Customer want to reserve from 2017/06/11 08:00 until 2017/06/15 12:00, but I can't let him because this period coincides with more than 5 records in my DB. How can I do it in mysql select query?
Try:
Select count(*)>5 as vacant
From orders
Where (input_start < end and input_start>start ) or
(Input_end > start and input start<start)
Where input are your search values
You can do count the number of matching records using logic like this:
select count(*)
from t
where $start < end and $end > start;
This counts the number of records that overlap with ($start, $end). You can put the comparison to "5" in your application. (Or just use select count(*) < 5.
Note: You should be passing in the values as parameters.
Try likethis :
select id from table where id not in
/*the query below will get the wrong result */
(select id from table where yourstartdate between start and end or yourenddate between start and end);
There are many, many solutions. You've tagged this as PHP so there is scope to do this in the application logic as well as one the storage.
You could separate the 5 slots across attributes (which are constrained by definition) rather than across rows (which are not constrained). Then let the application decide if the transaction is viable (although you could map this to a single slot-per-record representation using views and triggers).
While as others have suggested, you could count the number of slots currently booked to determine if there is availability (but this would need be done at least twice and you need to avoid race conditions). For preference this would be implemented as a before-insert trigger.
An alternative approach or enhancement to this would be to add a primary/unique key to the table containing the reservations including an enumerated column (with 5 possible values and a non-null constraint) making it impossible to inject more than 5 records for one slot.
But this is all about preventing a state which is considered inconsistent. Your first line of defence is presenting the user with options which are unlikely to cause such conflicts. The obvious case is not to present slots which already have 5 bookings.

SQL select all files where a value in table A is the same as in table B (same database)

I'm building a sales system for a company, but I'm stuck with the following issue.
Every day I load .XML productfeed into a database called items. The rows in the productfeed are never in the same order, so sometimes the row with Referentie = 380083 is at the very top, and the other day that very same row is at the very bottum.
I also have to get all the instock value, but when I run the following query
SELECT `instock` FROM SomeTable WHERE `id` > 0
I get all values, but not in the same order as in the other table.
So I have to get the instock value of all rows where referentie in table A is the same as it is in table B.
I already have this query:
select * from `16-11-23 wed 09:37` where `referentie` LIKE '4210310AS'
and this query does the right job, but I have like 500 rows in the table.
So I need to find a way to automate the: LIKE '4210310AS' bit, so it selects all 500 values in one go.
Can somebody tell me how that can be done?
I'm not even sure I understand your problem...
Don't take this personally, but you seem to be concerned/confused by the ordering of the data in the tables which suggests to me your understanding of relational databases and SQL is lacking. I suggest you brush up on the basics.
Can't you just use the following query?
SELECT a.referentie
, b.instock
FROM tableA a
, tableB b
WHERE b.referentie = a.referentie

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

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

Categories