Postgres update with an inner join across 2 tables? - sql

I have 3 tables in my local Postgres database:
[myschema].[animals]
--------------------
animal_id
animal_attrib_type_id (foreign key to [myschema].[animal_attrib_types])
animal_attrib_value_id (foreign key to [myschema].[animal_attrib_values])
[myschema].[animal_attrib_types]
--------------------------------
animal_attrib_type_id
animal_attrib_type_name
[myschema].[animal_attrib_values]
--------------------------------
animal_attrib_value_id
animal_attrib_value_name
At runtime I will know the animal_id. I need to run SQL to update the animal_attribute_value_name associated with this item, so something like:
UPDATE
animal_attribute_values aav
SET
aav.animal_attribute_value_name = 'Some new value'
WHERE
# Somehow join from the provided animal_id???
I may have to do some kind of nested SELECT or INNER JOIN inside the WHERE clause, but not sure how to do this. Thanks in advance!
Edit:
Let's say I have an animal record with the following values:
[myschema].[animals]
--------------------
animal_id = 458
animal_attrib_type_id = 38
animal_attrib_value_id = 23
And the corresponding animal_attrib_value (with id = 23) has the following values:
[myschema].[animal_attrib_values]
--------------------------------
animal_attrib_value_id = 23
animal_attrib_value_name = 'I am some value that needs to be changed.'
At runtime, I only have the animal_id (458). I need to look up the corresponding animal_attrib_value (23) and change its animal_attrib_value_name to 'Some new value', all inside of a single UPDATE statement.

UPDATE
animal_attribute_values aav
SET
animal_attribute_value_name = 'Some new value'
FROM animals aa
WHERE aa.animal_id = 458
AND aa.animal_attrib_value_id = aav.animal_attrib_value_id
;

are you asking something like this right..?
update animal_attribute_values aav
set aav.animal_attribute_value_name = 'Some new value'
where aav.animal_attrib_value_id in (
select a.animal_attrib_value_id where a.animal_id=458)
try this..

Related

Using the alias from the select in the WHERE clause leads to error : "Missing FROM-clause entry for a table"

I'm a newbie at SQL and I can't manage to make the following sql query to work ! There seem to be an issue with the alias and the where clause but I don't find any workaround...
Could someone enlighten me ?
Table t_adresse (SCHEMA ab)
-------
ad_nomvoie | ad_numero | action |
Privet Drive 4
KameHouse St 12
Table t_adresse (SCHEMA poma)
-------
ad_nomvoie | ad_numero |
Privet Drive 8
KameHouse St 12
After my update I would like to get this result below (if I had to run the select "defined" by "req1") :
-------
ad_nomvoie (from ab) | ad_numero (from ab) | ad_nomvoie (from poma) | ad_numero (from poma) | action
Privet Drive 4 Privet Drive 8 M
KameHouse St 12 KameHouse St 12
.
WITH req1 as (SELECT AA.ad_nomvoie, AA.ad_numero, BB.ad_nomvoie, BB.ad_numero, AA.action
FROM ab.t_adresse as AA
INNER JOIN poma.t_adresse as BB
ON AA.ad_code = BB.ad_code
ORDER BY AA.ad_numero ASC)
UPDATE ab.t_adresse
SET "action" = 'M'
FROM req1
WHERE AA.ad_nomvoie = BB.ad_nomvoie
AND AA.ad_numero == BB.ad_numero
Presumably, you want the CTE joined to the table being updated. That would be:
WITH req1 as (
SELECT aa.ad_nomvoie, aa.ad_numero, pa.ad_nomvoie, pa.ad_numero, aa.action
FROM ab.t_adresse aa INNER JOIN
poma.t_adresse pa
ON aa.ad_code = pa.ad_code
)
UPDATE ab.t_adresse a
SET action = 'M'
FROM req1
WHERE a.ad_nomvoie = req1.ad_nomvoie AND
a.ad_numero = req1.ad_numero;
Note:
The order by is superfluous in the CTE.
Don't escape identifiers with double quotes. If you created the table with double quotes, then re-create the table! They just clutter queries.
Use meaningful table aliases. pa is an abbreviation of the table name; bb is meaningless.
I would guess that the CTE is not necessary. So, perhaps this does what you want:
UPDATE ab.t_adresse a
SET action = 'M'
FROM poma.t_adresse as pa
WHERE a.ad_code = pa.ad_code;
However, without sample data and a clear explanation of the logic, I'm not 100% sure this is equivalent.
I think I have a solution for you. Please check =>
MY TABLE STUCTURE
CREATE TABLE t_adresseAA(ad_code varchar(20),ad_nomvoie varchar(20),ad_numero varchar(20),action varchar(20));
CREATE TABLE t_adresseBB(ad_code varchar(20),ad_nomvoie varchar(20),ad_numero varchar(20),action varchar(20));
INSERT DATA
INSERT INTO t_adresseAA VALUES('001','sdfsd','werwer','Action1');
INSERT INTO t_adresseAA VALUES('002','sdfsd111','werwer222','Action2');
INSERT INTO t_adresseAA VALUES('003','sdfsd111','werwer222','Action3');
INSERT INTO t_adresseBB VALUES('001','sdfsd','werwer','Action1');
INSERT INTO t_adresseBB VALUES('004','sdfsd111','werwer222','Action2');
INSERT INTO t_adresseBB VALUES('005','sdfsd111','werwer222','Action3');
FINAL QUERY
WITH req1 as (SELECT AA.ad_nomvoie ad_nomvoieA, AA.ad_numero ad_numeroA, BB.ad_nomvoie, BB.ad_numero, AA.action
FROM t_adresseAA as AA
INNER JOIN t_adresseBB as BB
ON AA.ad_code = BB.ad_code
)
UPDATE t_adresseAA
SET "action" = 'M'
FROM req1
WHERE req1.ad_nomvoieA = t_adresseAA.ad_nomvoie
AND req1.ad_numeroA = t_adresseAA.ad_numero;
SELECT * FROM t_adresseAA; -- This line is for checking that the data is updated or not.
NOTE: Code is written in postgresql v11. You check the code in DB Fiddle

Trying to display id of table 1 as it relates to table 3

I have three tables: exfillocation, phishkit, snapshot. We need to be able to query exfillocation.filename and print the related snapshot.id, which requires traversing the phishkit table.
exfillocation.phishkit_id is related to phishkit.id as a foreign key.
Table exfillocation schema:
id exfil_location phishkit_id
== ========= ============
1 ['open.txt'] 7442
2 ['bot.txt'] 9931
phishkit.snapshot_id is related to snapshot.id as a foreign key.
Phishkit schema:
id snapshot_id md5
=== ============ =====
7442 1492 f4a3954e39b90c02f4a3954e39b90c02
9931 1661 e048f240ad0845b50abe8df9124ce3fb
Snapshot schema:
id asn url
=== ====== =============
1661 123 badwebsite.malicious.com
1492 31 haxx0rs.hacking.com
I've tried reading postgresql's four different JOIN methods as well as the UNION method, but I don't seem to get the snapshot_id column returned.
I tried something awkward this this:
SELECT exfil_location, found_in_file, phishkit_id
FROM public.lookup_exfillocation
FULL OUTER JOIN public.lookup_phishkit
ON public.lookup_exfillocation.phishkit_id = public.lookup_phishkit.id
FULL OUTER JOIN public.lookup_snapshot
ON public.lookup_phishkit.snapshot_id = public.lookup_snapshot.id WHERE exfil_location::text NOT LIKE ('__script.txt__') ORDER BY phishkit_id;
I expected to see the related lookup_snapshot.id and the related lookup_phishkit.id, which neither showed.
I accidentally found the solution. It came down to what columns I was SELECTing. Using a * showed all columns in the JOIN statements. Then I picked from the columns needed. The query looks like:
FROM public.lookup_exfillocation
FULL OUTER JOIN public.lookup_phishkit
ON public.lookup_exfillocation.phishkit_id = public.lookup_phishkit.id
FULL OUTER JOIN public.lookup_snapshot
ON public.lookup_phishkit.snapshot_id = public.lookup_snapshot.id WHERE exfil_location::text NOT LIKE ('__script.txt__') ORDER BY phishkit_id;```

SQL Views - Modify Returned Result

I'm a little stuck here. I'm trying to modify a returned View based on a condition. I'm fairly green on SQL and am having a bit of difficultly with the returned result. Heres a partial component of the view I wrote:
WITH A AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY fkidContract,fkidTemplateItem ORDER BY bStdActive DESC, dtdateplanned ASC) AS RANK,
tblWorkItems.fkidContract AS ContractNo,
....
FROM tblWorkItems
WHERE fkidTemplateItem IN
(2895,2905,2915,2907,2908,
2909,3047,2930,2923,2969,
2968,2919,2935,2936,2927,
2970,2979)
AND ...
)
SELECT * FROM A WHERE RANK = 1
The return result is similar to the following:
ContractNo| ItemNumber | Planned | Complete
001 | 100 | 01/01/1900 | 02/01/1900
001 | 101 | 03/04/1900 | 02/01/1901
001 | 102 | 03/06/1901 | 02/08/1900
002 | 100 | 01/03/1911 | 02/08/1913
This gives me the results I expect, but due a nightmare crystal report I need to alter this view slightly. I want to take this returned result set and modify an existing column with a value pulled from the same table and the same Contract relationship, something like the following:
UPDATE A
SET A.Completed = ( SELECT R.Completed
FROM myTable R
INNER JOIN A
ON A.ContractNo = R.ContractNo
WHERE A.ItemNumber = 100 AND R.ItemNumber = 101
)
What I'm trying to do is modify the "Completed Date" of one task and make it the complete date of another task if they both share the same ContractNo field value.
I'm not sure about the ItemNumber relationships between A and R (perhaps it was just for testing...), but it seems like you don't really want to UPDATE anything, but you want to use a different value under some circumstances. So, maybe you just want to change the non-cte part of your query to something like:
SELECT A.ContractNo, A.ItemNumber, A.Planned,
COALESCE(R.Completed,A.Completed) as Completed
FROM A
LEFT OUTER JOIN myTable R
ON A.ContractNo = R.ContractNo
AND A.ItemNumber = 100 AND R.ItemNumber = 101 -- I'm not sure about this part
WHERE A.Rank = 1
So it turns out that actually reading the vendor documentation helps :)
SELECT
column1,
column2 =
case
when date > 1999 then 'some value'
when date < 1999 then 'other value'
else 'back to the future'
end
FROM ....
For reference, the total query did a triple inner join over ~5 million records and this case statement was surprisingly performant.
I suggest that this gets closed as a duplicate.

Postgres update with an inner join across 3 tables?

This morning I asked this very similar question, and it was answered beautifully.
However, after reviewing the play, I see that my actual problem is slightly more complicated than what I described in that question. Basically, I have 3 Postgres tables:
[myschema].[animals]
--------------------
animal_id
animal_attrib_type_id (foreign key to [myschema].[animal_attrib_types])
animal_attrib_value_id (foreign key to [myschema].[animal_attrib_values])
[myschema].[animal_attrib_types]
--------------------------------
animal_attrib_type_id
animal_attrib_type_name
[myschema].[animal_attrib_values]
--------------------------------
animal_attrib_value_id
animal_attrib_value_name
So, I might have an animal record like so:
[myschema].[animals]
--------------------
animal_id = 458
animal_attrib_type_id = 38
animal_attrib_value_id = 23
And the corresponding animal_attrib_type (with id = 38) has the following values:
[myschema].[animal_attrib_types]
--------------------------------
animal_attrib_type_id = 38
animal_attrib_type_name = 'animals.should-make-noise'
And the corresponding animal_attrib_value (with id = 23) has the following values:
[myschema].[animal_attrib_values]
--------------------------------
animal_attrib_type_id = 23
animal_attrib_type_name = 'true'
So, the same animal record can have multiple type/value pairs. In this case the animal had an animal_attrib_type_name of "animals.should-make-noise" corresponding to an animal_attrib_value_name of "true".
At runtime, I will only have the animal_id (i.e, 458) and animal_attrib_type_id (i.e, 38). I need to be able to look up the appropriate animal_attrib_value_name corresponding to that given animal_id and animal_attrib_type_id only, and then update its value to some static text ('true' or 'false'); all from within the same UPDATE statement.
The answer in the above-referenced question was correct for the problem I stated, but since the same animal has 0+ type/value combos I actually need a slightly different SQL statement. Thanks in advance!
Make use of the FROM clause in the PostgreSQL UPDATE command. This is usually cleaner and faster.
UPDATE animal_attrib_values av
SET animal_attrib_value_name = 'true'
FROM animals a
WHERE a.animal_id = 458
AND a.animal_attrib_type_id = 38
AND a.animal_attrib_value_id = av.animal_attrib_value_id;
Since we already know the animal_attrib_type_id we don't have to include the third table animal_attrib_types at all. We could join to it additionally if needed ...
Also, do not table-qualify SET items in an UPDATE. That's a syntax error. I quote the manual on said page:
Do not include the table's name in the specification of a target
column — for example, UPDATE tab SET tab.col = 1 is invalid.
Bold emphasis mine.
The below SQL should do what you are asking:
UPDATE animal_attrib_values aav
SET animal_attrib_value_name= 'true'
WHERE aav.animal_attrib_value_id = (
SELECT a.animal_attrib_value_id
FROM animals a
WHERE a.animal_id = 458
AND a.animal_attrib_type_id = 38
)
;

How to convert this sql script in linq to entity?

SELECT * INTO #Loc1
FROM LocaleStringResource
Where LanguageId = 1
SELECT * INTO #Loc2
FROM LocaleStringResource
Where LanguageId = 3
SELECT Loc1.Id, Loc1.LanguageId, Loc1.ResourceName, Loc1.ResourceValue,
Loc2.Id, Loc2.LanguageId, Loc2.ResourceName, Loc2.ResourceValue
FROM #Loc1 AS Loc1 INNER JOIN
#Loc2 AS Loc2 ON Loc1.ResourceName = Loc2.ResourceName
Update:
I have a table named - LocaleStringResource.
Columns: Id, LanguageId, ResourceName, ResourceValue,
Suppose I have 2 language in my system.
Id Language
1 English
3 Bangla
Id LanguageId ResourceName ResourceValue
1 1 Admin.Address Address
2 1 Admin.Phone Phone
51 3 Admin.Address SpAddress
51 3 Admin.Phone SpPhone
By ResourceName i get what the value is for choosen language. So from admin page i want to see for by ResourceName what are ResourceValue for both languages.
So I need a resultset which returns something like this.
ResourceName ResourceValue As EnglishText ResourceValue As SpanishText
Admin.Address Address SpAddress
Admin.Phone Phone SpPhone
var loc1 = Context.ObjectSet<LocaleStringResource>.Where(r => r.LanguageId == 1);
var loc2 = Context.ObjectSet<LocaleStringResource>.Where(r => r.LanguageId == 2);
var result = (
from l1 in loc1
join l2 in loc2 on l1.ResourceName equals l2.ResourceName
select new{
ResourceName = l1.ResourceName,
EnglishText = l1.ResourceValue,
SpanishText = l2.ResourceValue
}
).ToList();
Entity framework doesn't support temporary tables and SELECT INTO construction so you cannot directly convert it. You must go through the logic of your application and change it so that it can be used with EF or you must wrap this code into stored procedure and call it from EF (btw. you will have to use column aliases for result set because column names must not be the same when used with EF).