Subquery SQL DB2 - sql

I am trying to create a subquery (for a particular column) inside my base query. the code is as follows.
SELECT z.po_id,
max
(
select etcdc.ship_evnt_tms
FROM covinfos.shipment_event etcdc
WHERE etcdc.ship_evnt_cd = '9P'
AND etcdc.ship_id=scdc.ship_id
ORDER BY etcdc.updt_job_tms desc
FETCH first ROW only) AS llp_estimated_delivery_cdc
FROM covinfos.ibm_plant_order z
LEFT JOIN covinfos.ipo_line_to_case a
ON z.po_id = a.po_id
LEFT JOIN covinfos.shipment scdc
ON (
a.ship_id = scdc.ship_id
AND a.ship_to_loc_code = scdc.ship_to_loc_code
AND scdc.loc_type = 'CDC')
GROUP BY z.po_id
There seems to be some kind of typo somewhere based on the error message that pops up when I try to run the code.
BIC00004. DAL01008. An error occurred while accessing the database.
ILLEGAL SYMBOL ".". SOME SYMBOLS THAT MIGHT BE LEGAL ARE: , ). SQLCODE=-104,
SQLSTATE=42601, DRIVER=3.62.56; THE CURSOR SQL_CURLH200C1 IS NOT IN A
PREPARED STATE. SQLCODE=-514, SQLSTATE=26501, DRIVER=3.62.56
However, at plain sight or at least my sight, there is nothing that spots the misstake. Furthermore, running the subselect in a blank sheet (outside the base query, new one) it does correctly.
Thanks

You would probably be best to remove the co-related sub-select, and just join to a plain sub-select. E.g.
SELECT z.po_id,
max(ship_evnt_tms) AS llp_estimated_delivery_cdc
FROM covinfos.ibm_plant_order z
LEFT JOIN covinfos.ipo_line_to_case a
ON z.po_id = a.po_id
LEFT JOIN covinfos.shipment scdc
ON a.ship_id = scdc.ship_id
AND a.ship_to_loc_code = scdc.ship_to_loc_code
AND scdc.loc_type = 'CDC'
LEFT JOIN
( select ship_id
, ship_evnt_tms
FROM
( select ship_id
, ship_evnt_tms
, row_number() over(partition by ship_id order by updt_job_tms desc) as RN
FROM covinfos.shipment_event
WHERE ship_evnt_cd = '9P'
) s
WHERE RN = 1
) AS etcdc
ON etcdc.ship_id=scdc.ship_id
GROUP BY z.po_id
P.S. you could just INNER JOINs unless you want to include po_id's with no ship_evnt_tms

Try adding parentheses around the sub-select. At least this then parses Data Studio using z/OS validation
SELECT z.po_id,
max
((
select etcdc.ship_evnt_tms
FROM covinfos.shipment_event etcdc
WHERE etcdc.ship_evnt_cd = '9P'
AND etcdc.ship_id=scdc.ship_id
ORDER BY etcdc.updt_job_tms desc
FETCH first ROW only)) AS llp_estimated_delivery_cdc
FROM covinfos.ibm_plant_order z
LEFT JOIN covinfos.ipo_line_to_case a
ON z.po_id = a.po_id
LEFT JOIN covinfos.shipment scdc
ON (
a.ship_id = scdc.ship_id
AND a.ship_to_loc_code = scdc.ship_to_loc_code
AND scdc.loc_type = 'CDC')
GROUP BY z.po_id
Still, I'm not sure this is a very nice bit of SQL code.

Related

SQL (snowflake) - how can I return 1 row from a join or use MAX in a second join from result of first

I have a large query that I have pasted parts of below.
I am wanting to use the result of the first join in my second join.
What I am trying to do get the last session that has a lead_conversion then I am getting all sessions in between then and the current row
This is the part I am struggling with
left join (
select ss.id, ss.session_start, ss.lead_id
from sessions ss
inner join lead_conversions inner_lc on inner_lc.session_id = ss.id
) prev_lc
on prev_lc.lead_id = lc.lead_id
and prev_lc.session_start::TIMESTAMP < s.session_start::TIMESTAMP
left join cte_sessions reset_prev_sess
on reset_prev_sess.lead_id = lc.lead_id
and reset_prev_sess.session_start::TIMESTAMP <= s.session_start::TIMESTAMP
and (
prev_lc.session_start::TIMESTAMP IS NULL
OR
reset_prev_sess.session_start::TIMESTAMP > prev_lc.session_start::TIMESTAMP
)
my issue is I cant just fetch the last prev_lc and I cant seem to use max(prev_lc.session_start)
I have tried grouping in first select and using max but this does not work as I believe this is ran before the on
left join (
select max(ss.session_start) as session_start, max(ss.lead_id) as lead_id
from sessions ss
inner join lead_conversions inner_lc on inner_lc.session_id = ss.id
group by inner_lc.id
) prev_lc on prev_lc.lead_id = lc.lead_id
I have also tried using max in the second join but this give the error
SQL compilation error: Invalid aggregate function in ON clause [MAX(CAST(PREV_LC.SESSION_START AS TIMESTAMP_NTZ(9)))]
left join cte_sessions reset_prev_sess
on reset_prev_sess.lead_id = lc.lead_id
and reset_prev_sess.session_start::TIMESTAMP <= s.session_start::TIMESTAMP
and (
prev_lc.session_start::TIMESTAMP IS NULL
OR
reset_prev_sess.session_start::TIMESTAMP > max(prev_lc.session_start::TIMESTAMP)
)
any help with this would be very appreciated
Thank you
if I understand correctly you are looking for to join with the last session start,so what you can do is to order by startsession in your subquery and limit to 1 record:
left join (
select ss.id, ss.session_start, ss.lead_id
from sessions ss
inner join lead_conversions inner_lc on inner_lc.session_id = ss.id
order by ss.session_start desc
limit 1
) prev_lc
the rest of query stays untouched.
So I have found a solution for this if any one comes across this. I ended up just rethinking how I go about it.
I ended up adding a row number for each conversion
with cte_sessions as (
select
s.id
,s.lead_id
,s.session_start::TIMESTAMP as session_start
,CASE WHEN MAX(lc.id) IS NOT NULL
then ROW_NUMBER() over (partition by s.lead_id, (CASE WHEN
MAX(lc.id) IS NOT NULL then 1 else 0 end)
order by s.session_start
)
END as conversion_row
from sessions s
left join lead_conversions lc on lc.session_id = s.id
group by s.id, s.session_start, s.lead_id, s.project_id, s.crawler_id
order by s.session_start
)
The I just did this in the join
left join cte_sessions prev_lc on prev_lc.lead_id = lc.lead_id and prev_lc.conversion_row = s.conversion_row - 1

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

select top 1 in subquery?

I'm trying to get a top 1 returned for each code in this query but this is giving me syntax errors. Any ideas what I can do?
SELECT d.doc_no,
d.doc_short_name,
d.doc_name,
r.revision_code,
r.revision,
r.description,
dtg.group_name,
(SELECT top 1 di.index_user_id
FROM document_instance
WHERE doc_no = d.doc_no
ORDER BY entry_time DESC) AS 'last indexed by'
FROM documents d
LEFT JOIN document_revision r ON r.doc_no = d.doc_no
LEFT JOIN document_instance di ON di.doc_no = d.doc_no
LEFT JOIN document_type_group dtg ON dtg.doc_no = d.doc_no
Assuming Sybase ASE, the top # clause is only supported in derived tables, ie, it's not supported in correlated sub-queries like you're attempting.
Also note that order by is not supported in any sub-queries (derived table or correlated).
If I'm reading the query correctly, you want the index_user_id for the record with the max(entry_time); if this is correct, and assuming a single record is returned for a given doc_no/entry_time combo, you could try something like:
SELECT d.doc_no,
d.doc_short_name,
d.doc_name,
r.revision_code,
r.revision,
r.description,
dtg.group_name,
(SELECT d2.index_user_id
FROM document_instance d2
WHERE d2.doc_no = d1.doc_no
and d2.entry_time = (select max(d3.entry_time)
from document_instance d3
where d3.doc_no = d1.doc_no)
) as 'last indexed by'
FROM documents d
LEFT JOIN document_revision r ON r.doc_no = d.doc_no
LEFT JOIN document_instance d1 ON d1.doc_no = d.doc_no
LEFT JOIN document_type_group dtg ON dtg.doc_no = d.doc_no

Oracle: invalid identifier in subselect

I am trying to use a subselect to get the last row from an associated table but it seems the subselect doesn't know about one of the tables involved that is in the outer query, the error is at kd.KPI_DEF_ID, invalid identifier. Replacing this with a number makes the query valid.
SELECT bp.bp_id,
kd.kpi_def_id,
kd.kpi_name,
ks.kpi_status_now,
kd.threshold_min_val,
kd.threshold_max_val,
kd.threshold_min_alert,
kd.threshold_max_alert,
e.event_id,
e.event_name,
(SELECT *
FROM (SELECT l.log_desc
FROM rator_monitoring.alert_logs l
WHERE l.kpi_def_id = kd.kpi_def_id
ORDER BY TIMESTAMP DESC)
WHERE rownum = 1) log_desc
FROM business_process bp
JOIN kpi_definition kd
ON (kd.bp_id = bp.bp_id)
JOIN rator_monitoring.kpi_status ks
ON (ks.kpi_def_id = kd.kpi_def_id)
JOIN event e
ON (e.event_id = kd.event_id)
WHERE kd.kpi_active_current = 'Y';
What can I do to fix this?
You need to convert the log_desc scalar subquery so that the correlated join is done in the top level. For example, something like:
SELECT ...
(SELECT max(l.log_desc) keep (dense_rank first order by l.timestamp desc)
FROM rator_monitoring.alert_logs l
WHERE l.kpi_def_id = kd.kpi_def_id) log_desc
FROM ...
N.B. untested.
UNTESTED: Restructured as a join using inline views; not sure about performance though...
SELECT bp.bp_id,
kd.kpi_def_id,
kd.kpi_name,
ks.kpi_status_now,
kd.threshold_min_val,
kd.threshold_max_val,
kd.threshold_min_alert,
kd.threshold_max_alert,
e.event_id,
e.event_name,
l.log_desc
FROM business_process bp
JOIN kpi_definition kd
ON kd.bp_id = bp.bp_id
JOIN rator_monitoring.kpi_status ks
ON ks.kpi_def_id = kd.kpi_def_id
JOIN event e
ON e.event_id = kd.event_id
LEFT JOIN (SELECT log_Desc
FROM rator_monitoring.alert_logs
INNER JOIN (SELECT max(timestamp) mts, kpi_def_ID
FROM rator_monitoring.alert_logs
GROUP BY kpi_def_ID) Z
ON Z.mts = l.timestamp
AND Z.kpi_def_ID = l.kpi_def_ID) l
ON l.kpi_def_id = kd.kpi_def_id
WHERE kd.kpi_active_current = 'Y';

Subquery with multiple joins involved

Still trying to get used to writing queries and I've ran into a problem.
Select count(region)
where (regionTable.A=1) in
(
select jxn.id, count(jxn.id) as counts, regionTable.A
from jxn inner join
V on jxn.id = V.id inner join
regionTable on v.regionID = regionTable.regionID
group by jxn.id, regionTable.A
)
The inner query gives an ID number in one column, the amount of times they appear in the table, and then a bit attribute if they are in region A. The outer query works but the error I get is incorrect syntax near the keyword IN. Of the inner query, I would like a number of how many of them are in region A
You must specify table name in query before where
Select count(region)
from table
where (regionTable.A=1) in
And you must choose one of them.
where regionTable.A = 1
or
where regionTable.A in (..)
Your query has several syntax errors. Based on your comments, I think there is no need for a subquery and you want this:
select jxn.id, count(jxn.id) as counts, regionTable.A
from jxn inner join
V on jxn.id = V.id inner join
regionTable on v.regionID = regionTable.regionID
where regionTable.A = 1
group by jxn.id, regionTable.A
which can be further simplified to:
select jxn.id, count(jxn.id) as counts
, 1 as A --- you can even omit this line
from jxn inner join
V on jxn.id = V.id inner join
regionTable on v.regionID = regionTable.regionID
where regionTable.A = 1
group by jxn.id
You are getting the error because of this line:
where (regionTable.A=1)
You cannot specify a condition in a where in clause, it should only be column name
Something like this may be what you want:
SELECT COUNT(*)
FROM
(
select jxn.id, count(jxn.id) as counts, regionTable.A
from
jxn inner join
V on jxn.id = V.id inner join
regionTable on v.regionID = regionTable.regionID
group by jxn.id, regionTable.A
) sq
WHERE sq.a = 1