Fill one column with data from one column in another table (randomly) - sql

Let's say I have a table Geometry and another table Customer like this:
Geometry      Customer
City        ID    Location
----         --    --------
Berlin       1    (null)
Paris        2    (null)
London
Now I'd like to fill the column Location with data from the column City. "Randomly" would be nice but it doesn't matter at all.
I've tried
update Customer set Location = (select City from Geometry where rownum < 3);
but still getting this error: single-row subquery returns more than one row
UPDATE: I'd like to fill the whole column Location with one update statement. I'm using ORACLE. The result should look like this:
Customer
ID     Location
--      -------
1      Berlin
2      London
Does someone have any better idea?
Thank you very much!

SQL Server:
UPDATE
Customer
SET
Location = (SELECT TOP 1 City FROM Geometry ORDER BY NEWID());

Since you just want it to pick one record at "random", you need to specify the correct number of rows:
update Customer set Location = (select City from Geometry where rownum = 1);
But note that since the subquery is not correlated to the Customer at all, the subquery may be optimised to only run once, and the same (randomly chosen) City will probably be used to update all Locations.

I would do the following, create a trigger on customer:
CREATE OR REPLACE TRIGGER customer_location
BEFORE INSERT OR UPDATE OF location ON customer
FOR EACH ROW
WHEN (NVL(new.location, 'X') = 'X')
BEGIN
SELECT city INTO :new.location
FROM (
SELECT city FROM geometry
ORDER BY DBMS_RANDOM.VALUE
) WHERE rownum = 1;
END;
/
UPDATE customer SET location = 'X';
This will update the customers table with a matching, "random" location. The trigger will also produce a new "random" location when a record is INSERTed into customers - as long as the location to be inserted is 'X' or NULL. (This wouldn't be wise if you actually have a location X - plug in some other value there!)
It is very possible to write a stored procedure to do the same thing, but you would have to create a cursor to loop over all the rows of customers where location is NULL.

update customer set location =
(select city from (
select distinct c.id, g.city, dbms_random.value from customer c, geometry g
order by value, city, id
) randoms where randoms.id = customer.id and rownum=1);
distinct necessary if there were two equal random values for one id

Related

Replace t1 col with t2 col when [condition] + different datatype

I have this situation: deceduti(sigla,denominazione_provincia) , province(sigla_provincia,denominazione_provincia)
where sigla is a NUMBER and sigla_provincia is a CHAR(2).
I want to set deceduti.sigla=province.sigla_provincia where deceduti.denominazione_provincia=province.denominazione_provincia.
I have tried different ways but no one worked. I'd appreciate to understand how can i do this with join operator. There are my tries:
MERGE INTO DECEDUTI -- error with the datatypes
USING PROVINCE
ON ( DECEDUTI.DENOMINAZIONE_PROVINCIA = PROVINCE.DENOMINAZIONE_PROVINCIA )
WHEN MATCHED THEN
UPDATE SET DECEDUTI.Sigla = PROVINCE.sigla_provincia;
/
UPDATE -- oracle doesnt have the on update+policy react
(SELECT DECEDUTI.Sigla as OLD, to_number(PROVINCE.Sigla_provincia) as NEW
FROM DECEDUTI
INNER JOIN PROVINCE
ON DECEDUTI.DENOMINAZIONE_PROVINCIA = PROVINCE. DENOMINAZIONE_PROVINCIA
) t
SET t.OLD = t.NEW
/
UPDATE deceduti T
SET T.sigla =
(SELECT distinct sigla_provincia
FROM PROVINCE A
WHERE A.denominazione_provincia = T.denominazione_provincia);
This is what you have:
create table deceduti
(sigla number,
denominazione_provincia unknown_datatype
);
create table province
(sigla_provincia char(2),
denominazione_provincia unknown_datatype
);
Data stored within looks like this (according to datatypes you mentioned):
DECEDUTI:
sigla denominazione_provincia
----- -----------------------
25 1000
null 2000
PROVINCE:
sigla_provincia denominazione_provincia
--------------- -----------------------
AB 1000
X1 2000
As tables are joined on denominazione_provincia, you'd like to - for its value = 1000 - put AB into the deceduti.sigla column. How do you plan to put AB into a NUMBER datatype column? That won't work.
The simplest option is to
alter table deceduti modify sigla (char(2));
but only if sigla column is empty; shouldn't be problem to set it to NULL as it is supposed to accept a new value anyway. If you want to keep some "old" values, then it gets more complicated (creating a new column, store current sigla value in there, empty sigla, change its datatype, move data back, drop new column).
Other options are more complicated, e.g.
make sure that all sigla_provincia values are numeric so that to_number(sigla_provincia) returns a number
update deceduti.sigla values only for denominazione_provincias whose pair in province contains number in sigla_provincia

How Could I Update a table with conditions from other table

I Have the Table "Person" and the table "Fisica" which is the extention of "Person". Both tables are related by the field name Id, and I want to update the tables based on conditions that include both tables.
For example:
Tables:
Persona(Id, Name, Money)
Fisica(Id, LastName, Year)
With data:
Persona(1, X, 5)
Persona(2, A, 10)
Fisica(1, Y, 1990)
Fisica(2, B, 2000)
I want to set Persona.Name=some_Value, Fisica.LastName=other_Value and Fisica.Year=number when Persona.Name='X', so it results
Persona(1, some_Value, 5)
Persona(2, A, 10)
Fisica(1, other_Value, number)
Fisica(2, B, 2000)
I am working in Oracle
You can't update two tables with one statement. So you need two UPDATE statements.
So you have to update one, then the other. The question is, which one first?
It doesn't really matter, but if you update Persona first and change the name, then you have to use the new name when updating Fisica. Like this:
update Persona
set name = 'some_Value'
where name = 'current_Name'
;
update Fisica
set lastname = 'other_Value',
year = number
where id = (
select id
from Persona
where name = 'some_Value'
)
;
If you update Fisica first, you use the old value of name both times, like this:
update Fisica
set lastname = 'other_Value',
year = number
where id = (
select id
from Persona
where name = 'current_Value'
)
;
update Persona
set name = 'some_Value'
where name = 'current_Value'
;
note number has to be replaced with an actual numeric value.
Good coding practice would be to put both statements in the same transaction and commit only if they are both successful.
Though Oracle don't provide such functionality as compare to mysql where we can write query like this:
Update table1 t1, table2 t2 set t2.field2="ABC" where t1.id=t2.id
But you can update multiple tables using single query in Oracle for Views.
So create the view for the above two tables Persona, Fisica and write query as follows:
CREATE OR REPLACE FORCE VIEW "Persona_Fisica" ("PersonaID", "Name", "Money", "FisicaID", "Lastname", "Year") AS
select P.Id as PersonaID,
Name as Name,
Money as Money,
F.Id as FisicaID,
LastName as Lastname,
year as Year
from Persona P,
Fisica F
where P.ID=F.ID
/
Update Persona_Fisica set Name=some_Value, LastName=other_Value,Year=number were Name='X',

SQL-Oracle: Updating table multiple row based on values contained in the same table

I have one table named: ORDERS
this table contains OrderNumber's which belong to the same person and same address lines for that person.
However sometimes the data is inconsistent;
as example looking at the table screenshot: Orders table with bad data to fix -
you all can noticed that orderNumber 1 has a name associated to and addresses line1-2-3-4. sometimes those are all different by some character or even null.
my goal is to update all those 3 lines with one set of data that is already there and set equally all the 3 rows.
to make more clear the result expected should be like this:
enter image description here
i am currently using a MERGE statement to avoid a CURSOR (for loop )
but i am having problems to make it work
here the SQL
MERGE INTO ORDERS O USING
(SELECT
INNER.ORDERNUMBER,
INNER.NAME,
INNER.LINE1,
INNER.LINE2,
INNER.LINE3,
INNER.LINE4
FROM ORDERS INNER
) TEMP
ON( O.ORDERNUMBER = TEMP.ORDERNUMBER )
WHEN MATCHED THEN
UPDATE
SET
O.NAME = TEMP.NAME,
O.LINE1 = TEMP.LINE1,
O.LINE2 = TEMP.LINE2,
O.LINE3 = TEMP.LINE3,
O.LINE4 = TEMP.LINE4;
the biggest issues i am facing is to pick a single row out of the 3 randomly - it does not matter whihc of the data - row i pick to update the line/s
as long i make the records exaclty the same for an order number.
i also used ROWNUM =1 but it in multip[le updates will only output one row and update maybe thousand of lines with the same address and name whihch belong to an order number.
order number is the join column to use ...
kind regards
A simple correlated subquery in an update statement should work:
update orders t1
set (t1.name, t1.line1, t1.line2, t1.line3, t1.line4) =
(select t2.name, t2.line1, t2.line2, t2.line3, t2.line4
from orders t2
where t2.OrderNumber = t1.OrderNumber
and rownum < 2)

Getting original and modified content from a table with an audit trail

I came across the following table structure and I need to perform a certain type of query upon it.
id
first_name
last_name
address
email
audit_parent_id
audit_entry_type
audit_change_date
The last three fields are for the audit trail. There is a convention that says: all original entries have the value "0" for "audit_parent_id" and the value "master" for "audit_entry_type". All the modified entries have the value of their parent id for audit_parent_id" and the value "modified" for the "audit_entry_type".
Now what I want to do is to be able to get the original value and the modified value for a field and I want to make this with less queries possible.
Any ideas? Thank you.
Assuming a simple case, when you want to get the latest adress value change for the record with id 50, this query fits your needs.
select
p.id,
p.adress as original_address,
(select p1.adress from persons p1 where p1.audit_parent_id = p.id order by audit_change_date desc limit 1) as latest_address
from
persons p -- Assuming it's the table name
where
p.id = 50
But this assumes that, even if the address value doesn't change between one audit to the other, it remains the same in the field.
Here's another example, showing all persons that had an address change:
select
p.id,
p.adress as original_address,
(select p1.adress from persons p1 where p1.audit_parent_id = p.id order by audit_change_date desc limit 1) as latest_address
from
persons p -- Assuming it's the table name
where
p.audit_parent_id = 0
and
p.adress not like (select p1.adress from persons p1 where p1.audit_parent_id = p.id order by audit_change_date desc limit 1)
This can be solved with pure SQL in modern Postgres using WITH RECURSIVE.
For PostgreSQL 8.3, this plpgsql function does the job while it is also a decent solution for modern PostgreSQL. You want to ..
get the original value and the modified value for a field
The demo picks first_name as filed:
CREATE OR REPLACE FUNCTION f_get_org_val(integer
, OUT first_name_curr text
, OUT first_name_org text) AS
$func$
DECLARE
_parent_id int;
BEGIN
SELECT INTO first_name_curr, first_name_org, _parent_id
first_name, first_name, audit_parent_id
FROM tbl
WHERE id = $1;
WHILE _parent_id <> 0
LOOP
SELECT INTO first_name_org, _parent_id
first_name, audit_parent_id
FROM tbl
WHERE id = _parent_id;
END LOOP;
END
$func$ LANGUAGE plpgsql;
COMMENT ON FUNCTION f_get_org_val(int) IS 'Get current and original values for id.
$1 .. id';
Call:
SELECT * FROM f_get_org_val(123);
This assumes that all trees have a root node with parent_id = 0. No circular references, or you will end up with an endless loop. You might want to add a counter and exit the loop after x iterations.

How to get one common value from Database using UNION

2 records in above image are from Db, in above table Constraint are (SID and LINE_ITEM_ID),
SID and LINE_ITEM_ID both column are used to find a unique record.
My issues :
I am looking for a query it should fetch the recored from DB depending on conditions
if i search for PART_NUMBER = 'PAU43-IMB-P6'
1. it should fetch one record from DB if search for PART_NUMBER = 'PAU43-IMB-P6', no mater to which SID that item belong to if there is only one recored either under SID =1 or SID = 2.
2. it should fetch one record which is under SID = 2 only, from DB on search for PART_NUMBER = 'PAU43-IMB-P6', if there are 2 items one in SID=1 and other in SID=2.
i am looking for a query which will search for a given part_number depending on Both SID 1 and 2, and it should return value under SID =2 and it can return value under SID=1 only if the there are no records under SID=2 (query has to withstand a load of Million record search).
Thank you
Select *
from Table
where SID||LINE_ITEM_ID = (
select Max(SID)||Max(LINE_ITEM_ID)
from table
where PART_NUMBER = 'PAU43-IMB-P6'
);
If I understand correctly, for each considered LINE_ITEM_ID you want to return only the one with the largest value for SID. This is a common requirement and, as with most things in SQL, can be written in many different ways; the best performing will depend on many factors, not least of which is the SQL product you are using.
Here's one possible approach:
SELECT DISTINCT * -- use a column list
FROM YourTable AS T1
INNER JOIN (
SELECT T2.LINE_ITEM_ID,
MAX(T2.SID) AS max_SID
FROM YourTable AS T2
GROUP
BY T2.LINE_ITEM_ID
) AS DT1 (LINE_ITEM_ID, max_SID)
ON T1.LINE_ITEM_ID = DT1.LINE_ITEM_ID
AND T1.SID = DT1.max_SID;
That said, I don't recall seeing one that relies on the UNION relational operator. You could easily rewrite the above using the INTERSECT relational operator but it would be more verbose.
Well in my case it worked something like this:
select LINE_ITEM_ID,SID,price_1,part_number from (
(select LINE_ITEM_ID,SID,price_1,part_number from Table where SID = 2)
UNION
(select LINE_ITEM_ID,SID,price_1,part_number from Table SID = 1 and line_item_id NOT IN (select LINE_ITEM_ID,SID,price_1,part_number from Table SID = 2)))
This query solved my issue..........