Oracle ORA:00904: Subquery in LEFT JOIN - sql

I'm aware of the subquery limitations of Oracle's ANSI SQL setup. You can't use an identifier in a subquery that is declared more than one level deep.
I'm attempting the following query, which as far as I can see is only one level deep, but I'm getting this error. Does this not work for table joins? (I've truncated the procedure somewhat, but the problem should be clear. Additionally, if it means anything, I'm using FIRST_VALUE analytic functions in my select values. We're on 10g.)
The error:
Error(111,79): PL/SQL: ORA-00904: "VT"."MAIL_TO_ADDRESS_NUMBER": invalid identifier
The proc:
PROCEDURE MYPROCEDURE (
p_TransactionId IN NUMBER,
p_Cursor_Out OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN p_Cursor_Out FOR
SELECT
...
FROM vehicle_transaction vt
INNER JOIN registration_transaction reg ON vt.transaction_id = reg.transaction_id
/* The problem is here */
LEFT OUTER JOIN (
SELECT
laddt2.address
FROM lien_address_transaction laddt2
WHERE vt.mail_to_address_number IS NOT NULL AND laddt2.address_number = vt.mail_to_address_number
) laddt
ON (laddt2.address_number = vt.mail_to_address_number)
WHERE vt.transaction_id = p_TransactionId;
END MYPROCEDURE;

You are trying to do a lateral join. You cannot use an external table alias in the from clause. In general, the work-around is to use aggregation:
SELECT
...
FROM vehicle_transaction vt INNER JOIN
registration_transaction reg
ON vt.transaction_id = reg.transaction_id LEFT OUTER JOIN
(SELECT laddt2.address_number, MIN(laddt2.address) as address
FROM lien_address_transaction laddt2
WHERE vt.mail_to_address_number IS NOT NULL AND
GROUP BY laddt2.address_number
) laddt
ON laddt.address_number = vt.mail_to_address_number
WHERE vt.transaction_id = p_TransactionId;

Related

How to convert inline SQL queries to JOINS in SQL SERVER to reduce load time

I need help in optimizing this SQL query.
In the main SELECT statement there are three columns which is dependent on the outer query result. This is why my query is taking a long time to return data. I have tried making left joins but this is not working properly.
Can anyone help me to resolve this issue?
SELECT
DISTINCT ou.OrganizationUserID AS StudentID,
ou.FirstName,
ou.LastName,
(
SELECT
STRING_AGG(
(ug.UG_Name),
','
)
FROM
Groups ug
INNER JOIN ApplicantUserGroup augm ON augm.AUGM_UserGroupID = ug.UG_ID
WHERE
augm.AUGM_OrganizationUserID = ou.OrganizationUserID
AND ug.UG_IsDeleted = 0
AND augm.AUGM_IsDeleted = 0
) AS UserGroups,
order1.OrderNumber AS OrderId -- UAT-2455
,
(
SELECT
STRING_AGG(
(CActe.CustomAttribute),
','
)
FROM
CustomAttributeCte CActe
WHERE
CActe.HierarchyNodeID = dpm.DPM_ID
AND CActe.OrganizationUserID = ps.OrganizationUserID
) AS CustomAttributes -- UAT-2455
,
(
SELECT
STRING_AGG(
(CActe.CustomAttributeID),
','
)
FROM
CustomAttributeCte CActe
WHERE
CActe.HierarchyNodeID = dpm.DPM_ID
AND CActe.OrganizationUserID = ps.OrganizationUserID
) AS CustomAttributeID
FROM
ApplicantData acd WITH (NOLOCK)
INNER JOIN ClientPackage ps WITH (NOLOCK) ON acd.ClientSubscriptionID = ps.ClientSubscriptionID
INNER JOIN [ClientOrder] order1 WITH (NOLOCK) ON order1.OrderID = ps.OrderID
AND order1.IsDeleted = 0
INNER JOIN OUser ou WITH (NOLOCK) ON ou.OrganizationUserID = ps.OrganizationUserID
It looks like this query can be simplified, and the dependent subqueries in your SELECT clause removed, Consider your second and third dependent subqueries. You can refactor them into one nondependent subquery with a LEFT JOIN. Using nondependent subqueries is more efficient because the query planner can run them just once, rather than once for each row.
You want two STRING_AGG() results from the same table. This subquery gives those two outputs for every possible combination of HierarchyNodeID and OrganizationUserID values. STRING_AGG() is an aggregate function like SUM() and so works nicely with GROUP BY.
SELECT HierarchyNodeID, OrganizationUserID,
STRING_AGG((CActe.CustomAttribute), ',') CustomAttributes -- UAT-2455,
STRING_AGG((CActe.CustomAttributeID), ',') CustomAttributeIDs -- UAT-2455
FROM CustomAttributeCte CActe
GROUP BY HierarchyNodeID, OrganizationUserID
You can run this subquery itself to convince yourself it works.
Now, we can LEFT JOIN that into your query. Like this. (For readability I took out the NOLOCKs and used JOIN: it means the same thing as INNER JOIN.)
SELECT DISTINCT
ou.OrganizationUserID AS StudentID,
ou.FirstName,
ou.LastName,
'tempvalue' AS UserGroups, -- shortened for testing
order1.OrderNumber AS OrderId, -- UAT-2455
uat2455.CustomAttributes, -- UAT-2455
uat2455.CustomAttributeIDs -- UAT-2455
FROM ApplicantData acd
JOIN ClientPackage ps
ON acd.ClientSubscriptionID = ps.ClientSubscriptionID
JOIN ClientOrder order1
ON order1.OrderID = ps.OrderID
AND order1.IsDeleted = 0
JOIN OUser ou
ON ou.OrganizationUserID = ps.OrganizationUserID
LEFT JOIN (
SELECT HierarchyNodeID, OrganizationUserID,
STRING_AGG((CActe.CustomAttribute), ',') CustomAttributes -- UAT-2455,
STRING_AGG((CActe.CustomAttributeID), ',') CustomAttributeIDs -- UAT-2455
FROM CustomAttributeCte CActe
GROUP BY HierarchyNodeID, OrganizationUserID
) uat2455
ON uat2455.HierarchyNodeID = dpm.DPM_ID
AND uat2455.OrganizationUserId = ps.OrganizationUserID
See how we collapsed your second and third dependent subqueries to just one, then used it as a virtual table with LEFT JOIN? We transformed the WHERE clauses from the dependent subqueries into an ON clause.
You can test this: run it with TOP(50) and eyeball the results.
When you're happy, the next step is to transform your first dependent subquery the same way.
Pro tip Don't use WITH (NOLOCK), ever, unless a database administration expert tells you to after looking at your specific query. If your query's purpose is a historical report and you don't care whether the most recent transactions in your database are represented exactly right, you can precede your query with this statement. It also allows the query to run while avoiding locks.
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Pro tip Be obsessive about formatting your queries for readability. You, your colleagues, and yourself a year from now must be able to read and reason about queries like this.

Inner-join errors on SQL stored procedure

I guess I'm just a bit weary, but the answer isn't jumping out for me right now. It throws an error
SQL Error [4145] [S0001]: An expression of non-boolean type specified in a context where a condition is expected, near 'WHERE'
Code:
ALTER PROCEDURE [dbo].[spDirectoryLookup]
(#LookupName nvarchar(100),
#ClientNumber bigint)
AS
BEGIN
SELECT DISTINCT
DL.subid,
C.ClientNumber,
C.ClientName,
listid,
dld.Description
FROM
INTELLIGENT_2414_1.DBO.dirListings DL
INNER JOIN
Intelligent_2414_1.DBO.cltClients C ON DL.subid = C.subid
INNER JOIN
INTELLIGENT_2414_1.DBO.dirListingDescriptions dld ON dld.listID
WHERE
Description LIKE '%'+#LookupName+'%'
AND DL.subid IN (SELECT subid
FROM Intelligent_2414_1.DBO.cltClients C
WHERE C.ClientNumber = #ClientNumber)
END
The second join's on clause is missing a condition. I'm guessing you meant to do this:
INNER JOIN INTELLIGENT_2414_1.DBO.dirListingDescriptions dld on dld.listID = DL.listid

Group BY clause to temporary table

I am beginner in SQL trying to group by a result
SELECT
API.PROJECTNUMBER, Project.ProjectName, Project.PROJMGRID, Staff.Email
INTO
#TEMPUnmatchedProjectWithSMoD
FROM
{ProjectsIncidentsIntegration} API WITH(NOLOCK)
JOIN
{Project} project WITH(NOLOCK) ON Project.ProjectNumber = API.PROJECTNUMBER
JOIN
{COMMON_STAFF} Staff WITH(NOLOCK) ON Staff.EmplId = Project.PROJMGRID
WHERE
NOT EXISTS (SELECT 1
FROM #DBName.DBO.NCompasS_TBL_SMoDIncident SMoD WITH(NOLOCK)
WHERE SMoD.ProjectCode = API.PROJECTNUMBER)
SELECT *
FROM #TEMPUnmatchedProjectWithSMoD
GROUP BY Project.PROJMGRID
I get an error:
Database returned the following error:
Error in advanced query UnmatchedProjectWithSMoD2: The multi-part identifier "Project.PROJMGRID" could not be bound.
The problem appears to be in this query:
SELECT *
FROM #TEMPUnmatchedProjectWithSMoD
GROUP BY Project.PROJMGRID ;
There are two major issues:
SELECT * with GROUP BY is not correct. What should be done with the columns that are not aggregation keys? You might have some idea. SQL generates an error.
Project is not defined.
It is quite unclear what this code is supposed to be doing, so I cannot suggest anything useful. You can just select all rows from the temporary table using:
SELECT p.*
FROM #TEMPUnmatchedProjectWithSMoD p;

postgresql: join syntax error when joining 2 select statements

I am querying the aact database from clinicaltrials.gov. The database model is right here: https://aact.ctti-clinicaltrials.org/schema. I have two schemas that I am selecting from (ctgov, proj_cdek_standard_orgs). I am trying to join two select statements. edit: I have now tried aliasing my subqueries, but that still does nothing. I get the following error:
(SELECT ctgov.sponsors.name, ctgov.sponsors.nct_id, ctgov.sponsors.id, ctgov.studies.phase
FROM ctgov.sponsors, ctgov.studies
WHERE ctgov.sponsors.nct_id=ctgov.studies.nct_id) A
FULL [OUTER] JOIN
(SELECT proj_cdek_standard_orgs.cdek_synonyms.id, proj_cdek_standard_orgs.cdek_synonyms.name
FROM proj_cdek_standard_orgs.cdek_synonyms) B
ON
A.name = B.name;
I can do both select statements perfectly fine on their own, but I try the query and I get this error:
ERROR: syntax error at or near "t1" LINE 7: ) t1
What did I do wrong and how do I use joins without getting syntax errors?
Please use below query,
SELECT ctgov.sponsors.name, ctgov.sponsors.nct_id, ctgov.sponsors.id,
ctgov.studies.phase, proj_cdek_standard_orgs.cdek_synonyms.id,
proj_cdek_standard_orgs.cdek_synonyms.name
FROM ctgov.sponsors, ctgov.studies, proj_cdek_standard_orgs.cdek_synonyms
WHERE ctgov.sponsors.nct_id=ctgov.studies.nct_id
and proj_cdek_standard_orgs.cdek_synonyms.name = ctgov.sponsors.name;
But the right way is to use traditional joins,
SELECT ctgov.sponsors.name, ctgov.sponsors.nct_id, ctgov.sponsors.id,
ctgov.studies.phase, proj_cdek_standard_orgs.cdek_synonyms.id,
proj_cdek_standard_orgs.cdek_synonyms.name
FROM ctgov.sponsors
INNER JOIN ctgov.studies
ON (ctgov.sponsors.nct_id=ctgov.studies.nct_id)
INNER JOIN proj_cdek_standard_orgs.cdek_synonyms
ON (proj_cdek_standard_orgs.cdek_synonyms.name = ctgov.sponsors.name);
You can change it to LEFT or FULL OUTER JOIN according to your requirement.
You have to provide an alias to the sub-queries. Also you should not use implicit joins as you have used in first subquery, always try to use explicit joins.
SELECT
*
FROM
(
SELECT
ctgov.sponsors.name, ctgov.sponsors.nct_id, ctgov.sponsors.id, ctgov.studies.phase
FROM ctgov.sponsors
JOIN ctgov.studies
ON ctgov.sponsors.nct_id=ctgov.studies.nct_id
) t1
FULL JOIN
(
SELECT
proj_cdek_standard_orgs.cdek_synonyms.id, proj_cdek_standard_orgs.cdek_synonyms.name
FROM proj_cdek_standard_orgs.cdek_synonyms
) t2
ON
t1.name = t2.name;

SQL UNIONs that use the WITH statement

I have to run this query on 20 databases to produce one unified report. I've done this before with a UNION. Is there any way to reuse the WITH statement for each sub-query? I am receiving an error saying that the previous statement must be terminated with a semicolon. Could there be a better way of doing this?
WITH
DUPS (DocNum)
AS (
SELECT DocNum
FROM Akron.dbo.PWZ3
INNER JOIN Akron.dbo.OPWZ T5 ON T5.IdNumber = PWZ3.IdEntry
WHERE T5.PmntDate = '3/10/2011'
GROUP BY DocNum
HAVING COUNT(1) > 1;
)
SELECT PWZ3.IdEntry, PWZ3.DocNum, 'ARK' + PWZ3.CardCode, QUOTENAME(CardName,'"'),
Convert(Decimal(10,2),PayAmount), Convert(Decimal(10,2),InvPayAmnt),
CONVERT(VARCHAR(10), T5.PmntDate,101), NumAtCard, PymMeth, ObjType
FROM Akron.dbo.PWZ3 PWZ3
INNER JOIN DELAWARE.dbo.OPWZ T5 ON T5.IdNumber = PWZ3.IdEntry
LEFT JOIN Dups ON DUPS.DocNum = PWZ3.DocNum
WHERE T5.PmntDate = '3/10/2011'
AND T5.Canceled = 'N'
AND Checked = 'Y'
AND Dups.DocNum is null
The WITH statement indicates that the query expressed within the AS clause is a Common Table Expression (CTE).
If you're asking if you can write more than one query that uses a CTE, then the answer is no. The closest approximation would be creating an inline table-valued function.
(The simple definition of an ordinary table-valued function versus an inline table-valued function is that the inline version is defined only as a query, much like a CTE; you can't do any procedural operations within the function, including declaring/assigning variables).
The following works for me:
WITH stuff AS (
... some select
)
SELECT some_col
FROM some_table
JOIN stuff ON ...
UNION ALL
SELECT other_col
FROM other_table
JOIN stuff ON ...
Tested on PostgreSQL and Oracle