update all rows of a table in postgresql - sql

I am comparing every row of a table I have with every other row to find the minimum distance. I also want to add two columns one called "closest_distance", and the other "id_of_the_closest_distance".
I know that I need to do this in two steps: one- update the first row, and two- evaluate the second row based on the first.
I have a query that gives me the closest distance as below:
SELECT DISTINCT ON (a.id)
a.id,
(SELECT
MIN(ST_HausdorffDistance(a.the_geom, b.the_geom))
FROM
gridareas AS b
WHERE
b.id != a.id
)
FROM gridareas AS a;
However I cannot use a simple
UPDATE tablename SET colname = expression;
and use the query above as the expression, because
ERROR: subquery must return only one column
LINE 5: (SELECT DISTINCT ON (a.id)
On the other hand, the subquery cannot return both a.id and the MIN(ST_HausdorffDistance()).
How should I proceed to update this column?

Is this what you want?
update gridareas ga
set (closest_id, closest_dist) =
(select gs2.id, ST_HausdorffDistance(ga.the_geom, ga2.the_geom) as dist, ga2.id
from gridareas ga2
where ga2.id <> ga.id
order by ST_HausdorffDistance(ga.the_geom, ga2.the_geom)
limit 1
);

Not exactly, but it helped a lot, thanks!
This is what fixed my problem:
UPDATE
gridareas AS a
SET
(hausdorffdistance_to_closest_geom) =
(SELECT
MIN(ST_HausdorffDistance(a.the_geom, b.the_geom))
FROM
gridareas AS b
WHERE
b.id != a.id
);

Related

update multiple rows with joins

I have this query in postgresql:
select *
from A s
join B m on (s.id=m.id)
where m.key=4 and s.ran=some_input_from_user
This gives me all the rows that I need to update.
I want to set A.value to be 90 for all these rows.
It doesn't look like a standart update query
if I do...
Update A set value=90 where.....
then I can't do the join.
any ideas how to do it?
This is the basic update syntax for PostgreSQL where you are updating based on a join to another table:
update A s
set
value = 90
from B m
where
s.id = m.id and
m.key = 4 and
s.ran = some_input_from_user
The trick is you never use the alias in the lvalue for the set commands. In other words, value = 90 is not s.value = 90. It seems minor, but I'm pretty sure it will prevent your query from working. The rationale is if you are updating table A (alias s) then any fields you are updating are, de-facto, from table A -- no need to alias them, and to allow aliases would almost imply you could update something other than A with this statement, which you cannot.
You can definitely use them in the rvalues, so this would certainly be okay (if it were your desire to update A based on B):
update A s
set
value = m.salary * s.commission
from B m
where
s.id = m.id and
(s.value is null or
s.value != m.salary * s.commission)
Here is the query:
update a set value = 90
where exists (
select 1 from b
where a.id = b.id and b.key=4
and a.ran=some_input_from_user);
The above query will eliminate the requirement of reading table a twice.
Also you can use this query:
update a set value = 90
where a.id in
(select b.id from b
where a.id = b.id and b.key = 4
and a.ran=some_input_from_user);
TRY THIS
UPDATE A
SET A.VALUE = 90
from A
join B m on (A.id=m.id)
where m.key=4 and s.ran=some_input_from_user

Combine SQL query result with another query statement under one query? (Complicated)

I currently want to combine two SQL queries into one. This is a bit similar to SQL: Taking the result of of query and using it another - combine. Suppose there are two queries:
SQL Statement
1.) SELECT *
FROM (SELECT B.example1
FROM EXAMPLE1A A
INNER JOIN EXAMPLE1B B ON A.ID = B.ID
WHERE A.ABC ='ABC'
ORDER BY A.ORDER_BY ) as colstate
2.) SELECT colstate
FROM EXAMPLE_TABLE
WHERE EFG LIKE '%'
AND BGTHAN >= '1'
AND SMTHAN <= '100'
ORDER BY ORDER_BY ASC
I want to use the result in query 1.) as the colstate (column statement) in query 2.). But:
What Have I tried is:
SELECT (SELECT B.example1
FROM EXAMPLE1A A
INNER JOIN EXAMPLE1B B
ON A.ID = B.ID
WHERE A.ABC ='ABC'
ORDER BY A.ORDER_BY )
FROM EXAMPLE_TABLE
WHERE EFG LIKE '%'
AND BGTHAN >= '1'
AND SMTHAN <= '100'
ORDER BY ORDER_BY ASC
And it turns out to be Error: Scalar subquery is only allowed to return a single row, how should I replace the "=" into "IN"? Or is my statement totally wrong?
"Combine two queries into one" - that's not a good specs. Try to find out what exactly you want to get as a FLAT 2-dimensional table, think of nested SELECTs as of nested loops where the inner one can only set a single value for parent's row. Like this:
[Outer loop - parent row]
[Inner loop - children rows]
// all you can do here is change a single parent's field to anything
// like constant/sum/avg/topmost/ugly-subquery-returning-a-single-result
[/Inner loop]
[/Outer loop]
The error says that query you are using as column statement must return at most a single row.
It should probably look something like this:
SELECT (SELECT B.example1
FROM EXAMPLE1A A
INNER JOIN EXAMPLE1B B
ON A.ID = B.ID
WHERE A.ABC ='ABC'
AND A.SOME_COLUMN = E.SOMECOLUMN // retrieve only relevant data for this row
ORDER BY A.ORDER_BY )
FROM EXAMPLE_TABLE E
WHERE EFG LIKE '%'
AND BGTHAN >= '1'
AND SMTHAN <= '100'
ORDER BY ORDER_BY ASC

An aggregate may not appear in the set list of an UPDATE statement

UPDATE [silverdb01].[dbo].[info]
SET [FM] = SUM(a.[MONDAY] - b.[QUOTA])
FROM [silverdb01].[dbo].[info] a, [silverdb01].[dbo].[quota] b
WHERE a.[WORK_TYPE]='IN' AND a.[NAME]='KUTHAY'
When I run this I get the following error:
An aggregate may not appear in the set list of an UPDATE statement.
Any ideas?
I am guessing that (as other's have pointed out) you don't really want a cartesian on this update so I have added an "id" to the query so you will have to do some modification but this might get you on the right path
;with temp as (
select a.id, SUM(a.pazartesi - b.kota) as newTotal
from [asgdb01].[dbo].[info] a join [asgdb01].[dbo].[kota] b
on a.id = b.id
where a.work_type='in' and a.name='alp' )
update a
set fm = t.newTotal
from [asgdb01].[dbo].[info] a join temp t on a.id = t.id

Selective update in SQL Server

I've created a junction table like this one:
http://imageshack.us/scaled/landing/822/kantotype.png
I was trying to figure out a query that could able to select some rows - based on the PokémonID - and then updating only the first or second row after the major "filtering".
For example:
Let's suppose that I would like to change the value of the TypeID from the second row containing PokémonID = 2. I cannot simply use UPDATE KantoType SET TypeID = x WHERE PokémonID = 2, because it will change both rows!
I've already tried to use subqueries containing IN,EXISTS and LIMIT, but with no success.
Its unclear what are your trying to do. However, you can UPDATE with JOIN like so:
UPDATE
SET k1.TypeID = 'somethng' -- or some value from k2
FROM KantoType k1
INNER JOIN
(
Some filtering and selecting
) k2 ON k1.PokémonID = k2.PokémonID
WHERE k1.PokémonID = 2;
Or: if you want to UPDATE only the two rows that have PokémonID = 2 you can do this:
WITH CTE
AS
(
SELECT *,
ROW_NUMBER() OVER(ORDER BY TypeID) rownum
FROM KantoType
WHERE PokemonID = 2
)
UPDATE c
SET c.TypeID = 5
FROM CTE c
WHERE c.rownum = 1;
SQL Fiddle Demo
I can suggest something like this if you just need to update a single line in your table:
UPDATE kantotype
SET
type = 2
WHERE pokemon = 2
AND NOT EXISTS (SELECT * FROM kantotype k2
WHERE kantotype.type > k2.type
AND kantotype.pokemon = k2.pokemon)
It would be easier to get the first or last item of the table if you had unique identifier field in your table.
Not sure even if you are trying to update the row with PokemenID =2 by doing a major filtering on TypeID... So just out of assumptiong (big one), you can give a try on Case
UPDATE yourtable a
LEFT JOIN youtable b on a.pokeid = b.pokeid
SET a.typeid = (CASE
WHEN a.typeid < b.typeid THEN yourupdatevalue
WHEN a.typeid > b.typeid THEN someothervalue
ELSE a.typeid END);
If you know the pokemon ID and the type id then just add both to the where clause of your query.
UPDATE KantoType
SET TypeID = x
WHERE PokémonID = 2
AND TypeID=1
If you don't know the type ID, then you need to provide more information about what you're trying to accomplish. It's not clear why you don't have this information.
Perhaps think about what is the unique identifier in your data set.

select complete rows using subset of columns from a subquery (single table)

I am trying to solve the following problem, illustrated in this table, sql statement and comments
TABLE COLUMNS: id, version, idx_on; PK is 'id' column
So, I get from the subquery a set of tuples{ id, version}.
I want to set the IDX_ON value for all rows which have ID and VERSION the same as those in the subquery' tuples above. Alternately, selecting all rows (ID, VERSION, IDX_ON) with the same criterion would be a good first step.
I tried without success to use something like:
SELECT * FROM docs where ID, VERSION in (subquery)
Thanks for any comment...
You can update all rows for which a later version exists:
update (
select *
from docs d1
where exists
(
select *
from docs d2
where d1.id = d2.id
and d2.version > d1.version
)
)
set idx_on = 0;
Updated SQL Fiddle.
This seemed to work:
update docs d
set d.idx_on = 0
where exists (select * from docs where id = d.id and version > d.version);
I'm not familiar with Oracle's SQL syntax, if same as in SQL-Server, try this:
UPDATE d
SET d.idx_on = 0
FROM docs d
INNER JOIN
( SELECT id,
MAX(version) AS "version"
FROM docs
GROUP BY id
)
q
ON q.id = d.id
AND q.version = d.version