How to LEFT JOIN in DB2 iseries with first row? - sql

I have need a query that JOIN a TABLE with A first row of other table value based:
SELECT * FROM TABLEA A LEFT JOIN
(SELECT * from TABLEB
WHERE FIELD1 <> '3' and FIELD2 = 'D' AND A.CODE=CODE
FETCH FIRST 1 ROW ONLY
) B
on a.FIELDA = b.FIELDA
and A.FIELDB = B.FIELDB
but DB2 return ERROR because can't use A.CODE
How can solve this?

You need to use the nested table expression:
SELECT * FROM TABLEA A LEFT JOIN
LATERAL (SELECT * from TABLEB
WHERE FIELD1 <> '3' and FIELD2 = 'D' AND A.CODE=CODE
FETCH FIRST 1 ROW ONLY
) B
on a.FIELDA = b.FIELDA
and A.FIELDB = B.FIELDB

This is a highly optimized statement.
Your not getting any data from tableb and your going for first row so you just need exists clause.
select a.* from tablea a
where exists (select * from tableb b
where a.fielda = b.fielda
and a.fieldb = b.fieldb
and b.code = a.code
and b.field2 = 'd' and b.field1 <> '3')

You can use the OLAP function row_number() to rank the records according to somefield(s) within a (fielda,fieldb,code) group. Somefield might be a transaction id, or sequence, for example. The order by clause is optional there, but without it, you might be randomly picking which record is the first in the group.
WITH B AS
(SELECT *,
row_number() over (partition by fielda,fieldb,code
order by somefield
) as pick
from TABLEB
WHERE FIELD1 <> '3'
and FIELD2 = 'D'
)
SELECT *
FROM TABLEA A LEFT JOIN B
on a.FIELDA = b.FIELDA
and A.FIELDB = B.FIELDB
and A.CODE = B.CODE
where pick=1

Related

SQL select result from two fields where equal to same search result

Currently SQL statement as below:
SELECT result FROM tableA WHERE
field1 = (SELECT x FROM tableB WHERE field3 = "XXX") OR
field2 = (SELECT x FROM tableB WHERE field3 = "XXX");
Can simplify the two select statementSELECT x FROM tableB WHERE field3 = "XXX" ?
Have using JOIN and currently the statement as below:
SELECT resultB from tableA a join
tableB b on
b.field4 = a.field1 or
b.field4 = a.field2 where
b.field3 = "XXX";
Further on, "XXX" is from below SQL statement:
SELECT DISTINCT(resultA) FROM tableC c WHERE c.field5 is false;
How to combine this to having result as below:
resultA(1), resultB(1)
resultA(2), resultB(2)
resultA(3), resultB(3)
...
Thanks.
You can join the tables.
SELECT
a.result
FROM tableA a
join tableB b on b.x = a.field1 or b.x = a.field2
where b.field3 = 'XXX'
https://www.w3schools.com/sql/sql_join.asp
You can do it with EXISTS:
SELECT a.result
FROM tableA a
WHERE EXISTS (
SELECT 1
FROM tableB b
WHERE b.field3 = 'XXX' AND b.x IN (a.field1, a.field2)
)
Although you can "simplify" the logic, if you care about performance that is probably not a good route. Instead, I would suggest using exists twice:
SELECT a.result
FROM tableA a
WHERE EXISTS (SELECT 1
FROM tableB b
WHERE b.x = a.field1 AND b.field3 = 'XXX'
) OR
EXISTS (SELECT 1
FROM tableB b
WHERE b.x = a.field2 AND b.field3 = 'XXX'
);
This can make use of an index on tableB(x, field3).

SQL query to select from one table based on a column value in other table

I have two tables and I want to select all values from "TABLE A" that have a different value in a column from "TABLE B".
I tried this
SELECT A.* FROM tableA A
left join tableB B ON A.id = B.id WHERE B.column <> 1;
But this just return the value that I want to ignore.
SELECT A.*
FROM tableA A
INNER JOIN tableB B
ON A.id = B.id
WHERE B.column != 1;
or
SELECT A.* FROM tableA A WHERE A.Id NOT IN (SELECT B.Id FROM tableB B WHERE B.column != 1)
Depends on your SQL you can use <> or !=
I would suggest not exists:
SELECT A.*
FROM tableA A
WHERE NOT EXISTS (SELECT 1 FROM tableB B WHERE A.id = B.id AND B.column = 1);
Using a JOIN can result in duplicated rows, if more than one row in B matches the JOIN condition.

SQL query inner join and where on the second table

I have a oracle database and I'm trying to query data in table1 and inner join with another table2 where one of the columns(date) is equal to the most recent date and another column in table2(built) is equal to 'yes'. This query below is not picking up the where function and can't pinpoint why
SELECT id, b, c, d
FROM table1 a
INNER JOIN table2 b on b.id = a.id
WHERE b.date =(SELECT MAX(date) FROM table2) AND b.built = 'yes'
Actual query
SELECT m_tp_str, m_tp_trn, m_tp_dte, m_tp_buy, m_tp_qtyeq, m_tp_nom, m_instr,
m_tp_p, m_tp_status2
FROM HA_PRD_DM.TP_ALL_REP a INNER JOIN HA_PRD_DM.UDF_CURR_REP b
ON a.m_udf_ref2 = b.m_nb
WHERE b.m_rep_date2 = (SELECT MAX(c.m_rep_date2) FROM HA_PRD_DM.UDF_CURR_REP c)
AND b.m_purpose = 'yes'
You can do this using analytic functions:
SELECT id, b, c, d
FROM table1 a INNER JOIN
(SELECT b.*, MAX(date) OVER (PARTITION BY b.id) as max_date
FROM table2 b
WHERE built = 'yes'
) b
ON b.id = a.id AND b.max_date = b.date;

Alternative for union in Oracle

Is there any alternate way to fetch the following data without using union?
select A.name,A.age,B.Address,C.phoneNo from table1 A,Table2 B,Table3 C where a.pkId = b.FkId and b.pkId = c.FkId
union
select A.name,A.age,B.Address,C.phoneNo from table4 A,Table5 B,Table3 C where a.pkId = b.FkId and b.pkId = c.FkId
I am using this in Hibernate and unfortunately hibernate doesnt support Union. I was just wondering if there is any other way to achieve it else ill have to write it in a procedure and save the data in temp table and fire a sql to read data from that temp table
There is an alternative for union, but it is not pretty:
select distinct coalesce(x1.name, x2.name) as name,
coalesce(x1.age, x2.age) as age,
coalesce(x1.Address, x2.Address) as age,
coalesce(x1.phoneNo, x2.phoneNo) as age,
from (select A.name, A.age, B.Address, C.phoneNo
from table1 A join
Table2 B
on a.pkId = b.FkId join
Table3 C
on b.pkId = c.FkId
) x1 full outer join
(select A.name, A.age, B.Address, C.phoneNo
from table4 A join
Table5 B
on a.pkId = b.FkId join
Table3 C
on b.pkId = c.FkId
) x2
on 1 = 0; -- always false
I can't imagine why you would want to express a union like this. I would highly recommend, though, that you start using proper, explicit join syntax.
is this working ?
SELECT
CASE DISTINCT_FLG WHEN 1 THEN nameA ELSE nameB END name,
CASE DISTINCT_FLG WHEN 1 THEN ageA ELSE ageB END age,
CASE DISTINCT_FLG WHEN 1 THEN AddressA ELSE AddressB END Address,
CASE DISTINCT_FLG WHEN 1 THEN phoneNoA ELSE phoneNoB END phoneNo
FROM (
SELECT
T1.name AS nameA, T1.age AS ageA, T2.Address AS AddressA, T3.phoneNo AS phoneNoA,
T4.name AS nameB, T4.age AS ageB, T5.Address AS AddressB, T3.phoneNo AS phoneNoB,
ROW_NUMBER() OVER(PARTITION BY T1.name, T1.age, T2.Address, T4.name, T4.age, T5.Address, T3.phoneNo ORDER BY NULL) AS DISTINCT_FLG
FROM
table1 T1,
table2 T2,
table4 T4,
table5 T5,
table3 T3
WHERE
T1.pkId = T2.FkId AND
T4.pkId = T5.FkId AND
(
T2.pkId = T3.FkId OR
T5.pkId = T3.FkId
)
) WHERE DISTINCT_FLG IN (1, 2)
Those two UNION parts have Table3 C in common, so we can join the rest to it. To emulate UNION records from the source table can be replicated through unconditional cross join of an auxiliary table with the required number or rows:
Select Distinct
CASE R.r WHEN 1 THEN A1.name ELSE A2.name END As name ,
CASE R.r WHEN 1 THEN A1.age ELSE A2.age END As age ,
CASE R.r WHEN 1 THEN B1.Address ELSE B2.Address END As Address,
C.phoneNo
From Table3 C, --< Start at common Table3
(Select Rownum r From USER_TABLES Where Rownum < 3) R --< Two rows to replicate Table3 C
-- Any table with more than one row will do
-- USER_TABLES should have enough rows in this particular case
Left Join Table2 B1 On R.r = 1 AND B1.pkId = C.FkId --< Left Join branch one
Left Join table1 A1 On R.r = 1 AND A1.pkId = B1.FkId
Left Join Table5 B2 On R.r = 2 AND B2.pkId = C.FkId --< Left Join branch two
Left Join table4 A2 On R.r = 2 AND A2.pkId = B2.FkId
Where (R.r = 1 AND A1.pkId Is NOT NULL) --/ Make sure we have values
OR (R.r = 2 AND A2.pkId Is NOT NULL) --\ for the branch
But really, consider a view.

SQL getting the last item by date

I have a query that I had working on one item, then I wiped the dataset and started over and now I can't get it to pull any data at all.
The query is basically:
SELECT *
FROM TABLEA
LEFT JOIN TABLEB
ON TABLEA.ID = TABLEB.ID
WHERE TABLEA.ID = 1
AND TABLEB.DATE = (SELECT MAX(TABLEB.DATE)
FROM TABLEB
WHERE TABLEA.ID = 1)
TableB tracks changes and has hundreds of entries per ID. I want a single row of the last chronological item pertaining to that ID.
If there is a better way to do this then awesome but I'd really like to know why this specific query isn't working. When I run this query:
SELECT MAX(TABLEB.DATE)
FROM TABLEB
LEFT JOIN TABLEB
ON TABLEA.ID = TABLEB.ID
WHERE TABLEA.ID = 1
I get the proper value of the last date in the dataset.
select *
from tableA as a
left outer join tableB as b on b.ID = a.ID
where
b.Date = (select max(t.Date) from tableB as t WHERE t.ID = a.id)
-- and a.ID = 1 if you need it
if you just need date from tableB, you can do
select *
from tableA as a
left outer join (
select max(t.Date) as Date, t.ID from tableB as t group by t.ID
) as b on b.ID = a.ID
-- where a.ID = 1 if you need it
if you can use row_number function (you can change common table expression to subquery):
with cte as (
select *, row_number() over(partition by a.ID order by b.Date desc) as rn
from tableA as a
left outer join tableB as b on b.ID = a.ID
    -- where a.ID = 1 if you need it
)
select *
from cte
where rn = 1
if you're using SQL Server version >= 2005:
select *
from tableA as a
outer apply (
select top 1 t.*
from tableB as t
where t.ID = a.ID
order by t.Date desc
) as b
-- where a.ID = 1 if you need it
Please note using aliases in all subqueries.
About your initial query, I think you has an typo there:
SELECT *
FROM TABLEA
LEFT JOIN TABLEB
ON TABLEA.ID = TABLEB.ID
WHERE TABLEA.ID = 1
AND TABLEB.DATE = (SELECT MAX(TABLEB.DATE)
FROM TABLEB
WHERE TABLEA.ID = 1) -- <-- Do you mean TABLEB.ID = 1 ??
Here is one way:
SELECT *
FROM tableA LEFT JOIN
tableB
ON tableA.ID = tableB.ID
WHERE tableA.ID = 1
ORDER BY tableB.Date desc
LIMIT 1;