I do 99% php/javascript work so getting my head around SQL is always a struggle, sorry if I seem dense.
So I've got a table that looks something like this:
post_id | meta_key | meta_value
--------------------------------------
1 | requirement | 3
2 | requirement | 1
3 | requirement | 1
1 | adder_id | 3
1 | adder_id | 2
1 | adder_id | 69
2 | adder_id | 42
2 | complete_date| 20190309040445
On an insert trigger I want to run a query that will for each post_id that dose not have a "complete date":
INSERT INTO this_table ( post_id, meta_key, meta_value )
VALUES
( var_post_id, 'complete_date',NOW());
But only if
SELECT COUNT(*)
FROM this_table
WHERE post_id = var_post_id
AND meta_key = 'adder_id'
is >=
SELECT meta_value
FROM this_table
WHERE post_id = var_post_id
AND meta_key = 'requirement'
So post_id two is the intended effect (requires 1, has 1, got a complete date) while post_id one is an example of something that should trigger an update (requires 3, has 3, waiting on a complete date) and post_id three should be ignored (requires 1, has 0, just ignore).
Now this would be easy enough with an if/else and 2 or three variables but is this even possible with a mySQL statement? Is there an easier way of going about it within mySQL or should I try and find a PHP solution instead?
Thanks for any assistance, I don't usually ask for help here unless I'm properly stumped and this one really has me going.
Best Answer
Start with getting all the required counts:
Then derive another row set, which is the actual counts per
post_id
:Now join the two sets as derived tables and filter the results on
actual_count >= required_count
to get thepost_id
s fulfilling the requirement:You can simplify the last query by joining the
act
set directly tothis_table
and slightly modifying theWHERE
condition by referencingmeta_value
instead ofrequired_count
:We are almost there. Now you need to filter out the
post_id
s that already have acompleted_date
. This is called an anti-join (a self-anti-join in this specific case, as you excluding rows from a table based on a condition involving the same table). There are different methods of implementing an anti-join. Last I checked, the method that worked in MySQL better than other methods was the one involving a left join and anIS NULL
check. This is how it would be implemented in your case:An outer join could be basically described as an attempt to join. So by using a
LEFT JOIN
you are attempting to join eachreq
row (which is all therequirement
rows) to eachexc
row (all thecompleted_date
rows) onpost_id
. TheIS NULL
check in theWHERE
clause is saying that actually you want the rows where there was no match.Now that you have all the right
post_id
values, it only remains to add'complete_date', NOW()
to the SELECT list, and you are ready to insert new rows into the table: