checked several threads and some did help but now I'm getting an error:
ERROR: more than one row returned by a subquery used as an expression
SQL state: 21000
Not sure what's the exact issue even though read some explanations. Would appreciate if someone could explain with using my code bellow.
I have a table / view called vw_inv_stock_art_global, and it has a column "stock" with a number.
Then also I have a table dis_orderoutdetails with a column "onstock" which needs to copy the "stock" cells based on article_id both tables have in common.
UPDATE dis_orderoutdetails
SET onstock = (SELECT stock
FROM vw_inv_stock_art_global
WHERE vw_inv_stock_art_global.article_id = dis_orderoutdetails.article_id)
WHERE onstock is NULL
AND EXISTS(SELECT stock
FROM vw_inv_stoc_art_global
WHERE vw_inv_stock_art_global.article_id = dis_orderoutdetails.article_id);
Additional help if you can be bothered:
I was wondering if there's a possibility to change background colour of a cell just in SQL? Wanted to make an if...else and change colours of a cell depending on the result.
The problem is with this part of the statement:
SET onstock = (SELECT stock
FROM vw_inv_stock_art_global
WHERE vw_inv_stock_art_global.article_id = dis_orderoutdetails.article_id)
The SELECT query returns more than one row => there are more than one row in the vw_inv_stock_art_global view that has this article_id. If the result of a SELECT is to be used as a value there may only be one matching row.
Not sure about Postgres SQL syntax but it seems you would use LIMIT 1 to solve this.
SET onstock = (SELECT stock
FROM vw_inv_stock_art_global
WHERE vw_inv_stock_art_global.article_id = dis_orderoutdetails.article_id LIMIT 1)
However when you use LIMIT you probably need to use an ORDER BY clause as well to make sure that you use the most relevant row, not just any single row that matches the criterion. The most relevant row is most of the times the latest, so if there is some date column that specifies the entry of the row it is a good bet to be the column you need to order on. This is something you need to review according to your needs.
The ORDER BY would be inserted like this:
(Place holder needs to be replaced)
SET onstock = (SELECT stock
FROM vw_inv_stock_art_global
WHERE vw_inv_stock_art_global.article_id = dis_orderoutdetails.article_id
ORDER BY <some column>
LIMIT 1)
You can refactor your SQL without using subqueries, like:
UPDATE dis_orderoutdetails
SET onstock = g.stock
FROM vw_inv_stock_art_global
WHERE vw_inv_stock_art_global.article_id = dis_orderoutdetails.article_id
and onstock is NULL;
But be aware that the correctness of this SQL depends on the relationship between dis_orderoutdetails(article_id) and vw_inv_stock_art_global(article_id): article_id isn't a unique column in vw_inv_stock_art_global, this UPDATE won't be predictable, as each dis_orderoutdetails could be updated more than once, with different stock values.
Related
I have a table that I want to update that contains a column called 'expiration_days'. What I am doing is trying to update the records in the 'expiration_days' column by using an 'alias column' (not sure what to call it) that is apart of a subquery where I calculated the number of days until a user's password has expired. The column from the subquery that I want to take the values from and update them in the actual table is called 'countdown'. I named the subquery results 'query' (derived table). So far I have this:
UPDATE LOGIN_INFO
SET expiration_days = query.countdown
FROM (
select li.name as name, countdown = 365 - datediff(day, sl.pwdate, getdate())
from master..syslogins sl, LOGIN_INFO li
where li.name = sl.name) query
WHERE LOGIN_INFO.name = query.name
The issue I am having is I get this error: You cannot use a derived table in the FROM clause of an UPDATE or DELETE statement. ( I also get: Incorrect syntax near ')' on the subquery where clause)
Is there a way I can take the results from the calculated column in a select statement and update the column in the LOGIN_INFO table in one query or some other easy clean way?
Perhaps something along the lines of:
update login_info
set expiration_days = (select 365 - datediff(day,s1.pwdate,getdate())
from master..syslogins s1
where s1.name = li.name)
from login_info li
where exists(select 1
from master..syslogins s2
where s2.name = li.name)
NOTES:
the exists() clause is added to insure we don't erroneously update a row in login_info that doesn't have a match in syslogins, otherwise OP will need to modify the logic accordingly (ie, what to set expiration_days to if a matching rows does not exist in syslogins?)
if syslogins.pwdate is NULLable (I don't have access to a running ASE instance at the moment) then OP will need additional logic to handle the scenario where s1.pwdate is NULL; default countdown to some hardcoded value? or perhaps modify the exists() to include the additional clause and s2.pwdate is not NULL?
I'm updating a count column in one table with the count of corresponding rows in another table like so, which seems to work fine.
UPDATE #Circuits
SET CMLTotal = (SELECT COUNT(#UTCMLs.Drawing)
FROM #UTCMLs
WHERE #UTCMLs.DRAWING = #Circuits.DRAWING)
Now I need to include the rows from another table, #XRAYCMLs to get the total count of corresponding rows from both tables. I'm thinking UNION, but do not know how to make that happen.
How can I update my existing statement to accomplish my goal?
You might just want + and two subqueries:
Update #Circuits
SET CMLTotal = (select COUNT(u.Drawing)
from #UTCMLs u
where u.DRAWING = #Circuits.DRAWING
) +
(select COUNT(#UTCMLs.Drawing)
from #XRAYCMLs x
where x.DRAWING = #Circuits.DRAWING
);
I want to select row IDs associated with distinct column combinations in the remainder of a table. For instance, if the distinct rows are
I want to get the row IDs associated with each row. I can't query for distinct IDs since they are the row's primary key (and hence are all distinct).
So far I have:
SELECT e.ID
FROM E_UPLOAD_TEST e
INNER JOIN (
SELECT DISTINCT WHAT, MATERIALS, ERROR_FIELD, UNITS, SEASONALITY, DATA_TYPE, DETAILS, METHODS, DATA_FORMAT
FROM E_UPLOAD_TEST) c
ON e.WHAT = c.WHAT AND e.MATERIALS = c.MATERIALS AND e.ERROR_FIELD = c.ERROR_FIELD AND e.DATA_TYPE = c.DATA_TYPE AND e.METHODS = c.METHODS AND e.DATA_FORMAT = c.DATA_FORMAT;
which runs but doesn't return anything. Am I missing a GROUP BY and/or MIN() statement?
#serg is correct. Every single row in your example has at least one column value that is null. That means that no row will match your join condition. That is why your query results in no rows found.
Modifying your condition might get you what you want so long has your data isn't changing frequently. If it is changing frequently, then you probably want a single query for the entire job otherwise you'll have to set your transaction so that it is immune to data changes.
An example of such a condition change is this:
( (e.WHAT is null and c.WHAT is null) or (e.WHAT = c.WHAT) )
But such a change makes sense only if two rows having a null value in the same column means the same thing for both rows and it has to mean the same thing as time marches on. What "WHAT is null" means today might not be the same thing tomorrow. And that is probably why C. J. Date hates nulls so much.
Instead of comparing, use the decode function which compares two null values correctly.
e.WHAT = c.WHAT -> DECODE(e.WHAT, c.WHAT, 1) = 1
This code is only updating one row, why? It has to do with one of the sub-queries but I am not sure. I'm thinking the WHERE..IN in the UPDATE statement but I am not sure.
UPDATE [sde].[sy1].[Valve_evw]
SET [sde].[sy1].[Valve_evw].[MA]
= (SELECT [sde].[sy1].[Valve_Join_evw].[MC]
FROM [sde].[sy1].[Valve_Join_evw])
WHERE [sde].[sy1].[Valve_evw].[PrimaryKey]
IN (SELECT [sde].[sy1].[Valve_Join_evw].[PrimaryKey]
FROM [sde].[sy1].[Valve_Join_evw]
WHERE [sde].[sy1].[Valve_Join_evw].[MA]
!= [sde].[sy1].[Valve_Join_evw].[MC])
Context:
What I am trying to do is update the MA column in Valve_evw using the MC column in Valve_Join_evw. The PrimaryKey in Valve_evw references equivalent rows as the PrimaryKey in Valve_Join_evw. As in, a single row in Valve_Join_evw will have the same PrimaryKey as a single row in Valve_evw, thus that equivalency can be used to update the records in Valve_evw. Also the MA column is equivalent in both tables. [Note: The Valve_Join_evw table is created with ESRI mapping software using the spatial relationship between the Valve_evw and a separate table, this is how the duplicate rows exist]
I am using database views (hence the '_evw') in SQL Server with a default INSTEAD OF UPDATE trigger. This combination, views and trigger, prevents the use of table joins to do this update. I have also tried MERGE but that will not work either. Therefore I am stuck with the ANSI standard, hence the sub-queries. This script runs with no errors but it only updates a single row whereas there are about 9000 thousand rows in the tables.
The output message:
(1 row(s) affected)
(0 row(s) affected)
First of all let's reduce the eye hurting SQL to what it really is:
update sde.sy1.valve_evw
set ma = (select mc from sde.sy1.valve_join_evw)
where primarykey in (select primarykey from sde.sy1.valve_join_evw where ma <> mc)
WHERE clause
We look for all primarykey in valve_join_evw where a record's ma <> mc. We update all valve_evw records with such primarykey.
SET clause
For a record we want to update, we set ma to the value found with:
select mc from sde.sy1.valve_join_evw
But this query has no where clause, so what value does it select to fill the record's ma field? It selects all mc from valve_join_evw, so the DBMS probably picks one of these values arbitrarily. (It would be better, it raised an error.)
Conclusion
It is very easy to see which records the statement will update.
Which primarykey:
select primarykey from sde.sy1.valve_join_evw where ma <> mc
Which rows:
select *
from sde.sy1.valve_evw
where primarykey in (select primarykey from sde.sy1.valve_join_evw where ma <> mc)
As to the SET clause: Add a WHERE clause to your subquery that relates the record to select to the record to update (same ma? same primarykey?) E.g.:
set ma =
(
select mc
from sde.sy1.valve_join_evw vj
where vj.primarykey = valve_evw.primarykey
and vj.ma = valve_evw.ma
)
Hi there i recomend first to do the select statement and when you are ok with te records retrieved use the same where for the update statement
Here is what the final script looks like.
UPDATE [Valve_evw]
SET [Valve_evw].[MA] =
(
SELECT [Valve_Join_evw].[MC]
FROM [Valve_Join_evw]
WHERE[Valve_Join_evw].[PrimaryKey] = [Valve_evw].[PrimaryKey]
)
WHERE [Valve_evw].[PrimaryKey]
IN (
SELECT [Valve_Join_evw].[PrimaryKey]
FROM [Valve_Join_evw]
WHERE [Valve_Join_evw].[MA]
!= [Valve_Join_evw].[MC]
);
I am using PostgreSQL and I would like to update a table which would include an auto number column id. I know it might something very simple but I have done something like this;
CREATE SEQUENCE SEQ_ID
MINVALUE 1
START WITH 1
INCREMENT BY 1
CACHE 10
update trk2
set (id, track_id, track_point) =
(select nextval('seq_id'), trk1.track_fid, trk1.wkb_geometry
from track_points_1 as trk1
where track_fid = 0)
The thing is that it is giving me the following error (code reformatted):
ERROR: syntax error at or near "select"
LINE 3: set (id, track_id, track_point)=(select nextval('seq_id'), t...
Can anybody help please?
Your query is broken in several places. It could look something like this:
UPDATE trk2
SET (id, track_id, track_point) =
(next_id, x.track_fid, x.wkb_geometry)
FROM (
SELECT id
,nextval('seq_id') AS next_id
,track_fid
,wkb_geometry
FROM track_points_1
WHERE track_fid = 0
) x
WHERE trk2.id = x.id; -- adapt to your case
Or simpler (preferable syntax):
UPDATE trk2
SET (id, track_id, track_point) =
(nextval('seq_id'), x.track_fid, x.wkb_geometry)
FROM track_points_1 x
WHERE x.track_fid = 0
AND trk2.id = x.id; -- adapt to your case
Major points:
An UPDATE without a WHERE clause only makes sense if you really need to change each and every row in the table. Else it is wrong or at least sub-optimal.
When you retrieve values from another table, you get a CROSS JOIN between target and source if you don't add a WHERE clause connecting target with source - meaning that every row of the target table will be updated with every row in the source table. This can take a very long time and lead to arbitrary results. The last UPDATE wins. In short: this is almost always complete nonsense and extremely expensive at that.
In my example I link target and source by the id column. You have to replace that with whatever fits in your case.
You can assign multiple values in one SET clause in an UPDATE, but you can only return a single value from a correlated subselect expression. Therefore, it is strictly not possible to have a subselect in a SET clause with multiple values.
Your initial syntax error comes from a missing pair of parenthesis around your subselect. But adding that only reveals the error mentioned above.
Depending on what you are after, you would include nextval('seq_id') in the subquery or in the SET clause directly. This can lead to very different results, especially when you have rows in the subquery that are not used in the UPDATE.
I placed it in the SET clause because I suspect, that's what you want. The sequence of rows is still arbitrary. If you want more control over which numbers are assigned, you need to define what you want and then take a different route.
Tyler Eaves is correct, this action is not advisable.
However, if you insist, this may help:
Once you have a sequence on a column you don't have to call nextval() in the SET statement. Just leave it out and the column will auto-increment.
UPDATE
trk2
SET
(
track_id = [track_id Value],
track_point = [track_point Value]
)
or, include it and set it to default or null
UPDATE
trk2
SET
(
id = default,
track_id = [track_id Value],
track_point = [track_point Value]
)
Using your example:
UPDATE
trk2
SET
(
track_id,
track_point
) = (
SELECT
trk1.track_fid,
trk1.wkb_geometry
FROM
track_points_1 AS trk1
WHERE
track_fid = 0
)
I think you need a second set of parentheses on the RHS of the SET clause:
UPDATE trk2
SET (id, track_id, track_point) =
((SELECT nextval('seq_id'), trk1.track_fid, trk1.wkb_geometry
FROM track_points_1 as trk1
WHERE track_fid = 0));
The first set of parentheses matches the parentheses on the LHS of the SET clause. The second set wraps up the sub-query for re-use.