Regarding one query error - sql

Here is my Requirement when I am using the below query I am getting the correct response but the problem is I want to select the distinct records so please help me how can I use distinct in the below query
SELECT LISTAGG(PAC.DESCRIPTION || ' = '|| ORL.ITEM_PACKAGE_COUNT , ',') WITHIN GROUP (ORDER BY PAC.DESCRIPTION || ' = '|| ORL.ITEM_PACKAGE_COUNT)
FROM ORDER_RELEASE_LINE ORL , PACKAGED_ITEM PAC , SHIPMENT SH , ORDER_MOVEMENT OM
WHERE ORL.PACKAGED_ITEM_GID = PAC.PACKAGED_ITEM_GID
AND OM.ORDER_RELEASE_GID = ORL.ORDER_RELEASE_GID
AND OM.SHIPMENT_GID = SH.SHIPMENT_GID
AND SH.SHIPMENT_GID = 'ULA/SAO.5000072118'

Your subquery returns SELECT DISTINCT PAC.DESCRIPTION but outer query uses aliases and values from inner query LISTAGG(PAC.DESCRIPTION || ' = '|| ORL.ITEM_PACKAGE_COUNT , ',') ORL.ITEM_PACKAGE_COUNT is not returned by subquery. Try:
SELECT LISTAGG(SUBQ.DESCRIPTION || ' = '|| SUBQ.ITEM_PACKAGE_COUNT , ',')
WITHIN GROUP (ORDER BY SUBQ.DESCRIPTION || ' = '|| SUBQ.ITEM_PACKAGE_COUNT)
FROM (SELECT DISTINCT PAC.DESCRIPTION, ORL.ITEM_PACKAGE_COUNT
FROM ORDER_RELEASE_LINE ORL , PACKAGED_ITEM PAC , SHIPMENT SH , ORDER_MOVEMENT OM
WHERE ORL.PACKAGED_ITEM_GID = PAC.PACKAGED_ITEM_GID
AND OM.ORDER_RELEASE_GID = ORL.ORDER_RELEASE_GID
AND OM.SHIPMENT_GID = SH.SHIPMENT_GID
AND SH.SHIPMENT_GID = 'ULA/SAO.5000072118') SUBQ
Generally it is wrong practice to use same alias PAC in inner query for a table and in outer query for result of joined data. Another wrong practice is using implicit joins instead of defining explicit INNER JOIN ON

If you need to get distinct values from a query, and then build the LISTAGG of these distinct values, you can simply use DISTINCT in your query and wrap it with an external one where you use LISTAGG.
For example:
with dupValTab(s) as
(
select 'something' from dual union all
select 'something else' from dual union all
select 'something' from dual
)
select listagg(s, ', ') within group (order by s)
from (
select distinct s
from dupValTab
)

Related

Dynamic column fields using existing column values in SQL

I have this existing query
Select
mt.First_name,
mt.Last_name as OLD_Last_name,
ot.Last_name as New_Last_name,
ot.Date as Update_Date,
from maintable as mt
JOIN othertable as ot on mt.id=ot.id
I'd like to join a new column with the following output:
[mt.First_name] [ot.Last_name], nee [mt.Last_name] changed their name on [ot.Date].
I tried using a case statement but didn't get it right.
For closure, moving #Jnevill answer from comment to actual answer:
SELECT mt.First_name || ' ' || ot.Last_name || ', nee ' || mt.last_name || ' changed their name on ' || ot.Date AS yournewcolumn, mt.First_name
, mt.Last_name as OLD_Last_name
, ot.Last_name as New_Last_name
, ot.Date as Update_Date
from maintable as mt
JOIN othertable as ot on mt.id=ot.id
Apparently OP wanted to know how to concatenate strings, which is done with ||.

Optimize query using Concat method

I have a query which uses join, then group by caseId and then a concat-like function using STUFF.
SELECT distinct [CaseID], STUFF((SELECT ';' +space(1)+ A.[AssignedPathologist]+' ' FROM CTE1 A
WHERE A.[CaseID]=B.[CaseID] FOR XML PATH('')),1,1,'') As [AssignedPathologist]
From CTE1 B
Group By [CaseID]
The problem is that this query is super, super-slow and I tried to optimize it using CONCAT instead.
SELECT distinct A.[CaseID], [AssignedPathologist] = CASE A.AssignedPathologist = B.AssignedPathologist
WHEN 1 THEN A.AssignedPathologist
ELSE CONCAT(A.AssignedPathologist, ' ', B.AssignedPathologist)
END
FROM CTE1 A
INNER JOIN CTE1 B ON A.[CaseID]=B.[CaseID]
END
but it gives me syntax error here
[AssignedPathologist] = CASE A.AssignedPathologist = B.AssignedPathologist
which is logic because I used twice = here.
Is there any method to optimize my query using CONCAT or another methods ?
Thank you
I would try with this :
SELECT [CaseID],
STUFF( (SELECT CONCAT('; ', A.[AssignedPathologist])
FROM CTE1 A
WHERE A.[CaseID] = B.[CaseID]
FOR XML PATH('')
),1, 1, ''
) As [AssignedPathologist]
FROM (SELECT DISTINCT CaseID CTE1 B) B;
For newer versions you can use string_agg() :
SELECT CASEID, STRING_AGG(AssignedPathologist, '; ') AS AssignedPathologist
FROM CTE1 C1
GROUP BY CASEID;

how to join multiple select statement with full outer join. Error: subquery is returning more than one row

I have this code have been battling with since yesterday, when I unit test each part of this code, it is working, but I need to put them together to generate one output result. This is the full code below : but is giving subquery is returning more than one row.
SELECT NVL(TO_CHAR(D_TRANS.TRANS), 'NULL') AS ID, 'HEADER', D_SPILL.status,
(SELECT L_APPLICATION.APPLICATION
FROM L_APPLICATION L_APPLICATION
WHERE LANGUAGE = 2 AND APPLICATION = D_TRANS.APPLICATION)
AS CASE_TYPE,
NVL(TO_CHAR(D_TRANS.UNIT_IN_CHARGE), 'NULL') AS UNIT_IN_CHARGE,
NVL(TO_CHAR(D_TRANS.PERSON_IN_CHARGE), 'NULL') AS PERSON_IN_CHARGE,
NVL(TO_CHAR(D_TRANS.STATUS), 'NULL') AS CASE_STATUS,
NVL(TO_CHAR(D_TRANS.DEADLINE), 'NULL') AS INTERNAL_DEADLINE,
( select xmlquery('distinct-values(//text())' passing xmldoc returning content).getclobVal()
FROM ( select d_synergi_category.trans,
coalesce(max(case when language = 2 then description end), 'NULL'),
XMLELEMENT(root,xmlagg(XMLELEMENT(e,description,','))
) xmldoc
from L_CASE_CATEGORY
LEFT JOIN d_synergi_category ON d_synergi_category.case_category = L_CASE_CATEGORY.case_category
group by d_synergi_category.trans
)
)
FROM D_TRANS
FULL OUTER JOIN D_SPILL
ON D_TRANS.TRANS=D_SPILL.TRANS
ORDER BY D_TRANS.TRANS DESC;
If I remove the part code below with xmltagg and test both parts of the code separately it is working.
First part working separately
( select xmlquery('distinct-values(//text())' passing xmldoc returning content).getclobVal()
FROM ( select d_synergi_category.trans,
coalesce(max(case when language = 2 then description end), 'NULL'),
XMLELEMENT(root,xmlagg(XMLELEMENT(e,description,','))
) xmldoc
from L_CASE_CATEGORY
LEFT JOIN d_synergi_category ON d_synergi_category.case_category = L_CASE_CATEGORY.case_category
group by d_synergi_category.trans
)
)
Second part working separately is :
SELECT NVL(TO_CHAR(D_TRANS.TRANS), 'NULL') AS ID, 'HEADER',D_SPILL.status,
(SELECT L_APPLICATION.APPLICATION FROM L_APPLICATION
WHERE L_APPLICATION WHERE LANGUAGE = 2
AND APPLICATION = D_TRANS.APPLICATION) AS CASE_TYPE ,
NVL(TO_CHAR(D_TRANS.UNIT_IN_CHARGE), 'NULL') AS UNIT_IN_CHARGE,
NVL(TO_CHAR(D_TRANS.PERSON_IN_CHARGE), 'NULL') AS PERSON_IN_CHARGE,
NVL(TO_CHAR(D_TRANS.STATUS), 'NULL') AS CASE_STATUS ,
NVL(TO_CHAR(D_TRANS.DEADLINE), 'NULL') AS INTERNAL_DEADLINE
FROM D_TRANS
FULL OUTER JOIN D_SPILL
ON D_TRANS.TRANS=D_SPILL.TRANS
ORDER BY D_TRANS.TRANS DESC;
Query (SELECT rtrim(xmlagg( ... must return exactly one row.
We don't have your tables nor data, but it seems that you didn't join its tables (L_CASE_CATEGORY, D_SYNERGI_CATEGORY) with any of tables contained in main query's FROM clause (TRANS, D_SPILL). I suggest you do that and see what happens.
[EDIT]
This is what I meant:
select nvl(to_char(d_trans.trans, 'null') as id,
...,
rtrim(xmlagg(xmlelement(...)) as some_name --> XLM stuff goes here
from l_case_category left join d_synergi_category on ...
join l_case_category on ... --> XML subquery's tables go here,
--> properly joined to other tables
What #Littlefoot said, but I'm going to take a guess at how your tables might be joined, so that you have an example.
SELECT NVL(TO_CHAR(D_TRANS.TRANS), 'NULL') AS ID, 'HEADER',D_SPILL.status,
(SELECT L_APPLICATION.APPLICATION FROM L_APPLICATION
WHERE L_APPLICATION WHERE LANGUAGE = 2
AND APPLICATION = D_TRANS.APPLICATION) AS CASE_TYPE ,
NVL(TO_CHAR(D_TRANS.UNIT_IN_CHARGE), 'NULL') AS UNIT_IN_CHARGE,
NVL(TO_CHAR(D_TRANS.PERSON_IN_CHARGE), 'NULL') AS PERSON_IN_CHARGE,
NVL(TO_CHAR(D_TRANS.STATUS), 'NULL') AS CASE_STATUS ,
NVL(TO_CHAR(D_TRANS.DEADLINE), 'NULL') AS INTERNAL_DEADLINE,
(SELECT rtrim(xmlagg(
XMLELEMENT(e,L_CASE_CATEGORY.DESCRIPTION,',').EXTRACT('//text()')
).GetClobVal(),',')
FROM L_CASE_CATEGORY
INNER JOIN D_SYNERGI_CATEGORY on -- changed
D_SYNERGI_CATEGORY.CASE_CATEGORY = L_CASE_CATEGORY.CASE_CATEGORY
AND L_CASE_CATEGORY.LANGUAGE = 2
WHERE d_synergi_category.trans = D_TRANS.TRANS -- added this line
GROUP BY D_SYNERGI_CATEGORY.CASE_CATEGORY, d_synergi_category.trans) AS CAT_DESC_LIST
FROM D_TRANS
FULL OUTER JOIN D_SPILL
ON D_TRANS.TRANS=D_SPILL.TRANS
ORDER BY D_TRANS.TRANS DESC;
Edit: updated from your comment. This would be a lot easier if you provided table structure and example data.
Your subquery SELECT rtrim(xmlagg(... returns one row per CASE_CATEGORY and trans, because of:
GROUP BY D_SYNERGI_CATEGORY.CASE_CATEGORY, d_synergi_category.trans
When you put it in the main query's select clause, however, you don't want it to return all those rows per main query row, but the one row matching the main query row (just like you find the matching application row with WHERE APPLICATION = D_TRANS.APPLICATION).
So remove the GROUP BY clause and replace it with the WHERE clause instead. Something like
(
SELECT
RTRIM(XMLAGG(
XMLELEMENT(e, cc.description,',').EXTRACT('//text()')
).GetClobVal(),',')
FROM l_case_category cc
JOIN d_synergi_category sc ON sc.case_category = cc.case_category
WHERE sc.case_category = d_spill.case_category -- <=== here
AND sc.trans = d_trans.trans -- <=== and here
and cc.language = 2
)
(Just replace my criteria with your real criteria. Only you know how the tables are related. It is hard for me to even figure it out what the query is supposed to return. I don't understand why you full outer join with D_SPILL in one of the separate queries, without using any of its columns in the select clause. I don't know either why you outer join D_SYNERGI_CATEGORY on L_CASE_CATEGORY.LANGUAGE = 2 in the other query. This seems strange.)

How to enhance the performance of nested query?

I have the following query but it run slowly in my sql editor !
How to enhance it (write wise) to speed the query running .
SELECT year,main_code,name,father_code,main_code || '__' || year AS main_id,
(SELECT COUNT(*) FROM GK_main
WHERE father_code=sc.main_code AND
year= (SELECT MAX(year)FROM SS_job)) childcount
FROM GK_main sc WHERE year=(SELECT MAX(year)FROM SS_job)
The efficiency depends more on available indexes, rather than the way it is written. You could try this version (without inline subqueries):
SELECT
sc.year,
sc.main_code,
sc.name,
sc.father_code,
sc.main_code || '__' || sc.year AS main_id,
NVL(g.childcount, 0) AS childcount
FROM
GK_main sc
LEFT JOIN
( SELECT father_code ,
COUNT(*) AS childcount
FROM GK_main
WHERE year = (SELECT MAX(year) FROM SS_job)
GROUP BY father_code
) AS g
ON g.father_code = sc.main_code
WHERE
sc.year = (SELECT MAX(year) FROM SS_job) ;
But what would benefit the efficiency would be indexes.
Is there an index on SS_job (year)?
Is there an index on GK_main (year, father_code) or on GK_main (father_code, year)?
Is there an index on GK_main (year, main_code) or on GK_main (main_code)?
Use a join instead of subquery.
SELECT sc.year,sc.main_code,sc.name,sc.father_code,sc.main_code || '__' || sc.year AS main_id,
COUNT(F.father_code) AS childcount
FROM GK_main sc LEFT JOIN GK_main F ON F.father_code = sc.main_code
WHERE year=(SELECT MAX(year)FROM SS_job)
GROUP BY sc.year,sc.main_code,sc.name,sc.father_code
Not tested and made it quickly so might contain a mistake. But this should at least save you from checking SELECT MAX(year)FROM SS_job twice.
I would never do COUNT(*), but always chose the collumn(s) I wish to count.
Try this query
SELECT
year,
main_code,
name,
father_code,
main_code || '__' || year AS main_id,
childcount.cnt as 'count'
FROM
GK_main sc
LEFT JOIN
(SELECT
father_code,
COUNT(*) AS cnt
FROM
GK_main
WHERE
year= (SELECT MAX(year)FROM SS_job)
GROUP BY
father_code) childcount
ON childcount.father_code = sc.main_code
Create necesary index on (father_code, year) that will help

how to reference an alias in an oracle nested query?

I have a couple of nested queries like this:
(SELECT "impartidas"."idUsuarioProf"
FROM "impartidas"
WHERE "impartidas"."periodo" = "periodoPlanGrado"."periodo" and
"impartidas"."idMateria" = "materiasPlan"."idMateria") T,
(SELECT "usuarios"."apellidoPaterno" || ' , ' || "usuarios"."nombres"
FROM "usuarios"
WHERE "usuarios"."idUsuario" = 36) as "nomprofesor"
The first one outputs the teacher ID in a column named T.
What do I need to change in the second query, just so that instead of 36, it uses the value that was shown in column aliased T?
In short I need to perform the second query, based on the output ID value of the first query.
r In the absence of any context it's difficult to understand why you're taken such a convoluted approach. The obvious approach is just a straightforward join:
SELECT "impartidas"."idUsuarioProf"
, "usuarios"."apellidoPaterno" || ' , ' || "usuarios"."nombres" "nomprofesor"
FROM "impartidas"
, "periodoPlanGrado"
, "materiasPlan"
, "usuarios"
WHERE "impartidas"."periodo" = "periodoPlanGrado"."periodo"
and "impartidas"."idMateria" = "materiasPlan"."idMateria") T
and "usuarios"."idUsuario" = "impartidas"."idUsuarioProf"
/
But if you really need the inlining then you would need to do the joining externally, something like this:
select P."nomprofesor"
from
(SELECT "impartidas"."idUsuarioProf"
FROM "impartidas"
, "periodoPlanGrado"
, "materiasPlan"
WHERE "impartidas"."periodo" = "periodoPlanGrado"."periodo"
and "impartidas"."idMateria" = "materiasPlan"."idMateria") T,
(SELECT "usuarios"."apellidoPaterno" || ' , ' || "usuarios"."nombres" as "nomprofesor"
, "usuarios"."idUsuario"
FROM "usuarios" ) P
WHERE P."idUsuario" = T."idUsuarioProf"
Note that you need to include all the joining columns in the projection of each sub-query. As, you need to use an aliases to reference a derived column in the outer query.
What about this:
SELECT "usuarios"."apellidoPaterno" || ' , ' || "usuarios"."nombres" AS "nomprofesor"
FROM "usuarios"
WHERE "usuarios"."idUsuario" = (
SELECT "impartidas"."idUsuarioProf"
FROM "impartidas", "periodoPlanGrando", "materiasPlan"
WHERE "impartidas"."periodo" = "periodoPlanGrado"."periodo"
AND "impartidas"."idMateria" = "materiasPlan"."idMateria"
)
or maybe
SELECT "usuarios"."apellidoPaterno" || ' , ' || "usuarios"."nombres" AS "nomprofesor"
FROM "usuarios"
WHERE "usuarios"."idUsuario" IN (
SELECT "impartidas"."idUsuarioProf"
FROM "impartidas", "periodoPlanGrando", "materiasPlan"
WHERE "impartidas"."periodo" = "periodoPlanGrado"."periodo"
AND "impartidas"."idMateria" = "materiasPlan"."idMateria"
)
if multiple rows might be generated by the subquery (I do not know the schema and my Spanish is not very good (IS NULL) to understand what might be in the "impartidas" table).
For code maintenance and readability reasons I would write this:
SELECT u.apellidoPaterno || ' , ' || u.nombres AS nomprofesor
FROM usuarios u
WHERE u.idUsuario = (
SELECT i.idUsuarioProf
FROM impartidas i
INNER JOIN periodoPlanGrando p USING ( periodo )
INNER JOIN materiasPlan m USING ( idMateria )
-- WHERE (other condifitions)
)
or even this:
SELECT u.apellido_paterno || ' , ' || u.nombres AS nom_profesor
FROM usuarios u
WHERE u.id_usuario = (
SELECT i.id_usuario_prof
FROM impartidas i
INNER JOIN periodo_plan_grado p USING ( periodo )
INNER JOIN materias_plan m USING ( id_materia )
-- WHERE (other condifitions)
)
but this would require refractoring table and column names to be more Oracle identifier like.