Pivot and kind of cross-join at same time - sql

I have two tables:
I'm trying to construct a table that returns:
Where:
T3.VALUE_0M column is equal to T2.VALUE if:
T2.OLD_DATE = T1.REF_DATE and T2.ID = T1.ID
or:
T3.VALUE_0M is NULL if there is no T2.OLD_DATE = T1.REF_DATE.
T3.VALUE_1M column is equal to T2.VALUE if: T1.OLD_DATE =
ADD_MONTHS(T1.REF_DATE,-1) and T2.ID = T1.ID
or:
T3.VALUE_1M is NULL if there is no T2.OLD_DATE =
ADD_MONTHS(T1.REF_DATE,-1).
T3.VALUE_2M column is equal to T2.VALUE if:
T1.OLD_DATE = ADD_MONTHS(T1.REF_DATE,-2) and T2.ID = T1.ID
or:
T3.VALUE_2M is NULL if there is no T2.OLD_DATE = ADD_MONTHS(T1.REF_DATE,-2).
and so on.
My challenge is: if there are more than one value for the same T2.ID and T2.OLD_DATE, i want to show both of them in different rows, but crossing with the other VALUE columns.
I've tried to use cross join, but the result was not the desired:
Could be someone so kind and help me with this stuff?
Thank you very much!

As much as I understand, the resulting query would be such like the below one :
SELECT t1.ID, t2.ref_date,
(case when ( T1.OLD_DATE = T2.REF_DATE and T2.ID = T1.ID )
then t1.value end) value_0m,
(case when ( T1.OLD_DATE = ADD_MONTHS(T2.REF_DATE,-1) and T2.ID = T1.ID )
then t1.value end) value_1m,
(case when ( T1.OLD_DATE = ADD_MONTHS(T2.REF_DATE,-2) and T2.ID = T1.ID )
then t1.value end) value_2m,
(case when ( T1.OLD_DATE = ADD_MONTHS(T2.REF_DATE,-3) and T2.ID = T1.ID )
then t1.value
end) value_3m
FROM T1 CROSS JOIN T2;
SQL Fiddle Demo

Related

SQL three table joins using two ids and another column

I have three tables
t1 t2 t3
I want to select data from only two of the tables but need the ids and columns from other tables for reference.
How to select data from t3 and t2
WHERE t1.id = t2.id = t3.id
AND t1.fid = t2.fid = t3.fid
AND t1.type = 'abc'
id column will be the same value for all tables. fid column will have incremental fid's but need the ones where t1.type = 'abc' also
Would this work?
select data
from t3
select data
from t2
join on t1.id = t2.id and t2.id = t3.id
join on t1.fid = t2.fid and t2.fid = t3.fid and t1.type = 'abc'
where id = 1
Generally, this kind of problem can be solved using EXISTS as follows:
select data
from t2
join t1 on t1.id = t2.id and t1.fid = t2.fid
where exists (select 1 from t3 where t2.id = t3.id and t2.fid = t3.fid)
and t1.type = 'abc'
and t1.id = 1
You could try something like this:
select columns_that_you_want
from t1 x
inner join t2 y on x.id = y.id
inner join t3 z on y.id = z.id
where x.type = 'abc'
;
This will join the three tables, and filter just the type 'abc' that you want from table t1. Also you can add more filter on the where clause in case you need to filter more the result.

Conditional Join with replace and case

I have two tables that I want to join.
The case is in table 1 the default value is 1 then in table 2 the default value is 0
Table 1 Table 2
-------- ---------
1 0
1232342 1232342
1241232 1231231
I want to join table 1 and table 2 with condition that if table 2 is 0 then it will be replaced to 1.
SELECT T1.ID
FROM TABLE1 T1, TABLE2 T2
WHERE T1.ID = REPLACE(CASE WHEN T2 = 0 THEN 1 ELSE T2.ID END, 'X', 'E')
with this statement it does not return the other id's that are not 0 or 1
expected output
Table 1
--------
1
1232342
Use a join with a CASE. replace() is for string values:
select t1.*
from table1 t1
join table2 t2 on t1.id = case when t2.id = 0 then 1 else t2.id end;
use case when and sub-query
select t1.* from table1 t1 join
(
select case when t2.id=0 then 1 else t2.id end as id from table2 t2
) as t3 on t1.id=t3.id
Try using case when :
SELECT *
FROM TABLE1 T1 inner join TABLE2 T2
on T1.ID = (CASE WHEN T2.ID =0 THEN 1 ELSE T2.ID END)
Switch to modern, explicit JOIN syntax. Skip the case expression, simply use AND/OR instead:
SELECT T1.ID
FROM TABLE1 T1
JOIN TABLE2 T2
ON T1.ID = T2.ID OR (T1.ID = 1 and T2.ID = 0)
Or use INTERSECT:
SELECT ID FROM TABLE1
INTERSECT
SELECT case when ID = 0 then 1 else id end from TABLE2

How to optimize multiple subqueries that are running for lookup tables

I have two looK up tables, and need is to fetch value by correlating the both tables.
As of now I am doing this with multiple sub queries and trying to find a easiest way.
SELECT
(SELECT TYPE_NAME FROM T1 where FK_T2 = (SELECT PK FROM T2 WHERE T2.ID = 'A') AND T1.ID = 'AA')as A,
(SELECT TYPE_NAME FROM T1 where FK_T2 = (SELECT PK FROM T2 WHERE T2.ID = 'B') AND T1.ID = 'BB')AS B,
(SELECT TYPE_NAME FROM T1 where FK_T2 = (SELECT PK FROM T2 WHERE T2.ID = 'C') AND T1.ID = 'CC')AS C,
(SELECT TYPE_NAME FROM T1 where FK_T2 = (SELECT PK FROM T2 WHERE T2.ID = 'D') AND T1.ID = 'DD')AS D,
(SELECT TYPE_NAME FROM T1 where FK_T2 = (SELECT PK FROM T2 WHERE T2.ID = 'E') AND T1.ID = 'EE')AS E,
(SELECT TYPE_NAME FROM T1 where FK_T2 = (SELECT PK FROM T2 WHERE T2.ID = 'F') AND T1.ID = 'FF')AS F
FROM MYTABLE;
I assume you need something like this.
SELECT MAX ( CASE WHEN T1.ID = 'AA' AND T2.ID = 'A' THEN TYPE_NAME END ) as A,
MAX ( CASE WHEN T1.ID = 'BB' AND T2.ID = 'B' THEN TYPE_NAME END ) as B,
MAX ( CASE WHEN T1.ID = 'CC' AND T2.ID = 'C' THEN TYPE_NAME END ) as C,
..
FROM T1 t1
INNER JOIN T2 t2
ON t1.FK_T2 = t2.PK
I'll try something like:
SELECT
T1.TYPE_NAME,
T1.ID
FROM T1 t1
INNER JOIN T2 t2
ON t1.FK_T2 = t2.PK
WHERE
T1.ID||T1.ID = T2.ID
You could try rephrasing these queries as a single query consisting of a join between the two tables:
SELECT
T1.TYPE_NAME,
T1.ID
FROM T1 t1
INNER JOIN T2 t2
ON t1.FK_T2 = t2.PK
WHERE
(T1.ID = 'AA' AND T2.ID = 'A') OR
(T1.ID = 'BB' AND T2.ID = 'B') OR
(T1.ID = 'CC' AND T2.ID = 'C') OR
(T1.ID = 'DD' AND T2.ID = 'D') OR
(T1.ID = 'EE' AND T2.ID = 'E') OR
(T1.ID = 'FF' AND T2.ID = 'F');
You can keep track of to which subquery each returned record corresponds by checking the value of the ID column in the first table. This would serve as a marker for the source subquery.

SQL: select from t1 all rows for which there's no corresponding in t2

Let's say I have a table t1 with only one column: id, and I have a table t2 with two columns: id and Memo. I need to select those id from t1, for which there is NO row in t2 that satisfies both of the following two conditions t1.id = t2.id and t2.Memo = 'myText'. How can I do that? I have tried using join, but that selects row that do satisfy some conditions, whereas I need the opposite.
SELECT *
FROM t1
WHERE NOT EXISTS (SELECT 1
FROM t2
WHERE t2.id = t1.id
AND t2.Memo = 'myText')
One way to do it is using LEFT JOIN:
select id
from t1
left join t2
on t1.id = t2.id and t2.Memo = 'myText'
where t2.id is null
I'm not good in understanding your question:
You mean those t1.id EXISTS in t2 BUT the corresponding t2.Memo <> 'myText'?
SELECT t1.id FROM t1 JOIN t2
ON t1.id = t2.id
HAVING t1.id NOT IN (SELECT id FROM t2 WHERE Memo = 'myText');
Or all t1.id either NOT EXISTS in t2 or EXISTS but Memo <> 'myText'?
SELECT id FROM t1 WHERE id NOT IN (SELECT id FROM t2 WHERE Memo = 'myText');

PostgreSQL updating more rows than in where condition?

I have the following simple SQL update:
update t2 set col = 2
from t2, t1
where t2.id = t1.id
and t1.name = 'test';
But all the rows in t2 are updated! i.e. not just the one with the id where name is 'test', how do I achieve this in Postgres?
You've got too much from from t1,t2
do this:
update t2 set col = 2
from t1
where t2.id = t1.id
and t1.name = 'test';
If you must have t2 in the from alias it and join all three tables in the where..
update t2 as t2_up set col = 2
from t2 as t2_from , t1
where t2_from.id = t1.id
and t2_up.id = t2_from.id
and t1.name = 'test';
I'm guessing that you really mean:
update t2
set col = 2
from t2 join
t1
on t1.id = t2.id
where t1.name = 'test';
The condition t1.id = t1.id doesn't really make much sense in a query. It is equivalent to t1.id is not null. Hence, all rows in t2 would get updated due to the cross join.