DB2 - Invalid use of an aggregate function SQLCODE=-120 - sql

Can anyone help me to understand what is wrong with this Db2 query syntax,it is failing with SQLCODE -120 because i am trying to use row_number()?
SELECT COUNT(ORDER_ID) OVER() TOTAL_NO_OF_RECORDS,
ROW_NUMBER() OVER (ORDER BY CREATED_DATE DESC) AS ROW_NUM
FROM (
SELECT DISTINCT A.ORDER_ID ORDER_ID,
B.AgencyName AS AGENCY_NAME,
C.FirstName FIRST_NAME,
C.LastName LAST_NAME,
DEMOGRAPHIC.State STATE,
A.CreatedTS CREATED_DATE,
E.WritingTIN WRITING_TIN,
E.ParentTIN PARENT_TIN
FROM DBO.TABLE1 A
INNER JOIN
DBO.TABLE2 TABLE2 ON TABLE2.ORDER_ID=A.ORDER_ID
INNER JOIN
DBO.TABLE3 TABLE3 ON TABLE3.QuoteId=TABLE2.QuoteId
INNER JOIN
DBO.Demographic DEMOGRAPHIC ON
DEMOGRAPHIC.DemographicId=TABLE3 .DemographicId
INNER JOIN
DBO.Agent E ON E.AgentId=DEMOGRAPHIC.AgentId
INNER JOIN
DBO.User USER ON USER.WebAcctID=AGENT.WebAcctId
INNER JOIN
DBO.Shopper SHOPPER ON SHOPPER.ShopperId=DEMOGRAPHIC.ShopperId
LEFT OUTER JOIN
DBO.Subsidy D ON D.demographicId=DEMOGRAPHIC.demographicId
LEFT OUTER JOIN
DBO.Employer EMPLOYER ON DEMOGRAPHIC.demographicId=EMPLOYER.demographicId
WHERE E.WritingTIN = 'XYZ' AND E.ParentTIN = 'XYZ'
AND DEMOGRAPHIC.State='OH'
AND A.Status IN ('X','Y','Z')
)AS ORDER_DETAILS
where ROW_NUMBER() OVER (ORDER BY CREATED_DATE DESC) BETWEEN ((1*50)-50)+1 AND 1*50 ORDER BY CREATED_DATE DESC
ERROR SHOWN:Invalid use of an aggregate function or OLAP function.. SQLCODE=-120, SQLSTATE=42903, DRIVER=4.18.60

You have multiple errors:
X is not defined in the subquery.
B.CREATED_DATE is referenced in the outer query, but it is not defined.
ROW_NUMBER() is used in the WHERE clause.
This would seem to be the intention of the query you write:
SELECT COUNT(*) OVER () NO_OF_RECORDS, ROW_NUM
FROM (SELECT A.ID, B.FirstName as FIRST_NAME, B.LastName as LAST_NAME,
MAX(B.CREATED_DATE) as CREATED_DATE,
ROW_NUMBER() OVER (ORDER BY MAX(CREATED_DATE) DESC) AS ROW_NUM
FROM SCHEMANAME.A A INNER JOIN
SCHEMANAME.B B
ON B.ShopperId = A.ShopperId LEFT OUTER JOIN
SCHEMANAME.C C
ON C.demographicId = B.demographicId
WHERE A.WritingTIN = 'XYZ' AND A.ParentTIN = 'XYZ' AND
B.State = 'OH' AND C.Status IN ('X', 'Y', 'Z')
GROUP BY A.ID, B.FirstName, B.LastName
) ORDER_DETAILS
WHERE ROW_NUM BETWEEN ((1*50)-50)+1 AND 1*50
ORDER BY CREATED_DATE DESC;
I'm not sure that this result makes sense, but it should fix your error.

Related

How to combine multiple rows into one ,getting the one column that differs as comma separated values in t-sql?

I want to combine multiple rows into one, getting the one column that differs as comma-separated values.
I have written the below query and it gives the result as shown below.
I want 4 rows instead of 9, the last column should appear comma separated like (Storage, Wastewater, Misc).
Please help with your ideas, Thanks in advance!
SELECT DISTINCT
C.CONTRACTID, C.NUMBER, C.STATE,
O.CUSTOMERCODE, O.CUSTOMERNAME,
C.STARTDATE, C.TERMINATIONDATE, CT.Name AS CONTRACTTYPELIST
FROM
[DBO].[CONTRACT] C
INNER JOIN
[ORD].[ORDER] O ON C.CUSTOMERID = O.CUSTOMERID
INNER JOIN
[dbo].[Contract_ContractType] CCT ON CCT.ContractId = C.ContractId
INNER JOIN
[Ref].[ContractType] CT ON CT.ContractTypeId = CCT.ContractTypeId
WHERE
O.ORDERSTATEID = 6
ORDER BY
c.ContractId
I updated the query like below , but it gives long string in the last column but i want only values for that particular record id in one row. How can this be corrected ?
SELECT distinct
C.CONTRACTID,C.NUMBER, C.STATE ,
O.CUSTOMERCODE,O.CUSTOMERNAME ,
C.STARTDATE , C.TERMINATIONDATE ,
STRING_AGG(CAST(CT.Name AS NVARCHAR(MAX)) , ',') AS CONTRACTTYPELIST
FROM
[DBO].[CONTRACT] C
INNER JOIN
[ORDERING].[ORDER] O ON C.CUSTOMERID = O.CUSTOMERID
INNER JOIN
[dbo].[Contract_ContractType] CCT on CCT.ContractId = C.ContractId
INNER JOIN
[Ref].[ContractType] CT on CT.ContractTypeId = CCT.ContractTypeId
WHERE
O.ORDERSTATEID = 6
GROUP BY
C.CONTRACTID,C.NUMBER, C.STATE ,
O.CUSTOMERCODE,O.CUSTOMERNAME ,
C.STARTDATE , C.TERMINATIONDATE
You want to use a GROUP BY clause together with the STRING_AGG function
Example:
SELECT STRING_AGG(column_D, ',')
FROM dbo.table
GROUP BY column_A, column_B, column_C
Wrap the query with the DISTINCT in a sub-query.
Then use STRING_AGG in the outer query.
SELECT
CONTRACTID, [NUMBER], STATE,
CUSTOMERCODE, CUSTOMERNAME,
STARTDATE, TERMINATIONDATE,
STRING_AGG(CONTRACTTYPE,',') AS CONTRACTTYPELIST
FROM
(
SELECT DISTINCT
C.CONTRACTID, C.NUMBER, C.STATE,
O.CUSTOMERCODE, O.CUSTOMERNAME,
C.STARTDATE, C.TERMINATIONDATE,
CT.Name AS CONTRACTTYPE
FROM
[DBO].[CONTRACT] C
JOIN [ORDERING].[ORDER] O
ON C.CUSTOMERID = O.CUSTOMERID
JOIN [dbo].[Contract_ContractType] CCT
ON CCT.ContractId = C.ContractId
JOIN [Ref].[ContractType] CT
ON CT.ContractTypeId = CCT.ContractTypeId
WHERE
O.ORDERSTATEID = 6
) q
GROUP BY
CONTRACTID, [NUMBER], STATE,
CUSTOMERCODE, CUSTOMERNAME,
STARTDATE, TERMINATIONDATE

Using SQL how can I write a query to find the top 5 per category per month?

I am trying to get the Top 5 rows with the highest number for each category for a specific time interval such as a month. What I currently have returns 5 of the exact same descriptions for a category. I am trying to get the top five. This only happens when I try to sort it based on a time period.
WITH CustomerRank
AS
(SELECT
Count(*) AS "Count",
d.Item,
d.Description,
Name,
i.Type,
d.CreatedOn
FROM [dbo].i,
d,
dbo.b,
as,
a,
c
WHERE d.Inspection_Id = i.Id AND d.Inspection_Id = i.Id AND
b.Id = i.BuildingPart_Id AND b.as= Assessments.Id
AND as.Application_Id = a.Id AND a.Customer_Id = Customers.Id
group by d.Item, d.Description, Name, i.Type, d.CreatedOn
)
select * from (
SELECT "Count",Item,Description,Type,ROW_NUMBER() Over (PARTITION BY Name order by "Count" desc) AS RowNum, Name, CreatedOn
FROM CustomerRank
where CreatedOn > '2017-1-1 00:00:00'
) s where RowNum <6
Cheers
Try something like this:
WITH CustomerRank
AS
(SELECT
Count(*) AS "Count",
d.Item, d.Description, Name, i.Type
FROM dbo.Inspection i
INNER JOIN dbo.Details d ON d.Inspection_Id = i.Id
INNER JOIN dbo.BuildingParts b ON b.Id = i.BuildingPart_Id
INNER JOIN dbo.Assessments a ON a.Id = b.AssessmentId
INNER JOIN dbo.Applications ap ON ap.Id = a.Application_Id
INNER JOIN dbo.Customers c ON c.Id = a.Customer_Id
where CreatedOn > '2017-1-1 00:00:00'
group by d.Item, d.Description, Name, i.Type
)
select * from (
SELECT "Count",Item,Description,Type,ROW_NUMBER() Over (PARTITION BY Name order by "Count" desc) AS RowNum, Name
FROM CustomerRank
) s where RowNum <6
The idea is that the CreatedOn column must be removed from the GROUP BY clause (because if you keep it there, we would get a different row for each value of the CreatedOn column).
Also, it's better to use JOIN-s and aliases for each table.

Joining two tables with special case on the right table?

I have two tables: Candidate: {Id, Name} and Candidate_Education: {Id, CandidateId, Education, GraduationDate}
I want to show the candidate name and his last education , I made that query:
SELECT c.Name, ce.Education AS 'Last Education'
FROM Candidate c
LEFT JOIN Candidate_Education ce
ON c.Id = (SELECT TOP 1 CandidateID FROM Candidate_Education
ORDER BY GraduationDate DESC)
But the results is not correct, there are Candidates who assigned Educations they don't have relation with Candidate_Education
More typical ways to do what you want use ROW_NUMBER() or OUTER APPLY:
SELECT c.Name, ce.Education
FROM Candidate c OUTER APPLY
(SELECT TOP 1 ce.*
FROM Candidate_Education ce
WHERE ce.CandidateID = c.CandidateID
ORDER BY ce.GraduationDate DESC
) ce;
Your query is missing a join condition between the two tables in the FROM clause. However, there are alternatives that are more appropriate for SQL Server.
other solution
with OneCandidate as (
select * from (
select ce.*, ROW_NUMBER() over(partition by ce.CandidateID order by ce.CandidateID desc) rang
from Candidate_Education ce
) tmp
where tmp.rang=1
)
SELECT c.Name, ce.Education
FROM Candidate c left outer OneCandidate ce on ce.CandidateID = c.CandidateID
WITH maxGraduationCTE AS
(SELECT Id, MAX(GraduationDate) AS 'Last Education' FROM Candidate_Education
GROUP BY Id),
lastEducationCTE AS
(SELECT [Last Education], ce.Id, ce.CandidateId, ce.Education FROM maxGraduationCTE
INNER JOIN Candidate_Education ce ON maxGraduationCTE.Id = ce.Id);
SELECT c.Name,
CASE WHEN [Last Education] IS NULL THEN 'No Education'
ELSE CAST([Last Education] As Varchar)
END As [Last Education]
FROM Candidate c
LEFT JOIN lastEducationCTE ce
ON c.Id = ce.CandidateId
You could use two CTE expressions and a left join with a CASE statement to handle null values. I used a case because I wasn't sure about the data type for the GraduationDate...may have to convert it because if it is a date, you can't mix varchar and date data types

Get the biggest price using MAX() function

I am using SQL Oracle, and I want to change my query using MAX function and not ROWNUM.
SELECT *
FROM (SELECT a.name, price.price
FROM price
LEFT JOIN a
ON a.id = price.tk_a
ORDER BY price.price DESC)
WHERE ROWNUM <=1;
Any help or suggestions please?
You can use the MAX aggregate function with KEEP ( DENSE_RANK FIRST ORDER BY ... ) to get the maximum of another column:
SELECT MAX( a.name ) KEEP ( DENSE_RANK FIRST ORDER BY p.price DESC ) AS name,
MAX( p.price ) AS price
FROM a
LEFT OUTER JOIN price p
ON ( a.id = p.tk_a );
Try this:
select a1.name, p1.price
from price p1
JOIN a a1 ON a1.id = p1.tk_a
JOIN (SELECT MAX(p.price)
FROM price p) C on p1.price = c.price
MAX and group by
SELECT a.name, MAX(p.price)
FROM price
LEFT JOIN a ON a.id = p.tk_a
GROUP BY a.name
ORDER BY p.price DESC
If you just want the single MAX price then use this
SELECT MAX(p.price), (SELECT MAX(b.name) FROM a b LEFT JOIN price pp ON b.id = pp.tk_a WHERE a.id = b.id AND p.price = pp.price) AS name
FROM price
LEFT JOIN a ON a.id = p.tk_a
ORDER BY p.price DESC
Use This
SELECT *
FROM (SELECT a.name,MAX( price.price)
FROM price
LEFT JOIN a
ON a.id = price.tk_a
GROUP BY a.name
ORDER BY price.price DESC)

I have to get the second largest count in the query's result

I am using a test data base Advetureworks and I want to get the second highest count in the result but I'm not getting it.
What changes do I have to make on the following query to get the desired result?
select pa.City,psp.Name,COUNT(he.EmployeeID) as emp_count
from HumanResources.EmployeeAddress hea
join HumanResources.Employee he on he.EmployeeID=hea.EmployeeID
join Person.Contact pc on pc.ContactID=he.ContactID
join Person.Address pa on pa.AddressID=hea.AddressID
join Person.StateProvince psp on psp.StateProvinceID=pa.StateProvinceID
where COUNT(he.EmployeeID) < (select max(count(he.employeeid)) from HumanResources.Employee)
group by pa.City,psp.Name
You can use ranking functions, try it like this:
;WITH a AS (
select pa.City,psp.Name,COUNT(he.EmployeeID) as emp_count
from HumanResources.EmployeeAddress hea
join HumanResources.Employee he on he.EmployeeID=hea.EmployeeID
join Person.Contact pc on pc.ContactID=he.ContactID
join Person.Address pa on pa.AddressID=hea.AddressID
join Person.StateProvince psp on psp.StateProvinceID=pa.StateProvinceID
group by pa.City,psp.Name
), b AS (
SELECT *,
ROW_NUMBER() OVER (ORDER BY emp_count DESC) num
FROM a
)
SELECT *
FROM b
WHERE b.num = 2
I knew there was a ROW_NUMBER way of doing it as posted by Ivan G but I can never remember the syntax so here is a slightly different approach:
with top_cities (City, Name, emp_count) as
(
select top 2
pa.City,psp.Name,COUNT(he.EmployeeID) as emp_count
from
HumanResources.EmployeeAddress hea
join HumanResources.Employee he on he.EmployeeID=hea.EmployeeID
join Person.Contact pc on pc.ContactID=he.ContactID
join Person.Address pa on pa.AddressID=hea.AddressID
join Person.StateProvince psp on psp.StateProvinceID=pa.StateProvinceID
group by
pa.City,psp.Name
order by
emp_count desc
)
select top 1 * from top_cities order by emp_count asc