Update one column with two conditions - postgresql

I want to do the following:
UPDATE table1 t1
SET column1 = 10 * t2.column1
FROM table2 t2
WHERE t1.column2 = 'yyy'
UPDATE table1 t1
SET column1 = 10 * t2.column2
FROM table2 t2
WHERE t1.column2 = 'zzz'
Is it possible to keep it in one semantic block?

You could use CASE WHEN .. and apply the update only at the rows with valid condition ( 'yyy' OR 'zzz' )
UPDATE table1 t1
SET column1 = CASE
WHEN t1.column2 = 'yyy' THEN column1 = 10 * t2.column1
WHEN t1.column2 = 'zzz' THEN column1 = 10 * t2.column2
end
FROM table2 t2
WHERE t1.column2 IN ( 'yyy','zzz')

UPDATE table1 t1
SET column1 = (
CASE
WHEN t1.column2 = 'yyy' THEN column1 = 10 * t2.column1
WHEN t1.column2 = 'zzz' THEN column1 = 10 * t2.column2
end)
FROM table2 t2

Related

pl-sql equivalent for t-sql "UPDATE FROM" clause on temp tables

In SQL Server stored procedure I have this code:
UPDATE #tbinforesult
SET prifix = ''
FROM #tbmax t
INNER JOIN #tbinforesult i
ON i.prifix = t.prifix
AND i.PropertyID = t.PropertyID
AND i.GroupID = t.GroupID
AND i.NID <> t.id
What is the equivalent in pl-sql with pl-sql collections not global temporary table?
TSQL :
UPDATE
Table_A
SET
Table_A.col1 = Table_B.col1,
Table_A.col2 = Table_B.col2
FROM
Some_Table Table_A
INNER JOIN
Other_Table Table_B
ON
Table_A.id = Table_B.id
WHERE
Table_A.col3 = 'cool'
PLSQL:
UPDATE table1 t1
SET (name, desc) = (SELECT t2.name, t2.desc
FROM table2 t2
WHERE t1.id = t2.id)
WHERE EXISTS (
SELECT 1
FROM table2 t2
WHERE t1.id = t2.id )
OR:
UPDATE (SELECT t1.id,
t1.name name1,
t1.desc desc1,
t2.name name2,
t2.desc desc2
FROM table1 t1,
table2 t2
WHERE t1.id = t2.id)
SET name1 = name2,
desc1 = desc2
SOURCE :enter link description here

SQL Join 2 tables, return records where only 1 value exists and no other values

I am faced with an issue returning data records. I first wanted to find records where a certain value existed '0000' in a column doing a join for 2 tables. Below is my T-SQL;
SELECT ColumnA, ColumnB, ColumnC
FROM Table1, Table2
WHERE Table1.ColumnB. = Table2.ColumnB
and ColumnC='0000'
This returns the desired data records where '0000' exists at least once in all returned records.
The question I have is, how do I do the same, only returning Distinct records where '0000' is the only value that exists (one or many times) and no other value exists for the returned data records
Many thanks!
SELECT distinct ColumnA, ColumnB
FROM Table1, Table2
WHERE Table1.ColumnB = Table2.ColumnB
and ColumnC = '0000'
except
SELECT distinct ColumnA, ColumnB
FROM Table1, Table2
WHERE Table1.ColumnB = Table2.ColumnB
and ColumnC <> '0000'
if you want to use a join
guessing ColumnC is in Table2
SELECT distinct Table1.ColumnA, Table1.ColumnB, Table2.ColumnC
FROM Table1
JOIN Table2
on Table1.ColumnB = Table2.ColumnB
and Table2.ColumnC = '0000'
left join Table2 exclude
on Table1.ColumnB = exclude.ColumnB
and exclude.ColumnC <> '0000'
where exclude.ColumnB is null
this may be the best performer
SELECT distinct Table1.ColumnA, Table1.ColumnB, Table2.ColumnC
FROM Table1
JOIN Table2
on Table1.ColumnB = Table2.ColumnB
and Table2.ColumnC = '0000'
and not exists (select * from table2 exclude
where exclude.ColumnB = Table1.ColumnB
and exclude.ColumnC <> '0000')
Here's a solution using the ALL keyword
SELECT DISTINCT
columna,
columnb,
columnc
FROM table1 t1
INNER JOIN table2 t2
ON table1.columnb = table2.columnb
WHERE t2.columnc = '0000'
AND t2.columnc = ALL (SELECT columnc
FROM table2 t2Check
WHERE t2.columnb = t2Check.columb)
Here's a Example where I'm using only one table since the joins in your problem aren't actually important.

T-SQL: how to sort table rows based on 2 columns

I'm quite stuck with this problem for sometime now..
How do I sort column A depending on the contents of Column B?
I have this sample:
ID count columnA ColumnB
-----------------------------------
12 1 A B
13 2 C D
14 3 B C
I want to sort it like this:
ID count ColumnA ColumnB
-----------------------------------
12 1 A B
14 3 B C
13 2 C D
so I need to sort the rows if the previous row of ColumnB = the next row of ColumnA
I'm thinking a loop? but can't quite imagine how it will work...
I was thinking it will go like this (maybe)
SELECT
a.ID, a.ColumnA, a.ColumnB
FROM
TableA WITH a (NOLOCK)
LEFT JOIN
TableA b WITH (NOLOCK) ON a.ID = b.ID AND a.counts = b.counts
WHERE
a.columnB = b.ColumnA
the above code isn't working though and I was thinking more on the lines of...
DECLARE #counts int = 1
DECLARE #done int = 0
--WHILE #done = 0
BEGIN
SELECT
a.ID, a.ColumnA, a.ColumnB
FROM
TableA WITH a (NOLOCK)
LEFT JOIN
TableA b WITH (NOLOCK) ON a.ID = b.ID AND a.counts = #counts
WHERE
a.columnB = b.ColumnA
set #count = #count +1
END
If this was a C code, would be easier for me but T-SQL's syntax is making it a bit harder for a noobie like me.
Any help is greatly appreciated!
Edit: sample code
drop table tablea
create table TableA(
id int,
colA varchar(10),
colb varchar(10),
counts int
)
insert INTO TableA
(id, cola, colb, counts)
select 12, 'Bad', 'Cat', 3
insert INTO TableA
(id, cola, colb, counts)
select 13, 'Apple', 'Bad', 1
insert INTO TableA
(id, cola, colb, counts)
select 14, 'Cat', 'Dog', 2
select * FROM TableA
SELECT a.ID, a.ColA, a.ColB
FROM TableA a WITH (NOLOCK)
LEFT JOIN TableA b WITH (NOLOCK)
ON a.ID = b.ID
Where a.colB = b.ColA
ORDER BY a.ColA ASC
you just need to add ORDER BY clause
-- SELECT a.ID, a.ColumnA, a.ColumnB
-- FROM TableA WITH a (NOLOCK)
-- LEFT JOIN TableA b WITH (NOLOCK)
-- ON a.ID = b.ID
-- and a.counts = b.counts
-- Where a.columnB = b.ColumnA
ORDER BY a.ColumnA ASC
This is all you need. Sometimes you have to think simple
select * from table A
order by columnA asc

Displaying the correct condition found in WHERE clause

I have two tables that have the same columns. If a change occurs it is being recorded in table2 and then I compare table1 to table2 and see if they are different. If they are different I conclude there was a change and I would like to display that in my resulting table.
For example:
SELECT t1.name, t1.age, t1.profession, column_changed, old_value, new_value
FROM table1 t1, table2 t2
WHERE t1.column1<>t2.column1
OR t1.column2<>t2.column2
OR t1.column3<>t2.column3
Of course this query isn't correct. I would like the column_changed, old_value, new_value display the relevant values.
Any ideas?
Does Age, name, profession form a primary key (or at least a unique key?):
If so, you could do something like:
SELECT
t1.name, t1.age, t1.profession,
t1.column1 as t1column1, t2.column1 as t2column1,
t1.column2 as t1column2, t2.column2 as t2column2,
FROM
table1 t1, table2 t2
WHERE
(t1.name = t2.name and t1.age = t2.age and t1.profession = t2.profession) and
(
t1.column1<>t2.column1
OR t1.column2<>t2.column2
OR t1.column3<>t2.column3)
Of course, that requires a unique key which is the same across both tables. Also, I clearly changed the results of the query to show all columns instead of just the one that changed. Identifying the one that changed like that in a single T-SQL Query is awkward (but possible) so my recommendation would be to return it like this and depending on your use case have the application/presentation layer handle finding which column changed or just scan it by eye.
If you really want to do it in T-SQL, you could do it with UNIONS, like:
SELECT
t1.name, t1.age, t1.profession,
'column1' as ColumnChanged,
t1.column1 as oldValue,
t2.column1 as newValue
FROM
table1 t1, table2 t2
WHERE
(t1.name = t2.name and t1.age = t2.age and t1.profession = t2.profession) and
t1.column1<>t2.column1
UNION ALL #better peformance than UNION, which would enforce uniqueness
SELECT
t1.name, t1.age, t1.profession,
'column2' as ColumnChanged,
t1.column2 as oldValue,
t2.column2 as newValue
FROM
table1 t1, table2 t2
WHERE
(t1.name = t2.name and t1.age = t2.age and t1.profession = t2.profession) and
t1.column2<>t2.column2
.......
Try this:
Select t1.name, t1.age, t1.profession,
case when t1.column1 <> t2.column1 then 'column1 changed'
when t1.column2 <> t2.column2 then 'column2 changed'
-- and so on...
end as [column_changed],
case when t1.column1 <> t2.column1 then t1.column1
when t1.column2 <> t2.column2 then t1.column2
-- and so on...
end as [old_value],
case when t1.column1 <> t2.column1 then t2.column1
when t1.column2 <> t2.column2 then t2.column2
-- and so on...
end as [new_value]
From table1 t1, table2 t2
Where t1.column1 <> t2.column1
Or t1.column2 <> t2.column2
Or t1.column3 <> t2.column3
After further brain storming this I have concluded that ganders solution works better with slight improvment. The improvement is a while loop and a count variable. We need to have that in case there are several columns changed at once and not just one. It will, however, result in outputting NULL's as well so you can just delete them. Here is the modified query:
WHILE #count<3
BEGIN
Select t1.name, t1.age, t1.profession,
case when t1.column1 <> t2.column1 and #count = 1 then 'column1 changed'
when t1.column2 <> t2.column2 #count = 2 then 'column2 changed'
-- and so on...
end as [column_changed],
case when t1.column1 <> t2.column1 #count = 1 then t1.column1
when t1.column2 <> t2.column2 #count = 2 then t1.column2
-- and so on...
end as [old_value],
case when t1.column1 <> t2.column1 #count = 1 then t2.column1
when t1.column2 <> t2.column2 #count = 2 then t2.column2
-- and so on...
end as [new_value]
From table1 t1, table2 t2
Where t1.column1 <> t2.column1 Or t1.column2 <> t2.column2 Or t1.column3 <> t2.column3
SET #counter = #counter + 1
END
Here's your solution rewritten as a single SELECT statement (or, if you like, #ganders's rewritten to support several changes in the same row):
SELECT
x.column_changed,
t1.column1 AS old_value,
t2.column1 AS new_value
FROM table1 t1
INNER JOIN table2 t2 ON t1.name = t2.name
INNER JOIN (
SELECT 'column1' UNION ALL
SELECT 'column2' UNION ALL
…
) x (column_changed) ON (
x.column_changed = 'column1' AND t1.column1 <> t2.column1 OR
x.column_changed = 'column2' AND t1.column2 <> t2.column2 OR
…
)
I added a join #T2 t2 on t2.name = t1.name to your query using the name column. Making the assumption that it can be used to link the records between the two tables.
select
t1.name, t1.age, t1.profession,
column_change =
case when t1.column1 <> t2.column1 then 'column1'
when t1.column2 <> t2.column2 then 'column2'
when t1.column3 <> t2.column3 then 'column3'
end,
old_value =
case when t1.column1 <> t2.column1 then t1.column1
when t1.column2 <> t2.column2 then t1.column2
when t1.column3 <> t2.column3 then t1.column3
end,
new_value =
case when t1.column1 <> t2.column1 then t2.column1
when t1.column2 <> t2.column2 then t2.column2
when t1.column3 <> t2.column3 then t2.column3
end
from #T1 t1
join #T2 t2 on t2.name = t1.name
where
(t1.column1 <> t2.column1
or t1.column2 <> t2.column2
or t1.column3 <> t2.column3)

ordering by rows

OK so I have a query I am trying to build.. I have 2 tables, table1 has a bunch of regular records as normal with a unique ID (auto increment) and table2 has records that include some of those ids from table1. I am trying to order by the highest records with that same ID in table1.. Heres what I've got:
SELECT * FROM table1
WHERE table1.status = 1
AND (SELECT COUNT(*) FROM table2 WHERE table2.tbl1_id = table1.id)
ORDER BY table1.id DESC
Thanks :)
SELECT table1.id
FROM table1
LEFT JOIN table2 ON table2.tbl1_id = table1.id
WHERE table1.status = 1
GROUP BY table1.id
ORDER BY COUNT(table2.tbl1_id) DESC
Try this:
SELECT a.*, b.cnt
FROM table1 a LEFT JOIN
(
SELECT tbl1_id, COUNT(*) cnt
FROM table2
GROUP BY tbl1_id
) b
ON a.id = b.tbl1_id
WHERE table1.status = 1
ORDER BY cnt DESC