I want to assign the name of table1 in table 2 thanks - sql

UPDATE table1, (select top 1 [ID],chef,formateur,techni from table1 order by Num desc)
AS x SET table2.ID = x.[ID], table2.Nom = x.[chef], table2.Nom = x.[formateur],
table2.Nom = x.[techni]
WHERE table2.mission="chef" and table2.mission="Formateur" and table2.mission="techni" ;
returns
table2 table 1
ID | mission |Nom| ID |chef|Formateur|techni|
-------------------------------- ----------------------------
1 | chef | | 1 |nom1| nom2 | nom3|
2 | Formateur | | **Result**
3 | techni | | ID | mission | Nom|
--------------------------
1 | chef | nom1|
2 | Formateur| nom2|
3 | techni | nom3|
I want to assign the name of table1 in table 2.
Please i need your help :)

Data structure does not make sense. Table2 has only 3 records?
Your attempted example is updating Table1 when it appears you really want to update Table2. Why do you want to pull from just last record of Table1?
But try:
UPDATE Table2,
(SELECT TOP 1 Table1.ID, Table1.chef, Table1.formateur, Table1.techni
FROM Table1 ORDER BY Table1.ID DESC) AS Q
SET Table2.nom = Switch([mission]="chef",[chef],[mission]="formateur",[formateur],[mission]="techni",[techni]);

Related

Linking tables on multiple criteria

I've got myself in a bit of a mess on something I'm doing where I'm trying to get two tables linked together based on multiple bits of info.
I want to link one table to another based on the basic rules of(in this hierarchy)
where main linking is where orderid matches between the two tables
records from table 2 where valid=Y,
from those i want the valid records which has the highest seqn1 number and then from those the one that has the highest seqn2 value
table1
orderid | date | otherinfo
223344 | 22/10/2020 | okokkokokooeodijjf
table2
orderid | seqn1 | seqn2 | valid | additonaldata
223344 | 1 | 3 | y | sdfsfsf
223344 | 2 | 1 | y | sffferfr
223344 | 2 | 2 | y | sfrfrefr -- This row
223344 | 2 | 3 | n | rfrg66rr
223344 | 2 | 4 | n | adwere
223344 | 3 | 4 | n | adwere
so would want the final record to be
orderid | date | otherinfo | seqn1 | seqn2 | valid | additonaldata
223344 | 22/10/2020 | okokkokokooeodijjf | 2 | 2 | y | sfrfrefr
I started off with the code below but I'm not sure I'm doing it right and I can't seem to get it to pay attention to the valid flag when i try to add it in.
SELECT * FROM table1
left JOIN table2
ON table1.orderid = table2.orderid
AND table2.seqn1 = (SELECT MAX(table2.seqn1) FROM table2 WHERE table1.orderid = table2.orderid)
AND table2.seqn2 = (SELECT MAX(table2.seqn2) FROM table2 WHERE table1.orderid = table2.orderid
AND table2.seqn1 = (SELECT MAX(table2.seqn1) FROM table2 WHERE table1.orderid = table2.orderid))
Could someone help me amend the code please.
Use row_number analytic function with partition by orderid and order by SEQNRs in the order you need. No need for multiple subselects. To add more selections for the single row, use CASE to map your values to numbers and order by them also.
Fiddle here.
with l as (
select *,
rank() over(partition by orderid order by seqn1 desc, seqn2 desc) as rn
from line
where valid = 'y'
)
select *
from header as h
join l
on h.orderid = l.orderid
and l.rn = 1
How about something like this:
;
with cte_table2 as
(
SELECT ordered
,MAX(seqn1) as seqn1
,MAX(seqn2) as seqn2
FROM table2
where valid = 'y'
group by ordered --check if you need to add 'valid' to the group by but I don't think so.
)
SELECT
t1.*
,t3.otherinfo
--,t3.[OtherFields]
from table1 t1
inner join cte_table2 t2 on t1.orderid = t2.orderid -- first match on id
left join table2 t3 on t3.orderid = t2.orderid and t3.seqn1 = t2.seqn1 and t3.seqn2 = t2.seqn2

How to do an outer join with full result between two tables

I have two tables:
TABLE1
id_attr
-------
1
2
3
TABLE2
id | id_attr | val
----------------------
10 | 1 | A
10 | 2 | B
As a result I want a table that show:
RESULT
id | id_attr | val
----------------------
10 | 1 | A
10 | 2 | B
10 | 3 | NULL
So I want the row with id=10 and id_attr=3 also when id_Attr=3 is missing in TABLE2 (and I know that because I have a NULL value (or something else) in the val column of RESULT.
NB: I could have others ids in table2. For example, after insert this row on table2: {11,1,A}, as RESULT I want:
id | id_attr | val
----------------------
10 | 1 | A
10 | 2 | B
10 | 3 | NULL
11 | 1 | A
11 | 2 | NULL
11 | 3 | NULL
So, for every id, I want always the match with all id_attr.
Your specific example only has one id, so you can use the following:
select t2.id, t2.id_attr, t2.val
from table2 t2
union all
select 10, t1.id_attr, NULL
from table1 t1
where not exists (select 1 from table2 t2 where t2.id_attr = t1.id_attr);
EDIT:
You can get all combinations of attributes and ids in the following way. Use a cross join to create all the rows you want and then a left join to bring in the data you want:
select i.id, t1.id_attr, t2.val
from (select distinct id from table2) i cross join
table1 t1 left join
table2 t2
on t2.id = i.id and t2.id_attr = t1.id_attr;
It sounds like you want to do just an outer join on id_attr instead of id.
select * from table2 t2
left outer join table1 t1 on t2.id_attr = t1.id_attr;

SQL Join and Update query

So I want to update the action column to the value 'Insert' inside Table1, if the ids from Table1 and Table2 match but the UIDs dont.
Right now my query looks like
UPDATE Table1
SET Action = 'Insert'
FROM Table1
JOIN Table2 ON Table1.id = Table2.id
AND Table1.UID <> Table2.UID
This is setting the action to Insert even if the UIDs don't differ, can someone help me and explain why this is behaving this way?
My assumption is you have something like this:
Table1
id | UID | action
1 | 1 | bla
1 | 2 | bleck
1 | 3 | floop
Table2
id | UID | action
1 | 1 | bla
1 | 2 | bleck
1 | 4 | floop
And you hope to update the third row in Table1 because the UID isn't in Table2.
The problem is that the third row in Table2 matches all rows in Table1 on your condition: Table1.id = Table2.id AND Table1.UID <> Table2.UID
Which means that in this case, all rows in Table1 will be updated with Action = 'Insert'
I think you want to use NOT EXISTS():
UPDATE T1
SET Action = 'Insert'
FROM Table1 T1
WHERE NOT EXISTS (SELECT *
FROM Table2 T2
WHERE T1.id = T2.id
AND T1.UID = T2.UID)
Edit, more explanation on why the join fails:
This is a many to many join, meaning that the condition allows multiple rows from Table1 to match multiple rows from Table2
The easiest way to see this in action is to change your update to a select:
SELECT *
FROM Table1 T1
JOIN Table2 T2 on T1.id = T2.id
and T1.UID <> T2.UID
You may expect this to result in:
id | UID | action id | UID | action
1 | 3 | floop 1 | 4 | floop
But really it will result in:
id | UID | action id | UID | action
1 | 1 | bla 1 | 4 | floop
1 | 2 | bleck 1 | 4 | floop
1 | 3 | floop 1 | 4 | floop
This means that when you update you are hitting all the rows for id = 1 in Table1
If you put condition Table1.UID <> Table2.UID into WHERE clause, doesn't it solve your problem?
UPDATE Table1
SET Action = 'Insert'
FROM Table1
JOIN Table2 ON Table1.id = Table2.id
WHERE Table1.UID <> Table2.UID

Delete subtable from a table, SQL

What is the most clever way to delete tuples from table1, that are in the second table,
if the second table is not a part of initial database, but a result of some really big query?
table1 *this table is a result of some query
------------- -------------
| id1 | id2 | | id1 | id2 |
------------- -------------
| 1 2 | | 5 6 |
| 3 4 | | 1 2 |
| 5 6 | | 11 12 |
| 7 8 | -------------
| 9 10 |
| 11 12 |
| 13 14 |
-------------
I came up with
delete from table1
where id1 in (select id1 from ( really long query to get a second table))
and id2 in (select id2 from (the same really long query to get a second table));
It works, but I feel like I'm doing it way too wrong, and not keeping the query DRY.
And would the way you suggest work the same if table1 had an additional column, for example "somecol"?
IMO, You can use EXISTS statement like this:
DELETE FROM table1
WHERE EXISTS (
SELECT 1
FROM (<your long query>) AS dt
WHERE table1.id1 = dt.id1
AND table1.id2 = dt.id2);
[SQL Fiddle Sample]
One method is to use with, delete and exists:
with secondtable as (
<your query here>
)
delete from table1
where exists (select 1
from secondtable st
where table1.id1 = st.id1 and table1.id2 = st.id2
);
A Correlated Subquery using EXISTS allows matching multiple columns:
delete
from table1
where exists
( select * from
(
"really long query"
) as t2
where table1.id1 = t2.id1 -- correlating inner and outer table
and table1.id2 = t2.id2 -- similar to a join-condition
)

Postgres: "Recursive" query with Array

I have a database (that I can't change) one table looks like that:
| ID:integer | fk:integer | next:[integer array] |
--------------------------------------------------
| 1 | 711 | {4} |
| 2 | 712 | {6} |
| 3 | 788 | |
| 4 | 799 | {7} |
--------------------------------------------------
Now I try to define one Query that as first row the data with ID = 1 and as next rows, all data with the ID that are in the integer array next ({4}) so that my query returns:
| ID:integer | fk:integer | next:[integer array] |
--------------------------------------------------
| 1 | 711 | {4} |
| 4 | 799 | {7} |
--------------------------------------------------
But then stops, so it only results the element with the specified ID and it's next elements.
I tried sth. like this, but I can't get it to work:
SELECT * FROM tablenm WHERE ID = ANY(SELECT next FROM tablenm WHERE ID = 1) AND ID = 1
The current Workaround I use is to first use this query:
SELECT * FROM tablenm WHERE ID = 1
And then for each element in the Array I run the same query with the IDs in a loop programmatically, but this looks like a dirty hack and I hope there is a solutions for this with 1 SQL statement.
You can use = ANY(array) in the JOIN condition:
SELECT t2.*
FROM tbl t1
JOIN tbl t2 ON t2.id = ANY(t1.next)
OR t2.id = t1.id -- add first row
WHERE t1.id = 1 -- enter id to filter on once
ORDER BY (t2.id <> t1.id); -- "first row the data with ID = ?"
Should be fastest.
As #Daniel explained, this form (like your query) includes the first row only once.
If you want a "shorter query":
SELECT t2.*
FROM tbl t1
JOIN tbl t2 ON t2.id = ANY(t1.next || t1.id) -- append id to array
WHERE t1.id = 1; -- not sure if you need ORDER BY
Shorter, but not faster than the first form, because this will be expanded to an equivalent of the first form internally. Test performance with EXPLAIN ANALYZE.
It should be noted that next can even be NULL, because:
SELECT NULL::int[] || 5 --> '{5}'
This doesn't require recursion, just array un-nesting.
This should work:
select * from tablename where id=1
UNION ALL
select * from tablename where id
in (select unnest(next) from tablename where id=1);