Update table based on another table - sql

I'm trying to update a column in a table based on another column in another table.
UPDATE eval e
SET rank = (SELECT p.desc
FROM Position p
WHERE p.id = e.faculty
AND p.date >= '2011-05-20'
)
p.id and e.faculty correspond. I want to update rank with p.desc if the id's are the same. (e.faculty and p.id)
Any help will be great! :)

Try this for SQL Server:
UPDATE dbo.eval
SET rank = p.desc
FROM dbo.Position p
WHERE p.id = eval.faculty and p.date >= '2011-05-20'
or if you need an alias on the base table (for whatever reason), you need to do this:
UPDATE dbo.eval
SET rank = p.desc
FROM dbo.eval e
INNER JOIN dbo.Position p ON p.id = e.faculty
WHERE p.date >= '2011-05-20'

You need a restriction in the form of a WHERE clause; if you use EXISTS you can based it on you scalar subquery e.g.
UPDATE eval
SET rank = (
SELECT p.desc
FROM Position p
WHERE p.id = eval.faculty
AND p.date >= '2011-05-20'
)
WHERE EXISTS (
SELECT *
FROM Position p
WHERE p.id = eval.faculty
AND p.date >= '2011-05-20'
);
Note the above targets the UPDATE on the base table eval rather than the correlation name e. This makes a lot more sense when you think of an SQL UPDATE in terms of relational assignment i.e. you don't want to assign to e because it (unlike the base table) will go out of scope!

Related

Update different data type columns

I have two tables GCB.NewsOne & GCB.NewsTwo both table are same except one column
it's GCode in dbo.News table GCode is varchar(100) null and GCB.News table has a bigint null column.
Now I want to update the code in GCode in dbo.News to the value of GCB.News.
I tried like below, but it's not working
UPDATE [GCB].[NewsOne] AS G
SET G.Code = (SELECT P.Code FROM GCB.NewsTwo P WHERE G.ID = P.ID)
Try casting the bigint to varchar:
UPDATE G
SET Code = CAST(P.Code AS VARCHAR(MAX))
FROM [GCB].[NewsOne] G
INNER JOIN GCB.NewsTwo P
ON G.ID = P.ID;
This assumes that your problem really is the types of the two codes, and not something else.
Also note that I rewrote your join using update join syntax, which I think is easier to read.
You may not use an alias in an update statement. This works fine:
UPDATE [GCB].[NewsOne]
SET [GCB].[NewsOne].Code = ( SELECT P.Code FROM GCB.NewsTwo P
WHERE [GCB].[NewsOne].ID=P.ID )

SELECT statement where rows are omitted based on another table

Table with orders has another table with positions. I want the orders table to show but then only have the most up to-date position on it. Below is a picture of the 3 rows I want showing. Omit the rest.
SELECT DispatchTable.ordernumber, DispatchTable.truck,
DispatchTable.driver, DispatchTable.actualpickup,
DispatchTable.actualdropoff, orders.pickupdateandtime,
orders.dropoffdateandtime, Truck002.lastposition,
Truck002.lastdateandtime
FROM DispatchTable
INNER JOIN orders ON DispatchTable.ordernumber = orders.id
INNER JOIN Truck002 ON DispatchTable.truck = Truck002.name
WHERE (orders.status = 'onRoute')
Assuming that you want the row having the latest lastdateandtime for the truck name, this should work:
SELECT DispatchTable.ordernumber,
DispatchTable.truck,
DispatchTable.driver,
DispatchTable.actualpickup,
DispatchTable.actualdropoff,
orders.pickupdateandtime,
orders.dropoffdateandtime,
TruckLatest.lastposition,
TruckLatest.lastdateandtime
FROM DispatchTable
INNER JOIN orders ON DispatchTable.ordernumber = orders.id
INNER JOIN (SELECT name,
lastposition,
lastdateandtime
FROM Truck002 Truck1
WHERE lastdateandtime =
(SELECT MAX(lastdateandtime)
FROM Truck002 Truck2
WHERE Truck2.name = Truck1.name)) TruckLatest
ON DispatchTable.truck = TruckLatest.name
WHERE (orders.status = 'onRoute')
If I understand correctly, you can get the most recent record for a truck using ROW_NUMBER():
SELECT dt.ordernumber, dt.truck,
dt.driver, dt.actualpickup,
dt.actualdropoff, o.pickupdateandtime,
o.dropoffdateandtime, t.lastposition,
t.lastdateandtime
FROM DispatchTable dt INNER JOIN
orders o
ON dt.ordernumber = o.id INNER JOIN
(SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY t.name ORDER BY t.lastdateandtime DESC) as seqnum
FROM Truck002 t
) t
ON dt.truck = t.name
WHERE o.status = 'onRoute' AND seqnum = 1;
Firstly, why are you using Truck002's name field rather than its id field as the link to DispacthTable? This is considered a less efficient way of doing it than using id (which is either a numerical field or a shorter string than name).
Secondly, you should mention in your Question that each Order can have many DispatchTable's and that each DispacthTable can have many Truck002's, otherwise many people will start by assuming that it is the other way round between DispatchTable and Truck002.
Thirdly, please try...
SELECT DispatchTable.ordernumber,
DispatchTable.truck,
DispatchTable.driver,
DispatchTable.actualpickup,
DispatchTable.actualdropoff,
orders.pickupdateandtime,
orders.dropoffdateandtime,
Truck002.lastposition,
Truck002.lastdateandtime
FROM DispatchTable
INNER JOIN orders ON DispatchTable.ordernumber = orders.id
INNER JOIN Truck002 ON DispatchTable.truck = Truck002.name
WHERE (orders.status = 'onRoute')
GROUP BY ordernumber
HAVING lastdateandtime = MAX( lastdateandtime )
If you have any questions or comments, then please feel free to post a Comment accordingly.
Further Reading
https://msdn.microsoft.com/en-us/library/bb177906(v=office.12).aspx (on HAVING)
https://www.w3schools.com/sql/sql_having.asp (on HAVING)
https://msdn.microsoft.com/en-us/library/bb177905(v=office.12).aspx (on GROUP BY)
https://www.w3schools.com/sql/sql_groupby.asp (on GROUP BY)

Aggregate to 'plain' query

I have a query which uses aggregate functions to assign the maximum absolute of the values to another column in the table. The problem is that it takes whole lot of time (apprx. adds upto 10-15 seconds) to query completion time. This is what the query looks like:
UPDATE calculated_table c
SET tp = (SELECT MAX(ABS(s.tp))
FROM ts s INNER JOIN tc t ON s.id = t.id
GROUP BY s.id);
Where id is not unique, hence the grouping. tp is a numeric whole number field. Here is what the tables look like:
TABLE ts
PID(primary) | id (FKEY) | tp (integer)
--------------------+-----------------------------+------------------------------------------------------
1 | 2 | -100
2 | 2 | -500
3 | 2 | -1000
TABLE tc
PID(primary) | id (FKEY)
--------------------+-----------------------------+-------------------------
1 | 2
I want the output to look like:
TABLE c
PID(primary) | tp (integer)
--------------------+-----------------------------+--------
1 | 1000
I tried to make it work like this:
UPDATE calculated_table c
SET tp = (SELECT s.tp
FROM ts s INNER JOIN tc t ON s.id = t.id
ORDER BY s.tp DESC
LIMIT 1);
Though it improved the performance, however the results are incorrect.. any help would be appreciated?
I did manage to modify the query, turnsout nesting aggregate functions is not a good option. However, if it helps anyone, here is what I ended up doing:
UPDATE calculated_table c
SET tp = (SELECT ABS(s.trade_position)
FROM ts s INNER JOIN tc t ON s.id = t.id
WHERE c.id = s.id
ORDER BY ABS(s.tp) DESC
LIMIT 1);
Though it improved the performance, however the results are incorrect.
The operation was a success, but the patient died.
The problem with your query is that
SELECT MAX(ABS(s.tp))
FROM ts s INNER JOIN tc t ON s.id = t.id
GROUP BY s.id);
doesn't produce a scalar value; it produces a column of values, one for each s.id. Your DBMS really should raise a syntax error. In terms of performance, I think you're sequentially applying each row produced by the subquery to each row in the target table. It's probably both slow and wrong.
What you want is to correlate your select output with the table you're updating, and limit the rows updated to those correlated. Here's ANSI syntax to update one table from another:
UPDATE calculated_table
SET tp = (SELECT MAX(ABS(s.tp))
FROM ts s INNER JOIN tc t ON s.id = t.id
where s.id = calculated_table.id)
where exists ( select 1 from ts join tc
on ts.id = tc.id
where ts.id = calculated_table.id )
That should be close to what you want.
BTW, it's tempting to interpret correlated subqueries literally, to think that the subquery is run N times, once for each row in the target table. And that's the right way to picture it, logically. The DBMS won't implement it that way, though, in all likelihood, and performance should be much better than that picture would suggest.
Try:
UPDATE calculated_table c
SET tp = (SELECT greatest( MAX( s.tp ) , - MIN( s.tp ))
FROM ts s INNER JOIN tc t ON s.id = t.id
WHERE c.id = s.id
);
Also try to create a multicolumn index on ts( id, tp )
I hope the below sql will be helpful to you, I tested in netezza, but not postgresql. Also, I didn't put update on top of it.
SELECT ABS(COM.TP)
FROM TC C LEFT OUTER JOIN
(SELECT ID,TP
FROM TS A
WHERE NOT EXISTS (SELECT 1
FROM TS B
WHERE A.ID = B.ID
AND ABS(B.TP)>ABS(A.TP))) COM
ON C.ID = COM.ID

Error with the sum function in sql with Access

I am trying to sum the total price from invoices (named Total_TTC in table FACT) depending on the code of the taker ( named N_PRENEUR in the two concerned tables) and store the result in the DEBIT_P column of the table table_preneur.
Doing so i get a syntax error (missing operator) In access and can't seem to understand why. I tried other posts and the usggestions returned me the same error.
UPDATE P
SET DEBIT_P = t.somePrice
FROM table_preneur AS P INNER JOIN
(
SELECT
N_PRENEUR,
SUM(Total_TTC) somePrice
FROM
FACT
GROUP BY N_PRENEUR
) t
ON t.N_PRENEUR = p.N_PRENEUR
thx in advance
with cte as
(select t.somePrice
from table_preneur as P
inner join (select SUM(Total_TTC) as somePrice
from FACT
group by N_PRENEUR) t
on t.N_PRENEUR = p.N_PRENEUR)
update P
set DEBIT_P = cte.somePrice
-- DO YOU NEED A WHERE CLAUSE?
--or maybe
update table_preneur
set DEBIT_P = (select t.somePrice
from table_preneur as P
inner join (select SUM(Total_TTC) as somePrice
from FACT
group by N_PRENEUR) t
on t.N_PRENEUR = p.N_PRENEUR)
You're missing the as keyword before your column alias somePrice:
UPDATE P
SET DEBIT_P = t.somePrice
FROM table_preneur AS P INNER JOIN
(
SELECT
N_PRENEUR,
SUM(Total_TTC) as somePrice
FROM
FACT
GROUP BY N_PRENEUR
) t
ON t.N_PRENEUR = p.N_PRENEUR
Just to clarify the above, in MS Access SQL, you need to use AS when declaring a table alias - this is missing from your SQL (SUM(Total_TTC) AS somePrice)

SQL Update Left Join - however if no records put 0 in field

This query works, however I need it to do something additional that I can't figure out how to do. I need the query to put a 0 into the "activityTempBookings" field if there are no records returned in the LEFT JOIN section. This is so that it overwrites older data where there are no activities with a future "tempReserveDate" even though in the past the may have been.
UPDATE P
SET activityTempBookings = t.bookingTempTotal
FROM [LeisureActivities].[dbo].[activities] AS P
LEFT JOIN (
SELECT tempActivityID, SUM(tempPlaces) bookingTempTotal
FROM [LeisureActivities].[dbo].[tempbookings]
WHERE tempReserveDate > GETDATE ()
GROUP BY tempActivityID
)t
ON t.tempActivityID = p.activityID
Any help greatly appreciated - Please don't think I'm rude but I may not respond until Monday.
Thanks.
use COALESCE which basically returns the first nonnull expression among its arguments.
UPDATE P
SET activityTempBookings = COALESCE(t.bookingTempTotal, 0)
FROM [LeisureActivities].[dbo].[activities] AS P
LEFT JOIN
(
SELECT tempActivityID,
SUM(tempPlaces) bookingTempTotal
FROM [LeisureActivities].[dbo].[tempbookings]
WHERE tempReserveDate > GETDATE ()
GROUP BY tempActivityID
) t ON t.tempActivityID = p.activityID
TSQL COALESCE()
Use ISNULL
UPDATE P
SET activityTempBookings = ISNULL(t.bookingTempTotal,0)
FROM [LeisureActivities].[dbo].[activities] AS P
LEFT JOIN (
SELECT tempActivityID, SUM(tempPlaces) bookingTempTotal
FROM [LeisureActivities].[dbo].[tempbookings]
WHERE tempReserveDate > GETDATE ()
GROUP BY tempActivityID
)t
ON t.tempActivityID = p.activityID