how to reference an alias in an oracle nested query? - sql

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.

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 ||.

Regarding one query error

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
)

SQL - Select A only if B doesn't exist

I have this SQL statement (modified, because the real query is huge):
select tblInfo.IDNum, tblAddress.PrimaryAddress
from tblInfo
join tblAddress
on tblInfo.Agent = tblAddress.Agent
where (some stuff)
And I get a table that looks roughly like this:
|| IDNum || PrimaryAddress ||
-----------------------------
|| 01234 || 1 ||
|| 23456 || 1 ||
|| abcde || 0 ||
|| abcde || 1 ||
|| zyxwv || 0 ||
I need a way to return all records that have a PrimaryAddress of 1, as well as all records that have a PrimaryAddress of 0 and don't have an IDNum already returning the PrimaryAddress of 1. i.e. In the above example, (abcde || 0) should be excluded because (abcde || 1) exists.
Use NOT EXISTS
SELECT tblInfo.IDNum, tblAddress.PrimaryAddress
FROM tblInfo
INNER JOIN tblAddress
ON tblInfo.Agent = tblAddress.Agent
WHERE tblAddress.PrimaryAddress = 1
OR ( tblAddress.PrimaryAddress = 0 AND NOT EXISTS
(
SELECT 1 FROM tblInfo t2 INNER JOIN tblAddress a2 ON t2.Agent = a2.Agent
WHERE t2.IDNum = tblInfo.IDNum AND a2.PrimaryAddress = 1
)
)
In this case, a simple GROUP BY should work for what you are trying to do. Effectively you are saying you want all IDNum values to appear once, with the PrimaryAddress value corresponding to the highest value (1 if it exists, 0 if it doesn't).
Assuming you need to preserve your original query because you're doing other work with it, you could use:
SELECT IDNum, MAX(PrimaryAddress) AS PrimaryAddress
FROM
(
select tblInfo.IDNum, tblAddress.PrimaryAddress
from tblInfo
join tblAddress
on tblInfo.Agent = tblAddress.Agent
where (some stuff)
)
GROUP BY IDNum
This should work in MS SQL Server and Oracle, not sure about other DBMSs. If the nested query doesn't work in the DBMS you're using, you should be able to populate a temporary table with the results of your first query, then perform the grouping against that table.
I hope this helps
select * from tblAddress mainTBL
where mainTBL.primaryaddress = (Case when EXISTS(select t1.IDNUM from tblAddress t1 where
mainTBL.IDNUM = t1.IDNUM AND t1.primaryAddress = 1) THEN 1 ELSE 0 END)
Check the SQL fiddle

Why does this NOT IN query work as intended, but not this NOT EXISTS query?

Working (NOT IN) retrieves 3 rows:
select DISTINCT d.* from Device d , Company c3
WHERE d.deviceid NOT IN
(
Select d1.deviceid from Device d1, Clone x1
WHERE d1.deviceid = x1.deviceID
AND
(
x1.XPath = 'hi'
OR x1.XPath = 'bye'
)
AND
(
EXISTS ( select * from (SELECT * FROM [dbo].[Split] ('T130SF0W2050', ',')) as s
WHERE x1.Value like '%' + s.items + '%' )
)
)
AND
d.companyid = c3.companyid and c3.companynumber in (SELECT * FROM [dbo].[Split] ('00223200', ','))
Not Working(not exists):
select DISTINCT d.* from Device d , Company c3
WHERE NOT EXISTS
(Select * from Device d1, Clone x1
WHERE d1.deviceid = x1.deviceID
AND
(
x1.XPath = 'hi'
OR x1.XPath = 'bye'
)
AND
(
EXISTS ( select * from (SELECT * FROM [dbo].[Split] ('T130SF0W2050', ',')) as s
WHERE x1.Value like '%' + s.items + '%' )
)
)
AND
d.companyid = c3.companyid and c3.companynumber in (SELECT * FROM [dbo].[Split] ('00223200', ','))
I'm unsure I'm using the exists syntax correct, what should I select from the subquery? I've tried a few different combinations. It won't run if I put WHERE d.deviceid NOT EXISTS
Solution (thanks to Nikola):
add AND d1.deviceid = d.deviceid inside the Exists subquery.
The difference is that the NOT IN query returns devices that match the company and don't match the inner query specification.
For the NOT EXIST query to work as written (where "work as written" refers to returning the same result as the top query), there can't be any devices that exist matching the inner query. If any devices match the inner query at all, the query won't return any results.

How to rewrite this query (PostgreSQL) in SQL Server?

Few days ago I have asked a question about 1,2 and 3. degree connections. Question Link and #Snoopy gave an article link which can fix all my problems. Article Link
I have carefully examined this article but I was unable to use With Recursive query with SQL Server.
PostgreSQL Query:
SELECT a AS you,
b AS mightknow,
shared_connection,
CASE
WHEN (n1.feat1 = n2.feat1 AND n1.feat1 = n3.feat1) THEN 'feat1 in common'
WHEN (n1.feat2 = n2.feat2 AND n1.feat2 = n3.feat2) THEN 'feat2 in common'
ELSE 'nothing in common'
END AS reason
FROM (
WITH RECURSIVE transitive_closure(a, b, distance, path_string) AS
( SELECT a, b, 1 AS distance,
a || '.' || b || '.' AS path_string,
b AS direct_connection
FROM edges2
WHERE a = 1 -- set the starting node
UNION ALL
SELECT tc.a, e.b, tc.distance + 1,
tc.path_string || e.b || '.' AS path_string,
tc.direct_connection
FROM edges2 AS e
JOIN transitive_closure AS tc ON e.a = tc.b
WHERE tc.path_string NOT LIKE '%' || e.b || '.%'
AND tc.distance < 2
)
SELECT a,
b,
direct_connection AS shared_connection
FROM transitive_closure
WHERE distance = 2
) AS youmightknow
LEFT JOIN nodes AS n1 ON youmightknow.a = n1.id
LEFT JOIN nodes AS n2 ON youmightknow.b = n2.id
LEFT JOIN nodes AS n3 ON youmightknow.shared_connection = n3.id
WHERE (n1.feat1 = n2.feat1 AND n1.feat1 = n3.feat1)
OR (n1.feat2 = n2.feat2 AND n1.feat2 = n3.feat2);
or just
WITH RECURSIVE transitive_closure(a, b, distance, path_string) AS
( SELECT a, b, 1 AS distance,
a || '.' || b || '.' AS path_string
FROM edges
WHERE a = 1 -- source
UNION ALL
SELECT tc.a, e.b, tc.distance + 1,
tc.path_string || e.b || '.' AS path_string
FROM edges AS e
JOIN transitive_closure AS tc ON e.a = tc.b
WHERE tc.path_string NOT LIKE '%' || e.b || '.%'
)
SELECT * FROM transitive_closure
WHERE b=6 -- destination
ORDER BY a, b, distance;
As I said, I don't know how to write a recursive query with SQL Server using CTEs. Made a search and examined this page but still no luck. I couldn't run the query.
If someone interested, here is the answer;
I managed to convert the query in question to SQL by;
converting integer values to varchar(MAX). If you don't specify the length of varchar as MAX, you'll get "Types don't match between the anchor and the recursive part in column..."
I replaced || to +
I added ; to the beginning of query
Finally as #a_horse_with_no_name proposed I removed RECURSIVE from query.
Result;
;WITH transitive_closure(a, b, distance, path_string) AS
( SELECT a, b, 1 AS distance,
CAST(a as varchar(MAX)) + '.' + CAST(b as varchar(MAX)) + '.' AS path_string
FROM edges
WHERE a = 1 -- source
UNION ALL
SELECT tc.a, e.b, tc.distance + 1,
CAST(tc.path_string as varchar(MAX)) + CAST(e.b as varchar(MAX)) + '.' AS path_string
FROM edges AS e
JOIN transitive_closure AS tc ON e.a = tc.b
WHERE tc.path_string NOT LIKE '%' + CAST(e.b as varchar(MAX)) + '.%'
)
SELECT * FROM transitive_closure
WHERE b=6 -- destination
ORDER BY a, b, distance;
The recursive CTE should be the same on SQL Server (at least on a recent version, this was introduced with SQL Server 2005 if I'm not mistaken), just leave out the recursive keyword.
Note that SQL Server does not comply with the SQL standard and therefor you need to replace the || concatenation with +