MAX(), GROUP BY errors - db2

On DB2 V9 Z/Os
The query below three rows.
SELECT J01_REGION, I20_MMS_NO, I20_CONSUMER_ID, I21_CONSUMER_ID, I21_CASE_ID,
I42_FIN_MGR_PROV, J01_PROVIDER, I21_CASE_OPEN_DT, I42_FM_BEG_DT
FROM SERDB.I20_CONSUMER_T INNER JOIN SERDB.I21_CONS_CASE_T ON I20_CONSUMER_ID =
I21_CONSUMER_ID
INNER JOIN SERDB.I42_FIN_MGR_T ON I21_CASE_ID = I42_CASE_ID
INNER JOIN SERDB.J01_PROVIDER_T ON I42_FIN_MGR_PROV = J01_PROVIDER
WHERE J01_REGION = 2
AND I20_CONSUMER_ID = 96603
What I would like is for the query to return just one row by using the MAX values for I21_CASE_OPEN_DT & I42_FM_BEG_DT. If I use:
SELECT J01_REGION, I20_MMS_NO, I20_CONSUMER_ID, I21_CONSUMER_ID, I21_CASE_ID, MAX
(I21_CASE_OPEN_DT), MAX(I42_FM_BEG_DT), I42_FIN_MGR_PROV, J01_PROVIDER
FROM SERDB.I20_CONSUMER_T INNER JOIN SERDB.I21_CONS_CASE_T ON I20_CONSUMER_ID =
I21_CONSUMER_ID
INNER JOIN SERDB.I42_FIN_MGR_T ON I21_CASE_ID = I42_CASE_ID
INNER JOIN SERDB.J01_PROVIDER_T ON I42_FIN_MGR_PROV = J01_PROVIDER
WHERE J01_REGION = 2
AND I20_CONSUMER_ID = 96603;
I receive: SQL0122N A SELECT statement with no GROUP BY clause contains a column name or expression and a column function in the SELECT clause, or a column name or expression is contained in the SELECT clause but not in the GROUP BY clause. SQLSTATE=42803
If I use:
SELECT J01_REGION, I20_MMS_NO, I20_CONSUMER_ID, I21_CONSUMER_ID, I21_CASE_ID,
I42_FIN_MGR_PROV, J01_PROVIDER, I21_CASE_OPEN_DT, I42_FM_BEG_DT
FROM SERDB.I20_CONSUMER_T INNER JOIN SERDB.I21_CONS_CASE_T ON I20_CONSUMER_ID =
I21_CONSUMER_ID
INNER JOIN SERDB.I42_FIN_MGR_T ON I21_CASE_ID = I42_CASE_ID
INNER JOIN SERDB.J01_PROVIDER_T ON I42_FIN_MGR_PROV = J01_PROVIDER
WHERE J01_REGION = 2
AND I20_CONSUMER_ID = 96603
AND MAX(I21_CASE_OPEN_DT)
AND MAX(I42_FM_BEG_DT);
I recieve: SQL0199N The use of the reserved word "AND" following "AND" is not valid. Expected tokens may include: "MICROSECONDS MICROSECOND SECONDS SECOND MINUTES MINUTE HOURS". SQLSTATE=42601
Does anyone have a suggestion as to what else I could do?
Thank you

The second error tells you all you need to know:
A SELECT statement with no GROUP BY clause contains a column name or expression and a column function in the SELECT clause, or a column name or expression is contained in the SELECT clause but not in the GROUP BY clause
If you use aggregates (MAX, MIN, etc.) you must group by all other fields in the select statement, which you have not done.
Taking your second query, and adding the GROUP BY clause gets us this:
SELECT J01_REGION, I20_MMS_NO, I20_CONSUMER_ID, I21_CONSUMER_ID, I21_CASE_ID,
MAX (I21_CASE_OPEN_DT), MAX(I42_FM_BEG_DT), I42_FIN_MGR_PROV, J01_PROVIDER
FROM SERDB.I20_CONSUMER_T INNER JOIN SERDB.I21_CONS_CASE_T ON I20_CONSUMER_ID =
I21_CONSUMER_ID
INNER JOIN SERDB.I42_FIN_MGR_T ON I21_CASE_ID = I42_CASE_ID
INNER JOIN SERDB.J01_PROVIDER_T ON I42_FIN_MGR_PROV = J01_PROVIDER
WHERE J01_REGION = 2
AND I20_CONSUMER_ID = 96603
GROUP BY J01_REGION, I20_MMS_NO, I20_CONSUMER_ID, I21_CONSUMER_ID, I21_CASE_ID,
I42_FIN_MGR_PROV, J01_PROVIDER;

Related

Postgres string_agg function not recognized as aggregate function

I am attempting to run this query
SELECT u.*, string_agg(CAST(uar.roleid AS VARCHAR(100)), ',') AS roleids, string_agg(CAST(r.role AS VARCHAR(100)), ',') AS systemroles
FROM idpro.users AS u
INNER JOIN idpro.userapplicationroles AS uar ON u.id = uar.userid
INNER JOIN idpro.roles AS r ON r.id = uar.roleid
GROUP BY u.id, uar.applicationid
HAVING u.organizationid = '77777777-f892-4f4a-8328-c31df32bd6ba'
AND uar.applicationid = 'd88fbf05-c048-4697-8bf3-036f39897183'
AND (u.statusid = '7f9f0b75-44b7-4216-bf2a-03abc47dcff8')
AND uar.roleid IN ('cc9ada1c-fa21-400b-be98-c563ebb65a9c','de087148-4788-43da-89e2-dd7dff097735');
However, I'm getting an error stating that
ERROR: column "uar.roleid" must appear in the GROUP BY clause or be used in an aggregate function
LINE 9: AND uar.roleid IN ('cc9ada1c-fa21-400b-be98-c563ebb65a9c','...
string_agg() IS an aggregate function, is it not? My intent, if it isn't obvious, is to return each user record with the roleids and rolenames in comma-delimited lists. If I am doing everything wrong, could you please point me in the right direction?
You are filtering the data, so a WHERE clause would be needed. This tutorial is worth reading.
SELECT u.*,
string_agg(CAST(uar.roleid AS VARCHAR(100)), ',') AS roleids,
string_agg(CAST(r.role AS VARCHAR(100)), ',') AS systemroles
FROM idpro.users AS u
INNER JOIN idpro.userapplicationroles AS uar ON u.id = uar.userid
INNER JOIN idpro.roles AS r ON r.id = uar.roleid
WHERE u.organizationid = '77777777-f892-4f4a-8328-c31df32bd6ba'
AND uar.applicationid = 'd88fbf05-c048-4697-8bf3-036f39897183'
AND (u.statusid = '7f9f0b75-44b7-4216-bf2a-03abc47dcff8')
AND uar.roleid IN ('cc9ada1c-fa21-400b-be98-c563ebb65a9c','de087148-4788-43da-89e2-dd7dff097735');
GROUP BY u.id, uar.applicationid
The HAVING clause is helpful for filtering the aggregated values or the groups.
Since you are grouping by u.id, the table primary key you have access to every column of the u table. You can either use a where clause or a having clause.
For uar.applicationid, it is part of the group by so you can also use either a where or a having.
uar.roleid is not part of the group by clause, so to be usable in the having clause, you would have to consider the aggregated value.
The following example filters out rows whose aggregated length is more than 10 chars.
HAVING length(string_agg(CAST(uar.roleid AS VARCHAR(100)), ',')) > 10
A more common usage, on numerical field, is to filter out if the number of aggregated rows is less than a threshold (having count(*) > 2) or a sum of some kind (having sum(vacation_days) > 21)

Lateral query syntax

I'm trying to get lateral to work in a Postgres 9.5.3 query.
select b_ci."IdOwner",
ci."MinimumPlaces",
ci."MaximumPlaces",
(select count(*) from "LNK_Stu_CI" lnk
where lnk."FK_CourseInstanceId" = b_ci."Id") as "EnrolledStudents",
from "Course" c
join "DBObjectBases" b_c on c."Id" = b_c."Id"
join "DBObjectBases" b_ci on b_ci."IdOwner" = b_c."Id"
join "CourseInstance" ci on ci."Id" = b_ci."Id",
lateral (select ci."MaximumPlaces" - "EnrolledStudents") x
I want the right-most column to be the result of "MaximumPlaces" - "EnrolledStudents" for that row but am struggling to get it to work. At the moment PG is complaining that "EnrolledStudents" does not exist - which is exactly the point of "lateral", isn't it?
select b_ci."IdOwner",
ci."MinimumPlaces",
ci."MaximumPlaces",
(select count(*) from "LNK_Stu_CI" lnk
where lnk."FK_CourseInstanceId" = b_ci."Id") as "EnrolledStudents",
lateral (select "MaximumPlaces" - "EnrolledStudents") as "x"
from "Course" c
join "DBObjectBases" b_c on c."Id" = b_c."Id"
join "DBObjectBases" b_ci on b_ci."IdOwner" = b_c."Id"
join "CourseInstance" ci on ci."Id" = b_ci."Id"
If I try inlining the lateral clause (shown above) in the select it gets upset too and gives me a syntax error - so where does it go?
Thanks,
Adam.
You are missing the point with LATERAL. It can access columns in tables in the FROM clause, but not aliases defined in SELECT clause.
If you want to access alias defined in SELECT clause, you need to add another query level, either using a subquery in FROM clause (AKA derived table) or using a CTE (Common Table Expression). As CTE in PostgreSQL acts as an optimization fence, I strongly recommend going with subquery in this case, like:
select
-- get all columns on the inner query
t.*,
-- get your new expression based on the ones defined in the inner query
t."MaximumPlaces" - t."EnrolledStudents" AS new_alias
from (
select b_ci."IdOwner",
ci."MinimumPlaces",
ci."MaximumPlaces",
(select count(*) from "LNK_Stu_CI" lnk
where lnk."FK_CourseInstanceId" = b_ci."Id") as "EnrolledStudents",
from "Course" c
join "DBObjectBases" b_c on c."Id" = b_c."Id"
join "DBObjectBases" b_ci on b_ci."IdOwner" = b_c."Id"
join "CourseInstance" ci on ci."Id" = b_ci."Id"
) t

how to solve this complicated sql query

these are the five given tables
http://i58.tinypic.com/53wcxe.jpg
this is the recomanded result
http://i58.tinypic.com/2vsrts7.jpg
please help how can i write a query to have this result.
no idea how!!!!
SELECT K.* , COUNT (A.Au_ID) AS AnzahlAuftr
FROM Kunde K
LEFT JOIN Auftrag A ON K.Kd_ID = A.Au_Kd_ID
GROUP BY K.Kd_ID,K.Kd_Firma,K.Kd_Strasse,K.Kd_PLZ,K.Kd_Ort
ORDER BY K.Kd_PLZ DESC;
SELECT COUNT (F.F_ID) AS AnzahlFahrt
FROM Fahrten F
RIGHT JOIN Auftrag A ON A.Au_ID = F.F_Au_ID
SELECT SUM (T.Ts_Strecke) AS SumStrecke
FROM Teilstrecke T
LEFT JOIN Fahrten F ON F.F_ID = T.Ts_F_ID
how to join these 3 in one?
Grouping on Strasse etc. is not necessary and can be quite expensive. What about this approach:
SELECT K.*, ISNULL(Au.AnzahlAuftr,0) AS AnzahlAuftr, ISNULL(Au.AnzahlFahrt,0) AS AnzahlFahrt, ISNULL(Au.SumStrecke,0) AS SumStrecke
FROM Kunde K
LEFT OUTER JOIN
(SELECT A.Au_Kd_ID, COUNT(*) AS AnzahlAuftr, SUM(Fa.AnzahlFahrt1) AS AnzahlFahrt, SUM(Fa.SumStrecke2) AS SumStrecke
FROM Auftrag A LEFT OUTER JOIN
(SELECT F.F_Au_ID, COUNT(*) AS AnzahlFahrt1, SUM(Ts.SumStrecke1) AS SumStrecke2
FROM Fahrten F LEFT OUTER JOIN
(SELECT T.Ts_F_ID, SUM(T.Ts_Strecke) AS SumStrecke1
FROM Teilstrecke T
GROUP BY T.Ts_F_ID) AS Ts
ON Ts.Ts_F_ID = F.F_ID
GROUP BY F.F_Au_ID) AS Fa
ON Fa.F_Au_ID = A.Au_ID
GROUP BY A.Au_Kd_ID) AS Au
ON Au.Au_Kd_ID = K.Kd_ID

sql, group a query with no aggregations and multiple tables

I need to group the query below by dda.LA and need to display all the columns listed in the select but almost none of them are aggregated. i don't know what the syntax to get around this is and i can not find a post that shows this syntax (most examples only have one table, two at tops).
Select dda.a,
dda.b,
dda.c,
dda.d,
dda.e,
dda.f,
dda.g,
dda.h,
dda.i,
dda.j,
dda.k,
dda.l,
dda.m,
dda.n,
dda.o,
dda.p,
dda.r,
dda.u,
dda.LA,
dd.aa,
coalesce(apn.apn,Pt.z) as abc,
coalesce(apn.v,Pt.y) as def,
'RFN' RowFocusIndicator ,
'SRI' SelectRowIndicator ,
'Y' Expanded ,
Convert(Int, Null) SortColumn
From dda (NoLock)
Inner Join dd (NoLock) On dda.d = dd.q and dda.e = dd.e
Left Outer Join apn (nolock) on dda.r = apn.r
Left Outer Join Pt (nolock) on dda.s = Pt.t
Where 1 = 1
And dda.u = (Select Min(c.w)
From c (NoLock)
Where c.x = dda.s)
Thanks!
Just add this to any column that you want to aggregate by:
AggregatedColumnName = Aggregation(fieldToAggregate) Over (Partition By dda.LA)
ex.
aCount = Count(dda.a) Over (Partition By dda.LA)

DB2: group by interfering subquery in Select clause

I'm stuck with a SQL query. I'm making a subquery in the select clause and db2 prompts a -119 error telling:
"An expression starting with "FACILITY_ID" specified in a SELECT clause, HAVING clause, or ORDER BY clause is not specified in the GROUP BY clause or it is in a SELECT clause, HAVING clause, or ORDER BY clause with a column function and no GROUP BY clause is specified. SQL Code: -119, SQL State: 42803"
I don't know how to include NUMTAGS in the GROUP BY. I tried including the BC.ITEM in the GROUP BY clause with no result. I don't know how exactly to look for this in the web, and the forums I looked at were no useful.
If someone could explain me how to mend this or paste a link where I could look for a solution, I would be grateful.
The SQL query is with DB2 and it's down here:
SELECT SS.NAME, B.DESTINATION_ID, P.DESCRIPTION, B.LAST_READ_DATE, B.LABEL,
(SELECT COUNT(BC.ITEM)
FROM PROJECT_DB.BOX_CONTENT BC
WHERE BC.FACILITY_ID = B.FACILITY_ID
AND BC.BOX_ID = B.BOX_ID
GROUP BY BC.ITEM) AS NUMTAGS,
B.BOX_ID
FROM PROJECT_DB.BOX B
INNER JOIN MAINDB.DESTINATION P ON B.DESTINATION_ID = P.DESTINATION_ID
INNER JOIN MAINDB.WAREHOUSE_DESTINATION_SECTION WH
ON B.DESTINATION_ID = WH.DESTINATION_ID
AND B.WAREHOUSE_ID = WH.WAREHOUSE_ID
INNER JOIN MAINDB.SECTION S ON S.SECTION = WH.SECTION
AND S.SECTION_TYPE = B.SECTION_TYPE
INNER JOIN MAINDB.DESTINATION_SET SS
ON SS.DESTINATION_SET_ID = S.DESTINATION_SET_ID
WHERE B.WAREHOUSE_ID = 100
GROUP BY B.BOX_ID, B.FACILITY_ID, B.DESTINATION_ID, B.LAST_READ_DATE, B.LABEL, P.DESCRIPTION, SS.NAME
You can correct the statement by: v including the columns in the GROUP
BY clause that are in the SELECT clause, or v removing the columns
from the SELECT clause.
From: DB2 documentation.
You need to put ALL selected columns in your GROUP BY...
Since you're using a scalar sub-select, I don't think you need a GROUP BY clause on either of your statements. Try this:
SELECT
SS.NAME,
B.DESTINATION_ID,
P.DESCRIPTION,
B.LAST_READ_DATE,
B.LABEL,
(SELECT COUNT(BC.ITEM)
FROM PROJECT_DB.BOX_CONTENT BC
WHERE BC.FACILITY_ID = B.FACILITY_ID
AND BC.BOX_ID = B.BOX_ID
) AS NUMTAGS,
B.BOX_ID
FROM PROJECT_DB.BOX B
JOIN MAINDB.DESTINATION P
ON B.DESTINATION_ID = P.DESTINATION_ID
JOIN MAINDB.WAREHOUSE_DESTINATION_SECTION WH
ON B.DESTINATION_ID = WH.DESTINATION_ID
AND B.WAREHOUSE_ID = WH.WAREHOUSE_ID
JOIN MAINDB.SECTION S
ON S.SECTION = WH.SECTION
AND S.SECTION_TYPE = B.SECTION_TYPE
JOIN MAINDB.DESTINATION_SET SS
ON SS.DESTINATION_SET_ID = S.DESTINATION_SET_ID
WHERE B.WAREHOUSE_ID = 100
My final working query is this down here. I think I had the wrong tables referenced at the "group by" or something similar:
SELECT SS.NAME, P.DESTINATION_ID, P.DESCRIPTION, B.LAST_READ_DATE, B.LABEL,
(SELECT COUNT(BC.ITEM)
FROM PROJECT_DB.BOX_CONTENT BC
WHERE BC.ID_FACILITY = B.ID_FACILITY
AND BC.ID_BOX = B.ID_BOX
GROUP BY BC.ITEM) AS NUMTAGS,
B.BOX_ID, B.FACILITY_ID
FROM PROJECT_DB.BOX B
INNER JOIN MAINDB.DESTINATION P ON B.DESTINATION_ID = P.DESTINATION_ID
INNER JOIN MAINDB.WAREHOUSE_DESTINATION_SECTION WH
ON WH.WAREHOUSE_ID = B.WAREHOUSE_ID
AND WH.ID_DESTINATION = B.ID_DESTINATION
INNER JOIN MAINDB.SECTION S ON S.SECTION = WH.SECTION
AND S.SECTION_TYPE = B.SECTION_TYPE
INNER JOIN MAINDB.DESTINATION_SET SS ON SS.DESTINATION_SET_ID = S.DESTINATION_SET_ID
WHERE B.WAREHOUSE_ID = 100
GROUP BY B.BOX_ID, B.FACILITY_ID, P.DESTINATION_ID, B.LAST_READ_DATE, B.LABEL, P.DESCRIPTION, SS.NAME
WITH UR