merge multiple select queries and add a default value - oracle

I am using multiple select to get the certificates generated by policy in the last 10 minutes. if no certificates have been issued still list the policy with default value of 0.
if there are certificates issue with the policy then show the count of certificates issued with that policy.
the policy id's are gathered with this query
SELECT POLICY_ID FROM POLICY_DOMAIN_PATH_MAP_TBL
MINUS
SELECT POLICY_ID FROM POLICY_DOMAIN_PATH_MAP_TBL WHERE ACTION=1 AND PATH_ID IN (-4,-2)
then this will count the certificates generated by each policy.
SELECT
"A3"."POLICY_NAME"
count(*)
FROM
"POLICY_TBL" "A3",
"CERTIFICATE_TBL" "A2",
"CERT_STATUS_CHECK_TBL" "A1"
WHERE
"A2"."POLICY_ID" = "A3"."POLICY_ID"
AND "A2"."ISSUE_DATE" >= sysdate - 10/1440
AND "A1"."CERT_SERIAL_NUM" = "A2"."CERT_SERIAL_NUM"
AND "A1"."STATUS" = '0'
GROUP BY
"A3"."POLICY_NAME"
the problem is this latest query only lists the policies with a certificate generated but I need to have all the policies listed in the first query. if no certificates have been issued then default to 0 if there are certificated generated then show the count.
how can I adapt the where clause so that it search for the policies id listen in the first query and adds a a default value if nothing zero results are found for that policy id.

Something is missing in your query - I don't see join predicates for A3. It should be something like AND A2.POLICY_ID = A3.POLICY_ID.
Anyway you just add outer join here:
SELECT
"A3"."POLICY_NAME"
count("A1"."CERT_SERIAL_NUM")
FROM
"POLICY_TBL" "A3",
"CERTIFICATE_TBL" "A2",
"CERT_STATUS_CHECK_TBL" "A1"
WHERE
"A3"."POLICY_ID" = ???
AND "A3"."POLICY_ID" = "A2"."POLICY_ID"(+)
AND "A2"."ISSUE_DATE"(+) >= sysdate - 10/1440
AND "A1"."CERT_SERIAL_NUM"(+) = "A2"."CERT_SERIAL_NUM"
AND "A1"."STATUS"(+) = '0'
GROUP BY
"A3"."POLICY_NAME"
or in ANSI:
SELECT
"A3"."POLICY_NAME"
count("A1"."CERT_SERIAL_NUM")
FROM
"POLICY_TBL" "A3"
left join "CERTIFICATE_TBL" "A2"
on "A3"."POLICY_ID" = "A2"."POLICY_ID"
and "A2"."ISSUE_DATE" >= sysdate - 10/1440
left join "CERT_STATUS_CHECK_TBL" "A1"
on "A1"."CERT_SERIAL_NUM" = "A2"."CERT_SERIAL_NUM"
AND "A1"."STATUS" = '0'
WHERE
"A3"."POLICY_ID" = ???
GROUP BY
"A3"."POLICY_NAME"
Update:
Ah, you changed your query in the question. Previously it contained a predicate by policy_id. Since you don't need it, you need to join your results:
SELECT
"A3"."POLICY_NAME"
count("A1"."CERT_SERIAL_NUM")
FROM
(
SELECT POLICY_ID FROM POLICY_DOMAIN_PATH_MAP_TBL
MINUS
SELECT POLICY_ID FROM POLICY_DOMAIN_PATH_MAP_TBL WHERE ACTION=1 AND PATH_ID IN (-4,-2)
) A0
join "POLICY_TBL" "A3"
on A0.POLICY_ID = "A3"."POLICY_ID"
left join "CERTIFICATE_TBL" "A2"
on "A3"."POLICY_ID" = "A2"."POLICY_ID"
and "A2"."ISSUE_DATE" >= sysdate - 10/1440
left join "CERT_STATUS_CHECK_TBL" "A1"
on "A1"."CERT_SERIAL_NUM" = "A2"."CERT_SERIAL_NUM"
AND "A1"."STATUS" = '0'
GROUP BY
"A3"."POLICY_NAME"

Related

Rewriting query with table join containing GROUP BY clause

Is it possible to rewrite the following query
SELECT CT.GROUP, CT.EMP_ID, HT.EFF_DT
FROM CURR_TABLE CT
JOIN (SELECT GROUP, EMP_ID, MAX(EFF_DT) AS EFF_DT
FROM HIST_TABLE
WHERE STAT = 'A'
GROUP BY GROUP, EMP_ID) HT ON CT.GROUP = HT.GROUP AND
CT.EMPID = HT.EMP_ID
WHERE CT.GROUP = :1
AND CT.EMP_ID = :2
in a way that is similar to CROSS JOIN style?
SELECT table1.column1, table2.column2...
FROM table1, table2 [, table3 ]
The reason is that I want to create such query in Peoplesoft, and the above can only be achieved by creating a separate view for the selection with the group by clause. I want to do this just in one query without creating additional views.
You may try writing your query as a single level join with an aggregation:
SELECT
CT.GROUP,
CT.EMP_ID,
MAX(HT.EFF_DT) AS EFF_DT
FROM CURR_TABLE CT
LEFT JOIN HIST_TABLE HT
ON CT.GROUP = HT.GROUP AND
CT.EMPID = HT.EMP_ID AND
HT.STAT = 'A'
WHERE
CT.GROUP = :1 AND
CT.EMP_ID = :2
GROUP BY
CT.GROUP,
CT.EMP_ID;
Note that GROUP is a reserved SQL keyword, and you might have to escape it with double quotes to make this query (or the one in your question) work on Oracle.

Only want to return rows that have duplicate unitid within group by unitid

I am working in SSRS querying against an oracle database.
So I have a data source and this report is supposed to find duplicate Work Orders based on multiple open workorders on a unique unitid. So I only want to show groups that have more then one entry as they are grouped by unitid.
SELECT
COMPSTSB.UNITID,
COMPSTSB.UNITTYPE,
ACTDEFN.ACTDESC,
ACTDEFN.ACTCODE,
HISTORY.WONO,
HISTORY.COMPFLAG,
HISTORY.ADDDTTM,
HISTORY.COMMENTS
FROM (IMSV7.COMPSTSB COMPSTSB INNER JOIN IMSV7.HISTORY HISTORY ON
COMPSTSB.COMPKEY=HISTORY.COMPKEY) INNER JOIN IMSV7.ACTDEFN ACTDEFN ON
HISTORY.ACTKEY=ACTDEFN.ACTKEY
WHERE HISTORY.COMPFLAG='Y' AND NOT (ACTDEFN.ACTCODE='DBR' OR ACTDEFN.ACTCODE='IN')
ORDER BY COMPSTSB.UNITTYPE, COMPSTSB.UNITID, HISTORY.ADDDTTM
Can anyone point me in the right direction? And yes before someone says this has been asked a million times, I did search. Point me to the million times and I will see if I feel they match my question. Ideally in the SQL I could make new column that returned a count of the unitid and I did attempt this but failed, and then I could filter on that column to remove any that only had one count. I really don't think this should be difficult but I have spent about 4 hours on it so far.
Thanks in advance!
Steven
If I understood your question right, the following should give you what's needed :
SELECT * FROM
(
SELECT
COMPSTSB.UNITID,
COMPSTSB.UNITTYPE,
ACTDEFN.ACTDESC,
ACTDEFN.ACTCODE,
HISTORY.WONO,
HISTORY.COMPFLAG,
HISTORY.ADDDTTM,
HISTORY.COMMENTS,
COUNT(1) OVER (PARTITION BY COMPSTSB.UNITID) AS numDups
FROM (IMSV7.COMPSTSB COMPSTSB INNER JOIN IMSV7.HISTORY HISTORY ON
COMPSTSB.COMPKEY=HISTORY.COMPKEY) INNER JOIN IMSV7.ACTDEFN ACTDEFN ON
HISTORY.ACTKEY=ACTDEFN.ACTKEY
WHERE HISTORY.COMPFLAG='Y' AND NOT (ACTDEFN.ACTCODE='DBR' OR ACTDEFN.ACTCODE='IN')
)a
WHERE a.numDups >1
ORDER BY COMPSTSB.UNITTYPE, COMPSTSB.UNITID, HISTORY.ADDDTTM
I expect you are concerned about having duplicate values of UNITID in the IMSV7.COMPSTSB table. If so adding this join to your query should enable ou to identify them:
JOIN (SELECT COMPSTSB.UNITID
FROM IMSV7.COMPSTSB
GROUP BY COMPSTSB.UNITID
HAVING COUNT(COMPSTSB.UNITID) > 1) dups
ON DUPS.UNITID = COMPSTSB.UNITID
JOIN IMSV7.HISTORY HISTORY
Here's the full query:
SELECT COMPSTSB.UNITID
, COMPSTSB.UNITTYPE
, ACTDEFN.ACTDESC
, ACTDEFN.ACTCODE
, HISTORY.WONO
, HISTORY.COMPFLAG
, HISTORY.ADDDTTM
, HISTORY.COMMENTS
FROM IMSV7.COMPSTSB COMPSTSB
JOIN (SELECT COMPSTSB.UNITID
FROM IMSV7.COMPSTSB
GROUP BY COMPSTSB.UNITID
HAVING COUNT(COMPSTSB.UNITID) > 1) dups
ON DUPS.UNITID = COMPSTSB.UNITID
JOIN IMSV7.HISTORY HISTORY
ON COMPSTSB.COMPKEY = HISTORY.COMPKEY
JOIN IMSV7.ACTDEFN ACTDEFN
ON HISTORY.ACTKEY = ACTDEFN.ACTKEY
WHERE HISTORY.COMPFLAG = 'Y'
AND ACTDEFN.ACTCODE NOT IN ('DBR','IN')
ORDER BY COMPSTSB.UNITTYPE
, COMPSTSB.UNITID
, HISTORY.ADDDTTM;
Since the above query didn't work you can try outer joins to similar sub queries on each of your tables and limit to only records where the outer joined table returns data. This will show you which tables in your query are cuasing your extra rows.:
SELECT COMPSTSB.UNITID
, COMPSTSB.UNITTYPE
, ACTDEFN.ACTDESC
, ACTDEFN.ACTCODE
, HISTORY.WONO
, HISTORY.COMPFLAG
, HISTORY.ADDDTTM
, HISTORY.COMMENTS
, DUPS.UNITID UNITID_DUP
, DUPS2.COMPKEY COMPKEY_DUP
, DUPS3.ACTKEY ACTKEY_DUP
FROM IMSV7.COMPSTSB COMPSTSB
JOIN IMSV7.HISTORY HISTORY
ON COMPSTSB.COMPKEY = HISTORY.COMPKEY
JOIN IMSV7.ACTDEFN ACTDEFN
ON HISTORY.ACTKEY = ACTDEFN.ACTKEY
LEFT JOIN (SELECT COMPSTSB.UNITID
FROM IMSV7.COMPSTSB
GROUP BY COMPSTSB.UNITID
HAVING COUNT(COMPSTSB.UNITID) > 1) dups
ON DUPS.UNITID = COMPSTSB.UNITID
LEFT JOIN (SELECT HISTORY.COMPKEY
FROM IMSV7.HISTORY
GROUP BY HISTORY.COMPKEY
HAVING COUNT(HISTORY.COMPKEY) > 1) dups2
ON DUPS.UNITID = COMPSTSB.UNITID
LEFT JOIN (SELECT ACTDEFN.ACTKEY
FROM IMSV7.ACTDEFN
GROUP BY ACTDEFN.ACTKEY
HAVING COUNT(ACTDEFN.ACTKEY) > 1) dups3
ON DUPS.UNITID = COMPSTSB.UNITID
WHERE HISTORY.COMPFLAG = 'Y'
AND ACTDEFN.ACTCODE NOT IN ('DBR','IN')
AND ( DUPS.UNITID IS NOT NULL OR
DUPS2.COMPKEY IS NOT NULL OR
DUPS3.ACTKEY IS NOT NULL)
ORDER BY COMPSTSB.UNITTYPE
, COMPSTSB.UNITID
, HISTORY.ADDDTTM;

Nested subquery not supported in hive

We have tried the below query in hive. but getting the error. please help me to resolve this in any other way.
select count(1) as OpenItems from issues i , issue_statuses s
where s.id = i.status_id
and s.name NOT IN ('Closed','Passed','Rejected','On
Hold','Baselined','Completed')
and i.project_id IN
(select id from projects3 from
CASE WHEN ${projectname} = 'All' then id in
(select p.id from members m, projects3 p ,users_1 u
where m.project_id = p.id and u.id = m.user_id and u.status = '1'
and u.id IN
(select u1.id from users_1 u1, Supervisor_hierarchy s1 where u1.mail = s1.email and s1.name = ${Superisorname})
group by p.id)
WHEN (${projectname} <>'All' and ${SubProject projectname} ='All') then id
IN (select id from (select id from project_closure where parent_id in (select id from projects where name = ${projectname}) group by id)a)
WHEN (${SubProject projectname}<>'All' and ${projectname}<> 'All') then id
IN (select id from(select id from project_closure where id in (select id from projects where name = ${SubProject projectname}) group by id)a)
END
order by id)
error: 6:5 Unsupported SubQuery Expression 'id': SubQuery expression refers to both Parent and SubQuery expressions and is not a valid join condition.
I know it is late but posting for anyone who face this issue.
This issue occurs when we encounter one or more of the below limitations of Hive Subqueries.
In this scenario, the reference to the parent query is used in Group By clause which comes under the 4th limitation.
Hive Subquery Limitations
These subqueries are only supported on the right-hand side of an expression.
IN/NOT IN subqueries may only select a single column.
EXISTS/NOT EXISTS must have one or more correlated predicates.
References to the parent query are only supported in the WHERE clause of the subquery.
Source: https://cwiki.apache.org/confluence/display/Hive/LanguageManual+SubQueries

How to append result from select to resultset?

I have the following tables:
Table 1 - NODES (I access it through a DB_LINK):
SITE_ID LATITUDE LONGITUDE
ABC123 21.018 -89.711
CDE456 20.35 -87.349
FGH789 20.258 -87.406
ABB987 18.54 -88.302
CFF546 18.542 -88.273
GHT553 18.52 -88.311
Table 2 - LINKS
ID SITE_A SITE_B STATUS NAME LINK_TYPE REGION ---> Many other fields
1 ABC123 GHT553
2 FGH789 CFF546
3 CDE456 ABC123
4 CFF546 GHT553
Table 3 - RESULT (This is what I want to achieve) - No matter the order
LINK_ID SITE_A_ID LAT_SITE_A LON_SITE_A SITE_B_ID LAT_SITE_B LON_SITE_B
1 ABC123 21.018 -89.711 GHT553 18.52 -88.311
2 FGH789 20.258 -87.406 CFF546 18.542 -88.273
3 CDE456 20.35 -87.349 ABC123 21.018 -89.711
4 CFF546 18.542 -88.273 GHT553 18.52 -88.311
(Plus several other fields, which means no trouble for me)
This is what I have tried:
SELECT RES2.*, SAM2.LATITUDE LAT_SITE_B, SAM2.LONGITUDE LON_SITE_B FROM(
SELECT RES1.*, NOD.LATITUDE LAT_SITE_A, NOD.LONGITUDE LON_SITE_A FROM(
SELECT ID, SITE_A, SITE_B, STATUS, NAME, LINK_TYPE FROM LINKS
WHERE SITE_A IS NOT NULL AND SITE_B IS NOT NULL AND REGION IN (8,6)
)RES1, NODES#NODES_DBLINK NOD WHERE RES1.SITE_A = NOD.SITE_ID
)RES2, NODES#NODES_DBLINK NOD2
WHERE RES2.SITE_B = NOD2.SITE_ID;
Until the SELECT RES1.\*, everything works fine, but when I add the SELECT RES2.\*, it takes too long without returning anything.
From the textual part of your question, this query will generate the result you want:
SELECT links.id AS link_id,
node_a.site_id AS site_a_id,
node_a.latitude AS lat_site_a,
node_a.longitude AS lon_site_a,
node_b.site_id AS site_b_id,
node_b.latitude AS lat_site_b,
node_b.longitude AS lon_site_b
FROM links
INNER JOIN nodes#nodes_dblink node_a ON (links.site_a = node_a.site_id)
INNER JOIN nodes#nodes_dblink node_b ON (links.site_b = node_b.site_id)
ORDER BY links.id;
From the query you posted it seems you have some other criteria to include too which might mean you want something more like this:
SELECT links.id AS link_id,
node_a.site_id AS site_a_id,
node_a.latitude AS lat_site_a,
node_a.longitude AS lon_site_a,
node_b.site_id AS site_b_id,
node_b.latitude AS lat_site_b,
node_b.longitude AS lon_site_b
FROM links
INNER JOIN nodes#nodes_dblink node_a ON (links.site_a = node_a.site_id)
INNER JOIN nodes#nodes_dblink node_b ON (links.site_b = node_b.site_id)
WHERE links.site_a IS NOT NULL
AND links.site_b IS NOT NULL
AND links.region IN (8, 6)
ORDER BY links.id;
Hope it helps...
EDIT:
If your DB link is an issue, try to return only the data you're going to need over the link in advance either by creating a view on the remote DB or a materialised view on the local DB.
If that isn't practical then check the relative explain plans for the query above against this one and see if it is any better:
WITH node_data
AS (SELECT site_id,
latitude,
longitude
FROM nodes#nodes_dblink node
WHERE EXISTS (SELECT 1
FROM links
WHERE links.site_a = node.site_id
OR links.site_b = node.site_id))
SELECT links.id AS link_id,
node_a.site_id AS site_a_id,
node_a.latitude AS lat_site_a,
node_a.longitude AS lon_site_a,
node_b.site_id AS site_b_id,
node_b.latitude AS lat_site_b,
node_b.longitude AS lon_site_b
FROM links
INNER JOIN node_data node_a ON (links.site_a = node_a.site_id)
INNER JOIN node_data node_b ON (links.site_b = node_b.site_id)
WHERE links.site_a IS NOT NULL
AND links.site_b IS NOT NULL
AND links.region IN (8, 6)
ORDER BY links.id;

Oracle group by and the empty resulting set

I have the following SQL problem.
Scenario:
I have two tables: Change and ChangeTicket.
There is a 1:n relationship. One Change has cero or many changeTickets.
No change means no changeTickets.
A changeTicket has a status (open/closed/...)
A changeTicket has a field representing how many minutes took this change.
A Change has a company and a month. There is at most ONE change in the month.
I have to report for a given company and for a given month the sum of minutes
a given change took.
I wrote the following SQL statement.
select nvl(sum(service_req), 0) as SUM_REQ
from Change_Ticket, Change
where Change.company_id (+) = '0'
and Change.month (+)='07'
and Change.Id (+) = Change_Ticket.Change_Id
This is OK.
If for the given month and the given company there are neither changes nor tickets
then I get a null value which is converted to cero usgin the NVL function.
The problem arises when I want to group the information using the status.
If I add a grup clause
select Change_Ticket.status, nvl(sum(service_req), 0) as SUM_REQ
from Change_Ticket, Change
where Change.company_id (+) = '0'
and Change.month (+)='07'
and Change.Id (+) = Change_Ticket.Change_Id
group by Change_Ticket.status
then my result is the empty set.
I understand that there is no status and then the resulting set is
somehow consistent and then an empty resulting set is returned.
How can I avoid this problem. In this case I need to report an
empty status and cero as the the sum.
(BTW, I've also tried putting nvl(Change_Ticket.status, 'none') but didn't work)
Thanks a lot in advance.
Luis
I think to achieve what you want you would need to do this:
select Change_Ticket.status, nvl(sum(service_req), 0) as SUM_REQ
from Change_Ticket, Change
where Change.company_id (+) = '0'
and Change.month (+)='07'
and Change.Id (+) = Change_Ticket.Change_Id
group by Change_Ticket.status
union all
select '' as STATUS, 0 as SUM_REQ
from dual
where not exists (select null from Change_ticket)
Assuming you have the list of your statuses in a table called statuses:
SELECT statuses.id, nvl(sum(service_req), 0) as SUM_REQ
FROM statuses
LEFT JOIN
Change
ON Change.company_id = '0'
AND Change.month = '07'
AND Change.status = statuses.id
LEFT JOIN
Change_Ticket
ON Change_Ticket.Change_Id = Change.Id
GROUP BY
statuses.id
or this (only if you are using 8i, this syntax is deprecated in higher versions):
SELECT statuses.id, nvl(sum(service_req), 0) as SUM_REQ
FROM statuses, Change, Change_Ticket
WHERE Change.company_id(+) = '0'
AND Change.month(+) = '07'
AND Change.status(+) = statuses.id
AND Change_Ticket.Change_Id(+) = Change.Id
GROUP BY
statuses.id
If you only want to show existing statuses or a NULL when no records exist, use this:
SELECT statuses.id, nvl(sum(service_req), 0) as SUM_REQ
FROM dual
LEFT JOIN
Change
ON Change.company_id = '0'
AND Change.month = '07'
LEFT JOIN
Change_Ticket
ON Change_Ticket.Change_Id = Change.Id
GROUP BY
statuses.id

Resources