Update two tables with a single query in SQL Server - sql-server-2008

I need to update some information which are stored in two tables. To update one of the table, a JOIN with the other table must be done. I was wondering, if I can update both with a single query. Some posts suggested using a trigger. I was hoping there's another way, since I will have to do it in C#. Also I saw other posts saying it's possible using something like this:
update pd, pr
set pd.Name = 'Test',
pr.Date = '2012-07-31',
from prDetail pd
left join pr on pd.ID = pr.ID
where pd.Code = '45007'
and pr = '2019'
and pr.Item = '1'
This is not working for me (it's showing this error: Incorrect syntax near ','). Can this be achieved in some way?

No.
You can only update one table at a time.
Separate your update into two update queries, and if necessary, wrap them in a transaction.

Yes, As #podiluska said you can only update one table at a time. And you can also use transaction for executing both query with a single transaction.
Else,
If your table/relation has dependency (foreign key and primary key ) relation , then you can use cascade options.
Else,
You can use Trigger.

No, it's not possible to update two at a time but you may consider wrapping it up in a stored procedure and calling that instead. You should try to avoid triggers for something like this if possible.

Related

Update attribute on table based on lowest ranking attribute from other table mySQL

I am using MySQL for the following: I have 2 tables, sw_products and sw_components. Each sw_product can be made up of multiple sw_components. And there is another relation table where each row specifies the product and a component it is uses.
Each sw_component has a status: 'ready', 'not-ready', and 'unusable'. And each sw_product also has a status which corresponds to the lowest status of all of its components.
What I was doing was trying was to create a TRIGGER UPDATE when sw_components updates, but then I'd need to cycle through all the sw_products that use that sw_component and change their status if the new status is higher. How can I do this inside a trigger? (assign a variable to a select statement, and cycle through each row, maybe?)
Thanks!
I´m the OP. I was able to solve the problem after some thinking. As Ultimater said, you can use cursors, but they´re read only, so you can go into some trouble, and I thought they were over-complicated (but still, thanks!).
What I did was changed the status from VARCHARS to INTEGERS, then I created a View of each product alongside their lowest status (using a MIN(status):
CREATE VIEW product_status_by_component AS
SELECT s_name, s_version, min(status) AS min
FROM sw_components
JOIN sw_build
ON sw_components.name = c_name AND sw_components.version = c_version
GROUP BY s_name, s_version;
Then I used a trigger each time a components status got updated. I found out you Update unrelated tables even if the trigger does not belong to them, and that you could join tables inside an update:
UPDATE sw_products a
LEFT JOIN product_status_by_component b ON
a.name = b.s_name AND a.version = b.s_version
SET
a.status = b.min;

SQL Query : Cannot create view due to error #1349 : Help to restructure query

I using a query that selects a check type "checks" and looks in the log file to find the most recent log entry referencing this check.
SELECT checks.*, logs.last_completed_on, logs.completed_by
FROM checks INNER JOIN
(
SELECT check_id, MAX(completed_on) AS last_completed_on,
completed_by FROM checks_log GROUP BY check_id
) logs
ON checks.id = logs.check_id
This query works but i need to create a view for it. This is the first time I've used views so i don't know a lot about them but i read that its not possible with this type of query...
My question is whether there was a way to restructure it in any way?
I guess another solution would be to call this query on a specific check id for every row in a table? It sounds bad practice though... and slow, but i'm not sure.
Thanks
A view in MySQL cannot handle subqueries in the from clause. So, you will need somewhat different logic.
This version should work:
SELECT c.*, cl.completed_on as last_completed_on, cl.completed_by
FROM checks c INNER JOIN
checks_log cl
ON c.check_id = cl.check_id
WHERE cl.completed_on = (SELECT MAX(cl2.completed_on)
FROM checks_log cl2
WHERE cl2.check_id = cl.check_id
);
MySQL does allow subqueries in the SELECT and FROM clauses, so this should be ok.
As long as the query is working correctly you can create a view from it.
CREATE VIEW {insertnamehere} as
(insertyourqueryhere)
Try with and without the parenthesis. I don't know what tool you're using*

SQL query with nested query on another table in it

I've got two tables, we'll call them email_bounces and master_email_list.
master_email_list is ~3.5m records.
email_bounces is ~100,000 records.
I'm trying to do a query where I update bounce=1 in master_email_list if the email address is found in email_bounces.
Here's what I have.
update 'master_email_list' set bounce=1 where email in (select email FROM 'email_bounces')
Except that doesn't seem to work, it queries, then hangs indefinitely (I left it running overnight, after about 4 hours running prior).
Help is appreciated.
Use
update master_email_list l
inner join email_bounces b on b.email = l.email
set bounce = 1
You could also try to deactivate keys during the update to speed things up:
ALTER TABLE master_email_list DISABLE KEYS;
And afterwards
ALTER TABLE master_email_list ENABLE KEYS;
By using table alias names you have to set it.
In this i am using inner join
update master_email_list mel
inner join email_bounces eb
on mel.email = eb.email
set mel.bounce = 1
If that simple query takes hours, I can only see two possible reasons;
You're missing an index with master_email_list.email as a first column.
CREATE INDEX ix_email ON master_email_list(email);
...should speed things up significantly.
You have an active transaction on the table that holds a lock. Check that you have no uncommitted transactions pending, and if you can't find them, check this answer how to look for them.

MySQL: Why does this select query not find row when joined table has multiple results?

Title might be confusing, didn't quite know how to put it. Here's what i need to do. I have two tables, cronjobs and cronjob_seeds. I need to see if a cronjob exists before adding it to the database.
Consider these tables:
cronjobs:
-id- -callback_model- -callback_method-
1 movie_suggestion_model fetch_similar_movies
cronjob_seeds:
-cronjob_id- -seed-
1 seed1
1 seed2
Before adding a new cronjob, i need to see if the exact same cronjob exists in the database. I wrote the following query, but it doesn't work if the cronjob has multiple seeds. It works good if it only has one seed, but every time a cronjob has multiple seeds it returns nothing.
SELECT `id`
FROM (`cronjobs`)
INNER JOIN `cronjob_seeds` ON `cronjob_seeds`.`cronjob_id` = `cronjobs`.`id`
WHERE `cronjobs`.`callback_model` = 'movie_suggestion_model'
AND `cronjobs`.`callback_method` = 'fetch_similar_movies'
AND `cronjob_seeds`.`seed` = '1'
AND `cronjob_seeds`.`seed` = 10
Am i missing something? Should i be using another type of join?
And, off topic, but a seed is a parameter for the callback method, i just named it a little weird.
You should use IN clause
Change your query to:
SELECT `id`
FROM (`cronjobs`)
INNER JOIN `cronjob_seeds` ON `cronjob_seeds`.`cronjob_id` = `cronjobs`.`id`
WHERE `cronjobs`.`callback_model` = 'movie_suggestion_model'
AND `cronjobs`.`callback_method` = 'fetch_similar_movies'
AND `cronjob_seeds`.`seed` IN ('seed1', 'seed2')
Only to check if a cron entry exists, you don't need a join, unless you need to check if it exists and has specific seeds. To check only if a cron entry exists you need to do something like this:
SELECT `id`
FROM `cronjobs`
WHERE `cronjobs`.`callback_model` = 'movie_suggestion_model'
AND `cronjobs`.`callback_method` = 'fetch_similar_movies'
How come your query return result even when you had a single row for _cronjob_seeds_ . Cause the last two AND criteria conflict with each other. You should revise it as :
AND `cronjob_seeds`.`seed` BETWEEN '1' AND '10'
Also are you questioning the existance of a record in cronjob_seed or in cronjob? Your query parameters does not seem to be clear. Are you trying to check whether a specific cronjob with specific seeds exist? Tip: try to write the query in human language than sql

DELETE data from two tables, based on a third's ID

I'm hesitant to run this query which deletes data (for obvious reasons).
I would like to delete the the matching rows from two tables, where the ID = the ID of a third table (which i want to remain unaffected)
This is the exact query I would like to run:
DELETE FROM ItemTracker_dbo.Transaction t,
ItemTracker_dbo.Purchase p
USING ItemTracker_dbo.Transaction
INNER JOIN ItemTracer_dbo.Purchase ON p.Transaction_ID = t.Transaction_ID
INNER JOIN ItemTracker_dbo.Item i ON i.Item_ID = p.Item_ID
WHERE i.Client_ID = 1
To test this, i tried running a select replacing DELETE FROM with SELECT * FROM, and I get a syntax error 'near USING'. When I remove USING ... it selects EVERY row in the table (ignoring the client_id=1 clause).
I (essentially) copied the syntax from the mysql manual (obviously replacing the values).
Is this query valid?
I'm sorry I didn't comment instead of post, but I just don't have enough reputation. Why don't you run it as a transaction and see the results? Or am I missing something?
http://dev.mysql.com/doc/refman/5.0/en/commit.html
As far as I know, you can't do that. The way to acomplish that is with a transaction.
START TRANSACTION;
DELETE FROM tableOne WHERE criteria;
DELETE FROM tableTwo WHERE criteria;
COMMIT;
If something goes wrong between the statements, you can issue a ROLLBACK and your data will be there.
The catch is, THIS WON'T WORK WITH MyISAM. MyISAM doesn't support transactions, so it will simply delete the data and there is no way to roll it back. They need to be InnoDB tables. It does this silently. I've lost a production table that way (good thing I had a backup and it wasn't updated much).
Easiest way to find out if the tables are InnoDB?
SHOW CREATE TABLE tableName;
At the end, it will have something like 'Engine = InnoDB' or 'Engine = MyISAM'.
I'm not familiar with this (non-standard?) use of USING to join tables in the above, but if you just want to delete rows from only some of the tables in the join the normal way would be:
DELETE Purchase, `Transaction`
FROM Item
JOIN Purchase ON Purchase.Item_ID=Item.Item_ID
JOIN `Transaction` ON `Transaction`.Transaction_ID=Purchase.Transaction_ID
WHERE Item.Client_ID=1;
Assuming I understand your schema right. It seems a bit unusual to be deleting the Transaction that is referenced from the Purchase as this would naturally be a many-Purchase​s-to-one-Transaction relation. Is there a UNIQUE constraint to ensure it is one-to-one? If not, can you be sure no other Purchase will be referencing the deleted Transaction?
You can test the above construct as a SELECT simply:
SELECT Purchase.Purchase_ID, `Transaction`.Transaction_ID
FROM Item ...