My basic question has to do with updating multiple columns at once from specified values in my query. The reason I want to do this is that I am updating my values from a ginormous table so I only want to query it once in order to reduce run time. Here is an example of an example select statement that returns the value I want for just one of the columns I need to update:
select a.Value
from Table1
left outer join
(
select ID, FilterCol1, FilterCol2, Value
from Table2
) a on a.ID = Table1.ID
where {Condition1a on FilterCol1}
and {Condition2a on FilterCol2}
In order to update multiple columns at once I would like to be able do something like this (but it returns NULL):
Update T1
set T1Value1 = (select a.Value where {Condition1a on FilterCol1}
and {Condition2a on FilterCol2)
,T1Value2 = (select a.Value where {Condition1b on FilterCol1}
and {Condition2b on FilterCol2})
from Table1 T1
left outer join
(
select ID, FilterCol1, FilterCol2, Value
from Table2
) a on a.ID = Table1.ID
Any help figuring this out would be greatly appreciated, let me know if you have any questions or if I made any errors. Thanks!
EDIT: I think I have identified the problem, but I'm not sure of a solution yet. I think seeing the issue requires a little more context: The select from table 2 is actually an unpivot on a wide table. This means that when the left outer join is applied, there will be multiple rows for a given ID. What the case statement that Earl suggested seems to be doing (and I assume this is happening with the where clause as well) is comparing my Conditions to only the first row of the columns from a. Since my conditions are meant to help determine which of the rows from a is chosen, they will always evaluate false for the first row (I know this just from what I know about the data), hence my perpetual NULL values. Does anyone know of a workaround to look at the other rows in a?
UPDATE T1
SET T1Value1 = CASE WHEN (FilterCol1 = Condition1a AND FilterCol2 = Condition2a) THEN a.Value END,
T1Value2 = CASE WHEN (FilterCol1 = Condition1b AND FilterCol2 = Condition2b) THEN a.Value END
FROM Table1 T1
left outer join
(
select ID, FilterCol1, FilterCol2, Value
) a on a.ID = Table1.ID
Related
I'm attempting to update a table column based on the st_contains() results using two other tables. The code I've written below returns too many results. What do I need to change to make this work?
UPDATE "PRIMARY_USE_DESC"."CAD_Primary_Desc" SET "Parcel_Desc" = 'PARK'
WHERE (
SELECT geom_poly
FROM "Buda_Parks" t1
LEFT JOIN (
SELECT geom_point
FROM "HCAD_POINTS"
) t2 ON ST_Contains(t1.geom_poly, t2.geom_point)
) IS NOT NULL
Ok, I figured it out. Posting it here in case someone else has this question.
UPDATE "PRIMARY_USE_DESC"."CAD_Primary_Desc"
Set "Parcel_Desc" = 'PARK'
FROM
(select geom_poly from "Buda_Parks" t1
left join (SELECT geom_point FROM "HCAD_POINTS") t2 on ST_Contains(geom_poly,geom_point)) t3
WHERE ST_Contains(geom_poly, geom_point)
I have two unrelated tables that I want to do an LEFT JOIN on, I only want 1 column from the LEFT table but the entire entity (which I intend to update if its present or create if not) from the right.
Simplified version of tables:
TABLE1
id, type, data
TABLE2
id, type, and, other, stuff
Current JPQL:
SELECT T1.type,
(SELECT T2
FROM TABLE2 T2
WHERE T2.id = T1.id
AND T2.type = T1.type)
FROM T1
WHERE T1.id = :ID
I am currently getting some sort of logical union error...
Can this been done or should I just use separate queries?
The exact exception is:
Caused by: java.lang.ClassCastException: org.apache.openjpa.jdbc.sql.LogicalUnion$UnionSelect incompatible with org.apache.openjpa.jdbc.sql.SelectImpl
The Java code I use follows:
Query q = this.em.createQuery(jql, Tuple.class);
q.setParameter("ID", id);
#SuppressWarnings("unchecked")
List<Tuple> result = q.getResultList();
The subquery is not essential to my solution - it's just the only form that was parseable - a regular SQL LEFT JOIN wasn't. In words what I am trying to do is for a given ID in TABLE1 find all rows in TABLE2 that have the same ID and type or null if there is no row. Later code will create rows in TABLE2 where there are none for the id and type. I'm expecting 2-3 types per ID in TABLE1 and about half the time for a matching row in TABLE2.
The thing is: I've got this lookup table which I use as a dictionary to create a new column that 'translates' the meaning of a certain column of codes.
Let's say:
Table1:
ID Code
01 A
02 B
03 C
Lookup_table (dictionary):
Code Meaning
A Alice
B Bob
C Charlie
I can easily make a JOIN to create a new table (Table2) with the new column 'Meaning' added to it:
Table2:
CREATE TABLE Table2 AS SELECT T1.ID, T1.Code, LKP.Meaning
FROM Table1 AS T1
LEFT OUTER JOIN Lookup_table AS LKP
ON (T1.Code = LKP.Code);
But: What to do if a new Code appears in Table1 (e.g. ("04", "D") ) and there is no translation for it in Lookup_table? (given you want to avoid a NULL as an answer) Is there a way to obtain something like 'others' in Meaning to answer to this situation?
Thanks!
You could use COALESCE() in order to achieve that. COALESCE() takes two arguments, while selecting the first argument that is not NULL.
You can modify your query as follows:
CREATE TABLE Table2 AS
SELECT
T1.ID AS ID,
T1.Code AS Code,
COALESCE(LKP.Meaning,'others') AS Meaning
FROM Table1 AS T1
LEFT OUTER JOIN Lookup_table AS LKP
ON (T1.Code = LKP.Code);
In your case this would mean to put LKP.Meaning as first parameter. If this value is NULL, it will use 'others' as displayed.
See also the Hive Documentation.
In SQL Server, I know for sure that the following query;
SELECT things.*
FROM things
LEFT OUTER JOIN (
SELECT thingreadings.thingid, reading
FROM thingreadings
INNER JOIN things on thingreadings.thingid = things.id
ORDER BY reading DESC LIMIT 1) AS readings
ON things.id = readings.thingid
WHERE things.id = '1'
Would join against thingreadings only once the WHERE id = 1 had restricted the record set down. It left joins against just one row. However in order for performance to be acceptable in postgres, I have to add the WHERE id= 1 to the INNER JOIN things on thingreadings.thingid = things.id line too.
This isn't ideal; is it possible to force postgres to know that what I am joining against is only one row without explicitly adding the WHERE clauses everywhere?
An example of this problem can be seen here;
I am trying to recreate the following query in a more efficient way;
SELECT things.id, things.name,
(SELECT thingreadings.id FROM thingreadings WHERE thingid = things.id ORDER BY id DESC LIMIT 1),
(SELECT thingreadings.reading FROM thingreadings WHERE thingid = things.id ORDER BY id DESC LIMIT 1)
FROM things
WHERE id IN (1,2)
http://sqlfiddle.com/#!15/a172c/2
Not really sure why you did all that work. Isn't the inner query enough?
SELECT t.*
FROM thingreadings tr
INNER JOIN things t on tr.thingid = t.id AND t.id = '1'
ORDER BY tr.reading DESC
LIMIT 1;
sqlfiddle demo
When you want to select the latest value for each thingID, you can do:
SELECT t.*,a.reading
FROM things t
INNER JOIN (
SELECT t1.*
FROM thingreadings t1
LEFT JOIN thingreadings t2
ON (t1.thingid = t2.thingid AND t1.reading < t2.reading)
WHERE t2.thingid IS NULL
) a ON a.thingid = t.id
sqlfiddle demo
The derived table gets you the record with the most recent reading, then the JOIN gets you the information from things table for that record.
The where clause in SQL applies to the result set you're requesting, NOT to the join.
What your code is NOT saying: "do this join only for the ID of 1"...
What your code IS saying: "do this join, then pull records out of it where the ID is 1"...
This is why you need the inner where clause. Incidentally, I also think Filipe is right about the unnecessary code.
I am trying to map a self join where the right table must be filtered, e.g. SQL such as this:
select t2.* from table t
left join table t2
on t2.parentID = t.ID and t2.active=1;
I can figure out the syntax if I wanted to filter the left table:
// works
var query = from t in table
where t.active= 1
join t2 in table
on t.parentID equals t2.ID into joined
from r in joined.DefaultIfEmpty() ...
But I can't figure out how to filter the right table. It seems like it should be something like this...
// does not work
var query = from t in table
join t2 in table
where t.field = 1
on t.parentID equals t2.ID into joined
from r in joined.DefaultIfEmpty() ...
(not valid... join can't have where). There is discussion of using multiple from clauses, but if I create more than one from clause, so I can add a where to the 2nd one, I can't figure out how to join the results of them into a new temporary table.
I can't just add a "where" after the join; the right table must be filtered first or matches will occur, and a where clause at the end would remove the row from the left table that I do want in the output. That is, the output should have rows where there's nothing matched from filtered right table. So I need to filter the right table before the join.
I think you are looking to do this:
var query = from t in table
join t2 in
(from t3 in table
where t3.field = 1
select t3)
on t.parentID equals t2.ID into joined
from r in joined.DefaultIfEmpty() ...
Another way is to use multiple from like this:
var query = from t in table
from t2 in table.Where(x => x.field = 1)
.Where(x => x.ID == t.parentID)
.DefaultIfEmpty()
select ....