I have an Oracle table X. I want to update Column X in this table with a value from a column in table Y. The columns are the same but there is no join on these tables. I have written a select to get the IDs from table Y. I am just not sure how to update the table X records with each value from the select.
It does not matter which ID goes where because it mock data anyways. I just want to populate column X data from table Y.
Suppose these are your tables; both have ID column, but you can't make a join on it as they have nothing in common.
SQL> select * from x order by id;
ID X
---------- ----------
1 100
2 200
3 300
SQL> select * From y order by id;
I Y
- ----------
A 10
B 20
C 30
D 40
SQL>
You'd want to put Y values (10, 20, 30, ...) into X column (instead of 100, 200, ...). Here's one option: use ROWNUM as a fake ID column which will then be used to establish join between tables. No problem in doing that because you don't really care which value goes where.
SQL> update x set
2 x.x = (with
3 a as (select id, x, rownum rn from x),
4 b as (select id, y, rownum rn from y)
5 select b.y
6 from a join b on a.rn = b.rn
7 where a.id = x.id
8 );
3 rows updated.
New table X contents:
SQL> select * from x order by id;
ID X
---------- ----------
1 10
2 20
3 30
SQL>
Related
I'm looking for a way to merge two tables (or more) and modify/order their numeric id. To put it simply here is what I want to do schematically :
Table example 1 :
Id
Field
4
x
1
x
5
x
3
x
2
x
Table example 2 :
Id
Field
1
x
3
x
5
x
2
x
4
x
Expected result (modify table 1 as 1-2-3-4-5 and table 2 as 6-7-8-9-10 THEN order both id by asc)
Id
Field
1
x
2
x
3
x
4
x
5
x
6
x
7
x
8
x
9
x
10
x
I was aiming for a union tables nested in a select row_number() over (order by id) but I don't really know how to modify table 2 as 6-7-8-9-10 before
Try using this example:
SELECT id, Field FROM t1
UNION ALL
SELECT (SELECT MAX(id) FROM t1) + ROW_NUMBER() OVER (ORDER BY id) AS id, Field
FROM t2
ORDER BY id
fiddle
I have a table like:
id name value
--------------------
1 x 100
1 y 200
1 z 300
2 x 10
2 y abc
2 z 001
3 x 1
...
--------------------
and I need to transform it into something like that:
id x y z
---------------------
1 100 200 300
2 10 abc 001
3 1 ...
---------------------
Names are determined. I could make multiple joins but I'm looking for a more elegant solution.
Use conditional aggregation which in Postgres uses the filter syntax:
select id,
max(value) filter (where name = 'x') as x,
max(value) filter (where name = 'y') as y,
max(value) filter (where name = 'z') as z
from t
group by id;
The additional module tablefunc provides variants of the crosstab() function, which is typically fastest:
SELECT *
FROM crosstab(
'SELECT id, name, value
FROM tbl
ORDER BY 1, 2'
) AS ct (id int, x text, y text, z text);
You seem to have a mix of numbers and strings in your value, so I chose text as output.
See:
PostgreSQL Crosstab Query
I'm having trouble finding the right sql query. I want to select all the rows with a unique x value and if there are rows with the same x value, then I want to select the row with the greatest y value. As an example I've put a part of my database below.
ID x y
1 2 3
2 1 5
3 4 6
4 4 7
5 2 6
The selected rows should then be those with ID 2, 4 and 5.
This is what I've got so far
SELECT *
FROM base
WHERE x IN
(
SELECT x
FROM base
HAVING COUNT(*) > 1
)
But this only results in the rows that occur more than once. I've added the tags R, postgresql and sqldf because I'm working in R with those packages.
Here is a typical way to formulate the query in ANSI SQL:
select b.*
from base b
where not exists (select 1
from base b2
where b2.x = b.x and
b2.y > b.y
);
In Postgres, you would use distinct on for performance:
select distinct on (x) b.*
from base b
order by x, y desc;
You could try this query:
select x, max(y) from base group by x;
And, if you'd also like the id column in the result:
select base.*
from base join (select x, max(y) from base group by x) as maxima
on (base.x = maxima.x and base.y = maxima.max);
Example:
CREATE TABLE tmp(id int, x int ,y int);
INSERT INTO .....
test=# SELECT x, max(y) AS y FROM tmp GROUP BY x;
x | y
---+---
4 | 7
1 | 5
2 | 6
I have a table like this.
ID NAME VALUE
______________
1 A X
2 A Y
3 A Z
4 B X
5 B Y
6 C X
7 C Z
8 D Z
9 E X
And the query:
SELECT * FROM TABLE1 T WHERE T.VALUE IN (X,Z)
This query gives me
ID NAME VALUE
______________
1 A X
3 A Z
4 B X
6 C X
7 C Z
8 D Z
9 E X
But i want to see all values of names which have all params. So, only A and C have both X and Z values, and my desired result is:
ID NAME VALUE
______________
1 A X
2 A Y
3 A Z
6 C X
7 C Z
How can I get the desired result? No matter with sql or with reporting service. Maybe "GROUP BY ..... HAVING" clause will help, but I'm not sure.
By the way I dont know how many params will be in the list.
I realy appreciate any help.
The standard approach would be something like
SELECT id, name, value
FROM table1 a
WHERE name IN (SELECT name
FROM table1 b
WHERE b.value in (x,y)
GROUP BY name
HAVING COUNT(distinct value) = 2)
That would require that you determine how many values are in the list so that you can use a 2 in the HAVING clause if there are 2 elements, a 5 if there are 5 elements, etc. You could also use analytic functions
SELECT id, name, value
FROM (SELECT id,
name,
value,
count(distinct value) over (partition by name) cnt
FROM table1 t1
WHERE t1.value in (x,y))
WHERE cnt = 2
I prefer to structure these "sets within sets" of queries as an aggregatino. I find this is the most flexible approach:
select t.*
from t
where t.name in (select name
from t
group by name
having sum(case when value = 'X' then 1 else 0 end) > 0 and
sum9case when value = 'Y' then 1 else 0 end) > 0
)
The subquery for the in finds all names that have at least one X value and one Y value. Using the same logic, it is easy to adjust for other conditions (X and Y and Z,; X and Y but not Z and so on). The outer query just returns all the rows instead of the names.
I am generating some test-data and use dbms_random. I encountered some strange behavior when using dbms_random in the condition of the JOIN, that I can not explain:
------------------------# test-data (ids 1 .. 3)
With x As (
Select Rownum id From dual
Connect By Rownum <= 3
)
------------------------# end of test-data
Select x.id,
x2.id id2
From x
Join x x2 On ( x2.id = Floor(dbms_random.value(1, 4)) )
Floor(dbms_random.value(1, 4) ) returns a random number out of (1,2,3), so I would have expected all rows of x to be joined with a random row of x2, or maybe always the same random row of x2 in case the random number is evaluated only once.
When trying several times, I get results like that, though:
(1) ID ID2 (2) ID ID2 (3)
---- ---- ---- ---- no rows selected.
1 2 1 3
1 3 2 3
2 2 3 3
2 3
3 2
3 3
What am I missing?
EDIT:
SELECT ROWNUM, FLOOR(dbms_random.VALUE (1, 4))
FROM dual CONNECT BY ROWNUM <= 3
would get the result in this case, but why does the original query behave like that?
To generate three rows with one predictable value and one random value, try this:
SQL> with x as (
2 select rownum id from dual
3 connect by rownum <= 3
4 )
5 , y as (
6 select floor(dbms_random.value(1, 4)) floor_val
7 from dual
8 )
9 select x.id,
10 y.floor_val
11 from x
12 cross join y
13 /
ID FLOOR_VAL
---------- ----------
1 2
2 3
3 2
SQL
edit
Why did your original query return an inconsistent set of rows?
Well, without the random bit in the ON clause your query was basically a CROSS JOIN of X against X - it would have returned nine rows (at least it would have if the syntax had allowed it). Each of those nine rows executes a call to DBMS_RANDOM.VALUE(). Only when the random value matches the current value of X2.ID is the row included in the result set. Consequently the query can return 0-9 rows, randomly.
Your solution is obviously simpler - I didn't refactor enough :)