Querying two tables for a condition (Oracle) - sql

Suppose I have a two tables A and B which have similar cust_id column. I am trying to retrieve all the rows where the cust_id are equal for A and B but have different email addresses.
What I have now is the following:
SELECT
A.cust_id,
A.email_addr,
B.preferred_email
FROM
email_feature A
LEFT OUTER JOIN email_feature_sum B ON
(
A.cust_id = B.cust_id
AND
A.email_addr != B.preferred_email
)
ORDER BY
A.date_loaded DESC
but it isn't returning any results and I am not sure what I am doing wrong?

In response to the comment on the OP above, I believe the A.cust_id needs to have leading zeroes trimmed. This can be accomplished as follows:
If the B.cust_id is in a numeric format, you may also have to cast it as a string for the comparison to work. I have included this in the join, but if it is not needed because B.cust_id is already a char type, you can remove the casting and it will be more efficient.
SELECT
A.cust_id,
A.email_addr,
B.preferred_email
FROM
email_feature A
LEFT OUTER JOIN email_feature_sum B ON
(
ltrim(A.cust_id, '0') = to_char(B.cust_id)
AND
A.email_addr != B.preferred_email
)
ORDER BY
A.date_loaded DESC

Perhaps the ordering of the result set is throwing you off. What if you do a regular join?
SELECT ef.cust_id, ef.email_addr, efs.preferred_email
FROM email_feature ef JOIN
email_feature_sum efs ON
ON ef.cust_id = efs.cust_id and
ef.email_addr <> efs.preferred_email
ORDER BY ef.date_loaded desc;

I think your data is not match the condition. I has been test and it run success.
with email_feature as(
select 1 cust_id,'hvv#gmail.com' email_addr from dual
),
email_feature_sum as(
select 1 cust_id,'hvv#gmail2.com' preferred_email from dual
)
SELECT
A.cust_id,
A.email_addr,
B.preferred_email
FROM
email_feature A
LEFT OUTER JOIN email_feature_sum B ON
(
A.cust_id = B.cust_id
AND
A.email_addr != B.preferred_email
)

Related

LEFT JOIN & SUM GROUP BY

EDIT:
The result supposed to be like this:
desired result
I have this query:
SELECT DISTINCT mitarbeiter.mitarbnr, mitarbeiter.login, mitarbeiter.name1, mitarbeiter.name2
FROM vertragspos
left join vertrag_ek_vk_zuord ON vertragspos.id = vertrag_ek_vk_zuord.ek_vertragspos_id
left join mitarbeiter ON vertrag_ek_vk_zuord.anlage_mitarbnr = mitarbeiter.mitarbnr
left join vertragskopf ON vertragskopf.id = vertragspos.vertrag_id
left join
(
SELECT wkurse.*, fremdwaehrung.wsymbol
FROM wkurse
INNER join
(
SELECT lfdnr, Max(tag) AS maxTag
FROM wkurse
WHERE tag < SYSDATE
GROUP BY lfdnr
) t1
ON wkurse.lfdnr = t1.lfdnr AND wkurse.Tag = t1.maxTag
INNER JOIN fremdwaehrung ON wkurse.lfdnr = fremdwaehrung.lfdnr
) wkurse ON vertragskopf.blfdwaehrung = wkurse.lfdnr
left join
(
SELECT vertrag_ID, Sum (preis) preis, Sum (menge) menge, Sum (preis * menge / Decode (vertragskopf.zahlintervall, 1,1,2,2,3,3,4,6,5,12,1) / wkurse.kurs) vertragswert
FROM vertragspos
GROUP BY vertrag_ID
) s ON vertragskopf.id = s.vertrag_id
But I always get an error on line 21 Pos 145:
ORA-00904 WKURSE.KURS invalid identifier
The WKURSE table is supposed be joined already above, but why do I still get error?
How can I do join with all these tables?
I need to join all these tables:
Mitarbeiter, Vertragspos, vertrag_ek_vk_zuord, wkurse, fremdwaehrung, vertragskopf.
What is the right syntax? I'm using SQL Tool 1,8 b38
Thank you.
Because LEFT JOIN is executed on entire dataset, and not in row-by-row manner. So there's no wkurse.kurs available in the execution context of subquery. Since you join that tables, you can place the calculation in the top-most select statement.
EDIT:
After you edited the statement, it became clear where does vertragskopf.zahlintervall came from. But I don't know where are you going to use calculated vertragswert (now it is absent in the query), so I've put it in the result. As I'm not a SQL parser and have no idea of your tables, so I cannot check the code, but calculation now can be resolved (all the values are available in calculation context).
SELECT DISTINCT mitarbeiter.mitarbnr, mitarbeiter.login, mitarbeiter.name1, mitarbeiter.name2, s.amount / Decode (vertragskopf.zahlintervall, 1,1,2,2,3,3,4,6,5,12,1) / wkurse.kurs) vertragswert
FROM vertragspos
left join vertrag_ek_vk_zuord ON vertragspos.id = vertrag_ek_vk_zuord.ek_vertragspos_id
left join mitarbeiter ON vertrag_ek_vk_zuord.anlage_mitarbnr = mitarbeiter.mitarbnr
left join vertragskopf ON vertragskopf.id = vertragspos.vertrag_id
left join (
SELECT wkurse.*, fremdwaehrung.wsymbol
FROM wkurse
INNER join (
SELECT lfdnr, Max(tag) AS maxTag
FROM wkurse
WHERE tag < SYSDATE
GROUP BY lfdnr
) t1
ON wkurse.lfdnr = t1.lfdnr AND wkurse.Tag = t1.maxTag
INNER JOIN fremdwaehrung ON wkurse.lfdnr = fremdwaehrung.lfdnr
) wkurse ON vertragskopf.blfdwaehrung = wkurse.lfdnr
left join (
SELECT vertrag_ID, Sum (preis) preis, Sum (menge) menge, Sum (preis * menge) as amount
FROM vertragspos
GROUP BY vertrag_ID
) s ON vertragskopf.id = s.vertrag_id
Rewriting the code using WITH clause makes it much clearer than select from select.
Also get the rate on last day before today in oracle is as simple as
select wkurse.lfdnr
, max(wkurse.kurs) keep (dense_rank first order by wkurse.tag desc) as rate
from wkurse
where tag < sysdate
group by wkurse.lfdnr
One option is a lateral join:
left join lateral
(SELECT vertrag_ID, Sum(preis) as preis, Sum(menge) as menge,
Sum (preis * menge / Decode (vertragskopf.zahlintervall, 1,1,2,2,3,3,4,6,5,12,1) / wkurse.kurs) vertragswert
FROM vertragspos
GROUP BY vertrag_ID
) s
ON vertragskopf.id = s.vertrag_id

Join or match value from two tables

I have two tables . Based on the first table I need to check if it is locked or not.
In the below example , if the combination is present then I would pick else it should match with 'All' and bring that record.
Lock Table
Transaction Table
Output
Query tried - But it is doing a cross join . I understand the reason but could not solve it
SELECT a.GROUP,a.OFFICE,b.LOCK
FROM T_ITEMS a INNER JOIN LOCKED_T b
ON a.ORG=c.ORG
AND (a.OFFICE =b.OFFICE OR b.OFFICE='All')
AND a.GROUP=b.GROUP
What you want to do is match on group or use all as a "wildcard". The problem is that you are matching on both for one of the items -- so you get two results.
So what you do is the first join
SELECT a.GROUP, a.OFFICE, b.LOCK
FROM T_ITEMS a
LEFT JOIN LOCKED_T b ON a.ORG = c.ORG A
AND a.OFFICE = b.OFFICE
AND a.GROUP = b.GROUP
Now take those results and try to fill in the missing ones (missing ones will have a null in the lock column
SELECT
BASE.GROUP, BASE.OFFICE, COLLESCE(BASE.LOCK, L.LOCK) AS LOCK
FROM
(SELECT
a.GROUP, a.OFFICE, b.LOCK
FROM
T_ITEMS a
LEFT JOIN
LOCKED_T b ON a.ORG = c.ORG
AND a.OFFICE = b.OFFICE
AND a.GROUP = b.GROUP) BASE
LEFT JOIN
LOCKED_T L ON BASE.ORG = L.ORG
AND L.OFFICE = 'All'
AND base.GROUP = L.GROUP
AND BASE.LOCK IS NULL
I look at this as a "defaulting" problem. That can be solved with two left joins:
SELECT i.GROUP, i.OFFICE,
COALESCE(l.LOCK, l_default.LOCK)
FROM T_ITEMS i LEFT JOIN
LOCKED_T l
ON l.ORG = i.ORG AND l.OFFICE = i.OFFICE LEFT JOIN
LOCKED_T l_default
ON l_default.OFFICE = 'All' AND l_default.GROUP = i.GROUP AND l.ORG IS NULL;
As the number of combinations grows, this gets trickier. So a more generalizable alternative uses a correlated subquery:
SELECT i.*,
(SELECT MAX(l.LOCK) KEEP (DENSE_RANK FIRST ORDER BY NULLIF(l.OFFICE, 'All) NULLS LAST,NULLIF(l.GROUP, 'All) NULLS LAST
FROM LOCKED_T l
WHERE (l.OFFICE = i.OFFICE OR l.OFFICE = 'All') AND
(l.GROUP = i.GROUP OR l.GROUP = 'All')
) as LOCKED
FROM T_ITEMS i;
Oracle 12C supports lateral joins so this can actually be in the FROM clause instead.

SQL query to return unique top row for each group

Trying to write a query that would return a unique record for each systems name.
The existing query returns several records for each systemName since there are multiple version of the same product present.
I am able to sort by version number but would like to be able to only keep the top version number for each system.
SELECT DISTINCT v.sysName
,v.groupName
,a.versionNumb
,b.userName
FROM table1 AS a
INNER JOIN table2 AS v ON v.sID = a.sID
INNER JOIN table3 AS b ON v.sID = b.sID
WHERE a.versionNumb LIKE '10.%'
AND v.groupName LIKE '%' + #groupVar
ORDER BY a.versionNumb DESC
Tried using ROW_NUMBER() to sort and return the row value but I'm still not 100% on getting the proper data extracted.
Any help would be appreciated!
Just use MAX() and GROUP BY:
SELECT v.sysName,
v.groupName,
MAX(a.versionNumb) as versionNumb,
b.userName
FROM table1 AS a
INNER JOIN table2 AS v ON v.sID = a.sID
INNER JOIN table3 AS b ON v.sID = b.sID
WHERE a.versionNumb LIKE '10.%'
AND v.groupName LIKE '%' + #groupVar
GROUP BY v.sysName, v.groupName, b.userName
I removed your DISTINCT because it's redundant with a GROUP BY
You can use a query to GROUP BY by system name and after JOIN to take all information you need
SELECT d.sysName, max (d.versionNumb)
FROM (select * from table1 AS a
INNER JOIN table2 AS v ON v.sID = a.sID) as d
Group by d.sysName

Joining two tables on a key and then left outer joining a table on a number of criteria

I'm attempting to join 3 tables together in a single query. The first two have a key so each entry has a matching entry. This joined table will then be joined by a third table that could produce multiple entries for each entry from the first table (the joined ones).
select * from
(select a.bidentifier, a.bsession, a.symbol, b.jidentifier, b.JSession
from trade_monthly a, trade_monthly_second b
where
a.bidentifier = b.jidentifier AND
a.bsession = b.JSession)
left outer join
trade c
on c.symbol = a.symbol
order by a.bidentifier, a.bsession, a.symbol, b.jidentifier, b.JSession, c.symbol
There will be more criteria (not just c.symbol = a.symbol) on the left outer join but for now this should be useful. How can I nest the queries this way? I'm gettin gan SQL command not properly ended error.
Any help is appreciated.
Thanks
For what I know every derived table must be given a name; so try something like this:
SELECT * FROM
(SELECT a.bidentifier, ....
...
a.bsession = b.JSession) t
LEFT JOIN trade c
ON c.symbol = t.symbol
ORDER BY t.bidentifier, ...
Anyway I think you could use a simpler query:
SELECT a.bidentifier, a.bsession, a.symbol, b.jidentifier, b.JSession, c.*
FROM trade_monthly a
INNER JOIN trade_monthly_second b
ON a.bidentifier = b.jidentifier
AND a.bsession = b.JSession
LEFT JOIN trade c
ON c.symbol = a.symbol
ORDER BY a.bidentifier, a.bsession, a.symbol, b.jidentifier, b.JSession, c.symbol
Try this:
SELECT
`trade_monthly`.`bidentifier` AS `bidentifier`,
`trade_monthly`.`bsession` AS `bsession`,
`trade_monthly`.`symbol` AS `symbol`,
`trade_monthly_second`.`jidentifier` AS `jidentifier`,
`trade_monthly_second`.`jsession` AS `jsession`
FROM
(
(
`trade_monthly`
JOIN `trade_monthly_second` ON(
(
(
`trade_monthly`.`bidentifier` = `trade_monthly_second`.`jidentifier`
)
AND(
`trade_monthly`.`bsession` = `trade_monthly_second`.`jsession`
)
)
)
)
JOIN `trade` ON(
(
`trade`.`symbol` = `trade_monthly`.`symbol`
)
)
)
ORDER BY
`trade_monthly`.`bidentifier`,
`trade_monthly`.`bsession`,
`trade_monthly`.`symbol`,
`trade_monthly_second`.`jidentifier`,
`trade_monthly_second`.`jsession`,
`trade`.`symbol`
Why don't you just create a view of the two inner joined tables. Then you can build a query that joins this view to the trade table using the left outer join matching criteria.
In my opinion, views are one of the most overlooked solutions to a lot of complex queries.

Returning DISTINCT rows from database query

I am fairly new to SQL so apologies if there is a simple solution to this.
I have this piece of SQL that performs a join on 3 tables.
SELECT a.group_leader, b.forum_name
FROM flightuser_group a
INNER JOIN flightacl_groups c ON a.group_id = c.group_id
JOIN flightforums b ON c.forum_id = b.forum_id
WHERE a.user_id = '60'
ORDER BY a.group_leader DESC
This query returns this:
group_leader forum_name
1 tmpSQJ
0 jobby7
0 jobby5
0 tmpSQJ
I am trying to only keep the first tmpSQJ entry and remove the second but cannot determine where the DISTICT clause goes.
Many thanks in advance.
Try This:
SELECT MAX(a.group_leader), b.forum_name
FROM flightuser_group a INNER JOIN flightacl_groups c ON a.group_id = c.group_id
JOIN flightforums b ON c.forum_id = b.forum_id
WHERE a.user_id = '60'
GROUP BY b.forum_name
ORDER BY a.group_leader DESC
For MySQL, add a LIMIT 1 after the ORDER BY.
For MS SQL, add a TOP 1 after the SELECT.
These two flavors will get you only the first record in the recordset.
You could try a GROUP BY which essentially behaves the same:
SELECT a.group_leader, b.forum_name
FROM flightuser_group a
INNER JOIN flightacl_groups c ON a.group_id = c.group_id
JOIN flightforums b ON c.forum_id = b.forum_id
WHERE a.user_id = '60'
GROUP BY b.forum_name
ORDER BY a.group_leader DESC
You could also look at using "INNER JOIN" for flightforums