Updating certain data from one table to another table once a week - mysql

My end goal is to update information from table 1 to table 2 on a certain condition. More specifically, I'd like to update the date from table1 to table2 where the id's match and dates from table2 are NULL.
I want this to happen every Sunday.
Here are the specifics:
** Keep in mind, payee_id and id are the same but in two different tables. **
The table I plan to copy from is called orders, but I only want to select certain data from this table. My query looks like this:
TABLE 1
SELECT movement.payee_id,
min(origin_stop.sched_arrive_early) first_date
FROM orders
LEFT JOIN movement_order ON orders.id = movement_order.order_id
LEFT JOIN movement ON movement.id = movement_order.movement_id
LEFT JOIN stop as origin_stop ON origin_stop.id = movement.origin_stop_id
WHERE orders.status <> 'V'
GROUP BY movement.payee_id
OUTPUT 1
payee_id | first_date
-------------------|-----------------
STRINGID1 | 2013-12-20 15:00:00.000
STRINGID2 | 2013-12-27 13:00:00.000
TABLE 2
SELECT id, initial_date
FROM drs_payee
OUTPUT 2
id | initial_date
-------------------|-----------------
STRINGID1 | NULL
STRINGID2 | NULL
TABLE 2 OUTPUT SHOULD BE:
id | initial_date
-------------------|-----------------
STRINGID1 | 2013-12-20 15:00:00.000
STRINGID2 | 2013-12-27 13:00:00.000
My attempt to solve this:
UPDATE drs_payee a
(SELECT movement.payee_id,
min(origin_stop.sched_arrive_early) carrier_first_shipped_date
FROM orders
LEFT JOIN movement_order ON orders.id = movement_order.order_id
LEFT JOIN movement ON movement.id = movement_order.movement_id
LEFT JOIN stop as origin_stop ON origin_stop.id = movement.origin_stop_id
WHERE orders.status <> 'V'
GROUP BY movement.payee_id) b
ON a.id = b.payee_id
SET a.initial_date = b.first_date
WHERE a.initial_date IS NULL
Not sure if the format of this is correct and if you can even do a SELECT inside an UPDATE like shown above.
I believe I have to have a loop to find id's that match (i.e. where payee_id = id and initial_date is NULL). Would this be created in a stored procedure to loop through id's and create a weekly job schedule or would some type of update query be enough? Please help or point me in some direction with the an update query or stored procedure example using my data if possible.
Thanks in advance everyone!

For scheduled queries the best thing for me is creating events. First you have to select your db, and at the top right you'll see an option in phpmyadmin called "events". You have to turn on the events planner, and to do that you mut be logged in with a super privilege user, in phpMyadmin.
After you do that the query is:
DROP EVENT `dates update` ;
CREATE DEFINER = `your_user_name`#`your_host_name`
EVENT `dates update`
ON SCHEDULE EVERY1 WEEK STARTS '2015-07-29 03:00:00'
ON COMPLETION NOT PRESERVE ENABLE DO
UPDATE movement a
INNER JOIN orders b
ON a.payee_id = b.payee_id
SET a.initial_date = b.first_ship_date
WHERE a.initial_date IS NULL;
It must work.
If you need help about super privilege check this
I hope it works for you.
Caio Ortega

Update table2
inner join table1 on payee_id = id
set initial_date=first_date where initial_date is null
Through SQL server agent we can schedule the query as per our requirement (For example every Sunday )

Related

Retrieve rows that have a first entry in 2014 in MySQL

I want to retrieve all rows from a table that have their first entry on or after 01/01/2014 but no later than 31/12/2014
Example of the table:
OID FK_OID Treatment Trt_DATE
1 100 19304 2011-05-24
2 100 19304 2011-08-01
3 100 19306 2014-03-05
4 200 19305 2012-02-02
5 300 19308 2014-01-20
6 400 19308 2014-06-06
For example. I would like to pull all entries that have STARTED treatment in 2014. So above i would to extract FK_OID's 300 and 400 because their first entry is in 2014, but i would like to omit FK_OID 100 because they have 2 entries prior to 2014.
How do i go about this? I can extract all entries within a date range etc but that brings back all entries for that date and doesn't omit anyone who has an entry prior to the start of the date range. It just returns their first entry in 2014.
For the ones who need to see that i have tried something. See below.
I am not an experienced coder and this is the best i can get because i don't have the knowledge.
SELECT
mod,
(select NHSNum from person p
WHERE
p.oid = t.fk_oid) as 'NHS'
FROM
timeline t
Where trt_date BETWEEN '2014-01-01' AND '2014-12-31'
ORDER BY trt_date ASC
This returns every treatment for 2014 regardless of whether it is the first ever one for that person. I want to omit anyone from this list who has had treatment before 01/01/2014 as well as only return the first treatment per person. For example, this code returns all treatments for all people in 2014. I only want their first one and only if it is their first one ever.
Thanks.
create table aThing
( oid int auto_increment primary key,
fk_oid int not null,
treatment int not null,
trt_date date not null
);
insert aThing (fk_oid,treatment,trt_date) values
(100, 19304, '2011-05-24'),
(100, 19304, '2011-08-01'),
(100, 19306, '2014-03-05'),
(200, 19305, '2012-02-02'),
(300, 19308, '2014-01-20'),
(400, 19308, '2014-06-06');
select fk_oid,dt
from
( select fk_oid,min(trt_date) as dt
from aThing
group by fk_oid
) xDerived
where year(dt)=2014;
+--------+------------+
| fk_oid | dt |
+--------+------------+
| 300 | 2014-01-20 |
| 400 | 2014-06-06 |
+--------+------------+
The inner part, the nested one, become a derived table, and is given a name xDerived. This means that even though it is just a result set, by making it a derived table, it can be referred to by name. So it is not a physical table, but a derived one, or virtual one.
So that derived table is a very simple group by with an aggregate function. It says, for every fk_oid, bring back one row and only 1 row, with its minimum value for trt_date.
So if you have 10 million rows in that table called aThing, but only 17 distinct values for fk_oid, it will return only 17 rows. Each row being the minimum of trt_date for its fk_oid.
So now that that is achieved, the outer wrapper says just show me those two columns (but with a year check). There is a complicated to explain reason why I had to do that, so I will try to do it here.
But I might need a little time to explain it well, so bear with me.
This will be a shortcut way to say it. I had to get the min into an alias, and I only had access to that alias if resolved in a derived table, to cleanse it so to speak, and then access it with an outer wrapper.
An alias of aggregate column, like as dt, is not available (as a pseudo like column name which is what an alias is) ... it is not available in a where clause. But by wrapping it in a derived table name, I cleanse it so to speak, and then I can access it in a where clause.
So I can't access it directly in its own query in the where clause, but when I wrap it in an envelope (a derived table), I can access it on the outside.
I will try better to explain it later, maybe, but I would have to show alternative attempts to gain access to results, and the syntax errors that would result.
There's probably a more elegant solution, but this seems to satisfy the requirement...
SELECT x.*
FROM my_table x
JOIN
( SELECT fk_oid
, MIN(trt_date) min_date
FROM my_table
GROUP
BY fk_oid
HAVING min_date > '2014-01-01'
) a
ON a.fk_oid = x.fk_oid
LEFT
JOIN my_table b
ON b.fk_oid = a.fk_oid
AND b.trt_date > '2014-12-31'
WHERE b.oid IS NULL;
Having a few years a experience with this, i decided to revisit it. The solution i now use regularly is:
SELECT t1.column1, t1.column2
FROM MyTable AS t1
LEFT OUTER JOIN MyTable AS t2
ON t1.fkoid = t2.fkoid
AND (t1.date > t2.date
OR (t1.date = t2.date AND t1.oid > t2.oId))
WHERE t2.fkoid IS NULL and t1.date >= '2014-01-01'

mysql query if there is no record or record.xx != xx trouble with query

I've 3 MYSQL tables.
"villa" table has records for properties.
"villa_type" table has records for property types.
"villa_price" table for daily prices with dates, price, property id and availability columns.
I receive all data with SQL, left join it with villa_type table to receive some additional info about property which works ok, and left join the table with the 3rd table to ask if the property is booked on that date or available.
Query is like this.
SELECT villa.*, villa_type.tip as villatypename
FROM villa
LEFT JOIN villa_type on villa_type.id = villa.type
LEFT JOIN villa_price on villa_price.villaid = villa.id
WHERE villa.lang = 1
AND villa.area = 1980
AND villa.status = 1
AND villa.status2 = 1
-- Problem starts here..............
AND (villa_price.vdate = '2015-01-13' OR villa_price.vdate is null)
AND (
((villa_price.condition != 2) AND (villa_price.condition != 3))
OR (villa_price.condition is null)
)
The problem is: if the villa has a record for 2015-01-13 and its condition is 2 or 3, i correctly don't get that villa listed (which is what i'm trying to do), but if that villa has a record for that same date and the condition is 1, it still doesn't get listed (while it should).
I simply want to check villa_price table to see that villa has a condition of 2 or 3 for the given date and eliminate that villa from result.
Any help or guide will be appreciated. Thanks alot

How to SELECT MySQL 1-to-LAST on 1-to-Many Relationship

I have 2 Tables -- Table 1 is a master file and Table 2 is an activity file.
The relationship is 1-to-Many.
I am producing a report and all I want to return is every master file row joined to only the last activity row for the related master id.
I am unsure on how to request the last activity row. My code below returns every activity row (rightfully so).
Thank you for your help.
SELECT *
FROM master_file AS master
INNER JOIN activity_file AS activity ON activity.id = master.id
ORDER BY master.display_name
The activity file has a column called entry_date. It is a date and time stamp recording every activity. I simply want to select the last entry_date.
For example:
Table 2 - Activity looks like this
ID ACTIVITY ENTRY_DATE
1 Update 2012-08-01 09:00:00
1 Edit 2012-08-01 13:45:15
3 Create 2012-07-15 10:09:52
3 Delete 2012-07-22 23:02:00
3 Add 2012-08-05 04:33:00
4 Edit 2012-08-03 15:12:00
One standard way to solve this is to create an inline view that finds the last entry_date per ID.
SELECT *
FROM master_file AS master
LEFT JOIN activity_file AS activity ON activity.id = master.id
LEFT JOIN (select id , max(entry_date) entry_date
From activity_file
group by id) last_activity
ON activity_file.id = last_activity.id
and activity_file.entry_date= last_activity.entry_date
ORDER BY master.display_name
The one problem with this approach is that you may have more than one record with max(entry_date) for a given id. You'll either need to have your business rules handle this (e.g. simply display more than one record for that case) or you'll need to figure out a tie breaker. The last thing you want is to make it non-deterministic

mysql update with a self referencing query

I have a table of surveys which contains (amongst others) the following columns
survey_id - unique id
user_id - the id of the person the survey relates to
created - datetime
ip_address - of the submission
ip_count - the number of duplicates
Due to a large record set, its impractical to run this query on the fly, so trying to create an update statement which will periodically store a "cached" result in ip_count.
The purpose of the ip_count is to show the number of duplicate ip_address survey submissions have been recieved for the same user_id with a 12 month period (+/- 6months of created date).
Using the following dataset, this is the expected result.
survey_id user_id created ip_address ip_count #counted duplicates survey_id
1 1 01-Jan-12 123.132.123 1 # 2
2 1 01-Apr-12 123.132.123 2 # 1, 3
3 2 01-Jul-12 123.132.123 0 #
4 1 01-Aug-12 123.132.123 3 # 2, 6
6 1 01-Dec-12 123.132.123 1 # 4
This is the closest solution I have come up with so far but this query is failing to take into account the date restriction and struggling to come up with an alternative method.
UPDATE surveys
JOIN(
SELECT ip_address, created, user_id, COUNT(*) AS total
FROM surveys
WHERE surveys.state IN (1, 3) # survey is marked as completed and confirmed
GROUP BY ip_address, user_id
) AS ipCount
ON (
ipCount.ip_address = surveys.ip_address
AND ipCount.user_id = surveys.user_id
AND ipCount.created BETWEEN (surveys.created - INTERVAL 6 MONTH) AND (surveys.created + INTERVAL 6 MONTH)
)
SET surveys.ip_count = ipCount.total - 1 # minus 1 as this query will match on its own id.
WHERE surveys.ip_address IS NOT NULL # ignore surveys where we have no ip_address
Thank you for you help in advance :)
A few (very) minor tweaks to what is shown above. Thank you again!
UPDATE surveys AS s
INNER JOIN (
SELECT x, count(*) c
FROM (
SELECT s1.id AS x, s2.id AS y
FROM surveys AS s1, surveys AS s2
WHERE s1.state IN (1, 3) # completed and verified
AND s1.id != s2.id # dont self join
AND s1.ip_address != "" AND s1.ip_address IS NOT NULL # not interested in blank entries
AND s1.ip_address = s2.ip_address
AND (s2.created BETWEEN (s1.created - INTERVAL 6 MONTH) AND (s1.created + INTERVAL 6 MONTH))
AND s1.user_id = s2.user_id # where completed for the same user
) AS ipCount
GROUP BY x
) n on s.id = n.x
SET s.ip_count = n.c
I don't have your table with me, so its hard for me to form correct sql that definitely works, but I can take a shot at this, and hopefully be able to help you..
First I would need to take the cartesian product of surveys against itself and filter out the rows I don't want
select s1.survey_id x, s2.survey_id y from surveys s1, surveys s2 where s1.survey_id != s2.survey_id and s1.ip_address = s2.ip_address and (s1.created and s2.created fall 6 months within each other)
The output of this should contain every pair of surveys that match (according to your rules) TWICE (once for each id in the 1st position and once for it to be in the 2nd position)
Then we can do a GROUP BY on the output of this to get a table that basically gives me the correct ip_count for each survey_id
(select x, count(*) c from (select s1.survey_id x, s2.survey_id y from surveys s1, surveys s2 where s1.survey_id != s2.survey_id and s1.ip_address = s2.ip_address and (s1.created and s2.created fall 6 months within each other)) group by x)
So now we have a table mapping each survey_id to its correct ip_count. To update the original table, we need to join that against this and copy the values over
So that should look something like
UPDATE surveys SET s.ip_count = n.c from surveys s inner join (ABOVE QUERY) n on s.survey_id = n.x
There is some pseudo code in there, but I think the general idea should work
I have never had to update a table based on the output of another query myself before.. Tried to guess the right syntax for doing this from this question - How do I UPDATE from a SELECT in SQL Server?
Also if I needed to do something like this for my own work, I wouldn't attempt to do it in a single query.. This would be a pain to maintain and might have memory/performance issues. It would be best have a script traverse the table row by row, update on a single row in a transaction before moving on to the next row. Much slower, but simpler to understand and possibly lighter on your database.

Mysql subquery with joins

I have a table 'service' which contains details about serviced vehicles. It has an id and Vehicle_registrationNumber which is a foreign key. Whenever vehicle is serviced, a new record is made. So, for example if I make a service for car with registration ABCD, it will create new row, and I will set car_reg, date and car's mileage in the service table (id is set to autoincreament) (e.g 12 | 20/01/2012 | ABCD | 1452, another service for the same car will create row 15 | 26/01/2012 | ABCD | 4782).
Now I want to check if the car needs a service (the last service was either 6 or more months ago, or the current mileage of the car is more than 1000 miles since last service), to do that I need to know the date of last service and the mileage of the car at the last service. So I want to create a subquery, that will return one row for each car, and the row that I'm interested in is the newest one (either with the greatest id or latest endDate). I also need to join it with other tables because I need this for my view (I use CodeIgniter but don't know if it's possible to write subqueries using CI's ActiveRecord class)
SELECT * FROM (
SELECT *
FROM (`service`)
JOIN `vehicle` ON `service`.`Vehicle_registrationNumber` = `vehicle`.`registrationNumber`
JOIN `branch_has_vehicle` ON `branch_has_vehicle`.`Vehicle_registrationNumber` = `vehicle`.`registrationNumber`
JOIN `branch` ON `branch`.`branchId` = `branch_has_vehicle`.`Branch_branchId`
GROUP BY `service`.`Vehicle_registrationNumber` )
AS temp
WHERE `vehicle`.`available` != 'false'
AND `service`.`endDate` <= '2011-07-20 20:43'
OR service.serviceMileage < vehicle.mileage - 10000
SELECT `service`.`Vehicle_registrationNumber`, Max(`service`.`endDate`) as lastService,
MAX(service.serviceMileage) as lastServiceMileage, vehicle.*
FROM `service`
INNER JOIN `vehicle`
ON `service`.`Vehicle_registrationNumber` = `vehicle`.`registrationNumber`
INNER JOIN `branch_has_vehicle`
ON `branch_has_vehicle`.`Vehicle_registrationNumber` = `vehicle`.`registrationNumber`
INNER JOIN `branch`
ON `branch`.`branchId` = `branch_has_vehicle`.`Branch_branchId`
WHERE vehicle.available != 'false'
GROUP BY `service`.`Vehicle_registrationNumber`
HAVING lastService<=DATE_SUB(CURDATE(),INTERVAL 6 MONTH)
OR lastServiceMileage < vehicle.mileage - 10000
;
I hope I have no typo in it ..
If instead of using * in the subquery you specify the fields you need (which is always good practice anyway), most databases have a MAX() function that returns the maximum value within the group.
Actually, you don't even need the subquery. You can do the joins and use the MAX in the SELECT statement. Then you can do something like
SELECT ...., MAX('service'.'end_date') AS LAST_SERVICE
...
GROUP BY 'service'.'Vehicle_registrationNumber'
Or am I missing something?