SQL Error: ORA-01489: result of string concatenation is too long - sql

I am working on the query below:
select ip.intake_id,
ip.estimated_years,
ip.gender_code,
LISTAGG(ip.race_code, ',') WITHIN GROUP (ORDER BY ip.race_code) as race_code,
eth.ethnicity_code,
i.living_arrangements,
p.dep_actv_military_flag,
LISTAGG(ale.allegation_super_type_code) WITHIN GROUP (ORDER BY ale.allegation_super_type_code) as maltreatment_type_code,
LISTAGG(ale.initial_report_disp_code) WITHIN GROUP (ORDER BY ale.initial_report_disp_code) as maltreatment_dispo_lvl,
ip.deceased_flag,
LISTAGG(ch.characteristic_code, ',') WITHIN GROUP (ORDER BY ch.characteristic_code) as chara_codes,
LISTAGG(ich.intake_characteristic_code, ',') WITHIN GROUP (ORDER BY ich.intake_characteristic_code) as intake_chara_codes,
pe.removed_date,cm.petition_submitted_flag,cm.created_date,atr.person_id
from intake i inner join intake_participant ip on i.intake_id = ip.intake_id
left outer join reporter r ON i.intake_id=r.intake_id
left outer join ethnicity eth on eth.person_id = ip.person_id
left outer join person p on p.person_id = ip.person_id
left outer join allegation ale on ale.intake_id = i.intake_id
left outer join characteristic ch on ch.person_id = ip.person_id
left outer join intake_characteristic ich on ich.intake_id = i.intake_id
left outer join placement_episode pe on pe.child_id = ip.person_id
left outer join complaint cm on cm.petitioner_id = ip.person_id
left outer join attorney atr on atr.person_id = ip.person_id
left outer join intake_participant_role apr on apr.intake_participant_id = ip.intake_participant_id
group by ip.intake_id,ip.estimated_years,ip.gender_code,eth.ethnicity_code,i.living_arrangements,p.dep_actv_military_flag,
ip.deceased_flag,pe.removed_date,cm.petition_submitted_flag,cm.created_date,atr.person_id
when I am running this query I am getting following error message:
Error report:
SQL Error: ORA-01489: result of string concatenation is too long
01489. 00000 - "result of string concatenation is too long"
*Cause: String concatenation result is more than the maximum size.
*Action: Make sure that the result is less than the maximum size.
But when I remove the line :
left outer join reporter r ON i.intake_id=r.intake_id
from my query then it executes without any error message. The working query is given below:
select ip.intake_id,
ip.estimated_years,
ip.gender_code,
LISTAGG(ip.race_code, ',') WITHIN GROUP (ORDER BY ip.race_code) as race_code,
eth.ethnicity_code,
i.living_arrangements,
p.dep_actv_military_flag,
LISTAGG(ale.allegation_super_type_code) WITHIN GROUP (ORDER BY ale.allegation_super_type_code) as maltreatment_type_code,
LISTAGG(ale.initial_report_disp_code) WITHIN GROUP (ORDER BY ale.initial_report_disp_code) as maltreatment_dispo_lvl,
ip.deceased_flag,
LISTAGG(ch.characteristic_code, ',') WITHIN GROUP (ORDER BY ch.characteristic_code) as chara_codes,
LISTAGG(ich.intake_characteristic_code, ',') WITHIN GROUP (ORDER BY ich.intake_characteristic_code) as intake_chara_codes,
pe.removed_date,cm.petition_submitted_flag,cm.created_date,atr.person_id
from intake i inner join intake_participant ip on i.intake_id = ip.intake_id
left outer join ethnicity eth on eth.person_id = ip.person_id
left outer join person p on p.person_id = ip.person_id
left outer join allegation ale on ale.intake_id = i.intake_id
left outer join characteristic ch on ch.person_id = ip.person_id
left outer join intake_characteristic ich on ich.intake_id = i.intake_id
left outer join placement_episode pe on pe.child_id = ip.person_id
left outer join complaint cm on cm.petitioner_id = ip.person_id
left outer join attorney atr on atr.person_id = ip.person_id
left outer join intake_participant_role apr on ipr.intake_participant_id = ip.intake_participant_id
group by ip.intake_id,ip.estimated_years,ip.gender_code,eth.ethnicity_code,i.living_arrangements,p.dep_actv_military_flag,
ip.deceased_flag,pe.removed_date,cm.petition_submitted_flag,cm.created_date,atr.person_id
I am not sure why this error occured. Can someone help me to figure out the problem? I got same questions from these links link1 and link2, but I didn't get the solution to my question from these links.

The join to table "reporter" is probably increasing the record count (this could only be the case if column "intake_id" is not a unique key of "reporter"). By increasing the record count, you are generating more strings that LISTAGG must concatenate together within each group. If the total length of concatenated strings exceeds 4000 bytes, LISTAGG will fail with the error you see.

Let's take a different approach: just like when you're aggregating sums and joining to other tables, sometimes you have to materialize the results before you additional one-to-many join so your aggregation isn't artificially inflated due to multiple records in joining tables. This approach is assuming you don't need the repetition that is occurring due to the additional table joins however.
I think by creating the inline view the results of the race_Code will fit within size limits. This could be done using a CTE as well. Simply put, provided you don't need the record duplication, you may need to materialize the listAgg results individually first then join them back in. If you have other problems with the other listAggs, you may want to create multiple CTE's and then join them all back together in the end. This approach simply uses a inline view.
select B.intake_id,
B.estimated_years,
B.gender_code,
B.race_code,
eth.ethnicity_code,
B.living_arrangements,
p.dep_actv_military_flag,
LISTAGG(ale.allegation_super_type_code) WITHIN GROUP (ORDER BY ale.allegation_super_type_code) as maltreatment_type_code,
LISTAGG(ale.initial_report_disp_code) WITHIN GROUP (ORDER BY ale.initial_report_disp_code) as maltreatment_dispo_lvl,
B.deceased_flag,
LISTAGG(ch.characteristic_code, ',') WITHIN GROUP (ORDER BY ch.characteristic_code) as chara_codes,
LISTAGG(ich.intake_characteristic_code, ',') WITHIN GROUP (ORDER BY ich.intake_characteristic_code) as intake_chara_codes,
pe.removed_date,cm.petition_submitted_flag,cm.created_date,atr.person_id
from (SELECT ip.intake_id,
ip.estimated_years,
ip.gender_code,
ip.deceased_flag,
ip.person_id,
ip.intake_participant_id,
LISTAGG(ip.race_code, ',') WITHIN GROUP (ORDER BY ip.race_code) as race_code, i.living_arrangements
FROM intake i
INNER JOIN intake_participant ip on i.intake_id = ip.intake_id
GROUP BY ip.intake_id, ip.estimated_years, ip.gender_code,
i.living_arrangements, ip.deceased_flag, ip.person_id,
ip.intake_participant_id) B
left outer join ethnicity eth on eth.person_id = B.person_id
left outer join person p on p.person_id = B.person_id
left outer join allegation ale on ale.intake_id = B.intake_id
left outer join characteristic ch on ch.person_id = B.person_id
left outer join intake_characteristic ich on ich.intake_id = i.intake_id
left outer join placement_episode pe on pe.child_id = B.person_id
left outer join complaint cm on cm.petitioner_id = B.person_id
left outer join attorney atr on atr.person_id = B.person_id
left outer join intake_participant_role apr on ipr.intake_participant_id = B.intake_participant_id
GROUP BY ip.intake_id,ip.estimated_years,ip.gender_code, eth.ethnicity_code,i.living_arrangements,p.dep_actv_military_flag, ip.deceased_flag,pe.removed_date,cm.petition_submitted_flag, cm.created_date,atr.person_id

Related

Can't get the SUM function to work with my query

I'm trying to SUM some warehouse stock values, grouped by zones, but can't get it to work.
The following query returns all materials on stock. Same material is placed on more locations, in more zones. So material AAA can be located on two locations in zone 111, and three locations in zone 222
SELECT Zones.Label,
Materials.Material,
Shelves.Label as ShelfLabel,
Items.StockQty
FROM Zones INNER JOIN
(dbo.LangTexts(null) AS Texts INNER JOIN (WarehouseStatus INNER JOIN
(Shelves INNER JOIN (Positions INNER JOIN
(Materials INNER JOIN Items
ON Materials.Material = Items.Material)
ON Positions.ID = Items.Owner)
ON Shelves.ID = Positions.Owner)
ON WarehouseStatus.Status = Items.Status)
ON Texts.TextID = WarehouseStatus.Text)
ON Zones.ID = Shelves.Owner
WHERE Zones.Label IS NOT NULL
ORDER BY Materials.Material, Zones.Label
Output:
output screenshot
As I have tried to markup in the screenshot, I need the total StockQty grouped by zone (label column)
I'm trying to achieve that by modifying the query like this.
SELECT Zones.Label,
Materials.Material,
Shelves.Label as ShelfLabel,
SUM(Items.StockQty)
FROM Zones INNER JOIN
(dbo.LangTexts(null) AS Texts INNER JOIN (WarehouseStatus INNER JOIN
(Shelves INNER JOIN (Positions INNER JOIN
(Materials INNER JOIN Items
ON Materials.Material = Items.Material)
ON Positions.ID = Items.Owner)
ON Shelves.ID = Positions.Owner)
ON WarehouseStatus.Status = Items.Status)
ON Texts.TextID = WarehouseStatus.Text)
ON Zones.ID = Shelves.Owner
WHERE Zones.Label IS NOT NULL
GROUP BY Zones.Label
ORDER BY Materials.Material, Zones.Label
But it keeps returning the following error.
Msg 8120, Level 16, State 1, Line 6
Column 'Materials.Material' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I have been dealing with such error before, but don't understand exactly what I'm doing wrong. Sometimes I succeed by changing the query back and forth, but this time I really stuck.
Hope that someone is possible to guide me.
Thank's in advance.
As the column Shelves.Label actually not bring any value in this matter, I ended up with the following query based on #Md.SumanKabir's answer.
SELECT Zones.Label,
Materials.Material,
SUM(Items.StockQty)
FROM Zones INNER JOIN
(dbo.LangTexts(null) AS Texts INNER JOIN (WarehouseStatus INNER JOIN
(Shelves INNER JOIN (Positions INNER JOIN
(Materials INNER JOIN Items
ON Materials.Material = Items.Material)
ON Positions.ID = Items.Owner)
ON Shelves.ID = Positions.Owner)
ON WarehouseStatus.Status = Items.Status)
ON Texts.TextID = WarehouseStatus.Text)
ON Zones.ID = Shelves.Owner
WHERE Zones.Label IS NOT NULL
GROUP BY Zones.Label, Materials.Material
ORDER BY Materials.Material, Zones.Label
The correct query would be :
SELECT Zones.Label,
Materials.Material,
Shelves.Label as ShelfLabel,
SUM(Items.StockQty)
FROM Zones INNER JOIN
(dbo.LangTexts(null) AS Texts INNER JOIN (WarehouseStatus INNER JOIN
(Shelves INNER JOIN (Positions INNER JOIN
(Materials INNER JOIN Items
ON Materials.Material = Items.Material)
ON Positions.ID = Items.Owner)
ON Shelves.ID = Positions.Owner)
ON WarehouseStatus.Status = Items.Status)
ON Texts.TextID = WarehouseStatus.Text)
ON Zones.ID = Shelves.Owner
WHERE Zones.Label IS NOT NULL
GROUP BY Zones.Label, Materials.Material, Shelves.Label
ORDER BY Materials.Material, Zones.Label
You need to use the columns in GROUP BY which are not used in any aggregate functions like SUM
You can get more information on how to use GROUP BY Here
The problem here is that your grouping does not match your select. You select 3 columns Zones.Label, Materials.Material and Shelves.Label, but you group only by Zones.Label. Therefore, it does not know what to do with the 2 other columns.
Either you have to aggregate them like you did with the sum or you have to add them to the grouping.

Unnecessary LEFT JOINs on all Child tables from main LEFT JOIN table required in query for correct result

I am LEFT JOIN-ing the table RECALLS_T with EVENTS_T. Some Recalls do not have any Events, and for those I want a blank row returned.
However, once an entry in EVENTS_T exists, all the following extra tables from EVENTS_T which I also need (ANSWERS_T, ACTIVITY_QUESTIONS_T, ACTIVITES_T) are guaranteed to have entries. For these subsequent tables there is no need to do a LEFT JOIN from their parent, it can be an INNER JOIN just as well.
But if I do the following, the query does not return blank EVENTS_T rows for a RECALLS_T.
SELECT ..
FROM
recalls_t r
LEFT JOIN events_t e ON ( r.id = e.recall_id ) --Only LEFT JOIN this main table
INNER JOIN answers_t ans ON (ans.event_id = e.id)
INNER JOIN activity_questions_t aq ON (ans.activity_question_id = aq.id)
INNER JOIN PUBLIC.activities_t act ON (aq.activity_id = act.id)
Instead, I need to change every subsequent INNER JOIN to a LEFT JOIN as well, in order to get Recalls with blank Events.
SELECT ..
FROM
recalls_t r
LEFT JOIN events_t e ON ( r.id = e.recall_id )
LEFT JOIN answers_t ans ON (ans.event_id = e.id)
LEFT JOIN activity_questions_t aq ON (ans.activity_question_id = aq.id)
LEFT JOIN PUBLIC.activities_t act ON (aq.activity_id = act.id)
I'm just not clear on why I have to do this. The top-level optional join is all I care about, but the downstream joins from EVENTS_T are guaranteed to have data provided the Event exists. Shouldn't the top-level single EVENTS_T join be enough? I'm using Postgres.
The reason you need to do this is because rows preserved by the outer join will have NULL for all columns from events - so inner joining using an equality condition on e.id will remove them from the result again.
you can move the ON clause to the end of the query to give your desired semantics.
The left join is then on the virtual result of inner joining events_t, answers_t, activity_questions_t and activities_t
SELECT ...
FROM recalls_t r
LEFT JOIN events_t e
INNER JOIN answers_t ans
ON ( ans.event_id = e.id )
INNER JOIN activity_questions_t aq
ON ( ans.activity_question_id = aq.id )
INNER JOIN PUBLIC.activities_t act
ON ( aq.activity_id = act.id )
ON ( r.id = e.recall_id )
Or you could consider a RIGHT JOIN here instead
SELECT ...
FROM events_t e
INNER JOIN answers_t ans
ON ( ans.event_id = e.id )
INNER JOIN activity_questions_t aq
ON ( ans.activity_question_id = aq.id )
INNER JOIN PUBLIC.activities_t act
ON ( aq.activity_id = act.id )
RIGHT JOIN recalls_t r
ON ( r.id = e.recall_id )
You have to do this because answers_t`` is joining onevents_s. If thejoinkey (e.recall_id) isNULL`, then there will be no match. And the inner join will not return the row. And so on for the other tables.
You seem to understand the fix. Once you use left join, you need to continue using left join for those tables that are connected to the second table of the left join.

Possible to write this query without aggregate function?

SELECT l.LocID, COUNT(ulr.UserID)
FROM Locations l
LEFT OUTER JOIN UserLocationRights ulr ON l.LocID = ulr.LocID
LEFT OUTER JOIN Devices d ON l.LocID = d.LocID
LEFT OUTER JOIN UserModelRights umr ON d.ModelName = umr.ModelName
AND ulr.UserID = umr.UserID
GROUP BY l.LocID, ulr.UserID, d.ModelName
ORDER BY l.LocID, ulr.UserID
I want the results to be the LocID of all of the entries in Locations and the second column to be the number of Users who have rights to this location that also have the rights to at least one of the Devices in the Location which is determined by the entries in UserModelRights.
I can only figure out how to get what I want like this:
SELECT l.LocID, IsNull(UserHasModelRightInLoc.UserCount, 0) UserCount
FROM Locations l
LEFT OUTER JOIN (
SELECT ulr.LocID, COUNT(UserModelRightsPerLocation.UserID) UserCount
FROM UserLocRights ulr
INNER JOIN (
SELECT l.LocID, umr.UserID
FROM UserModelRights umr
INNER JOIN Devices d ON umr.ModelName = d.ModelName
INNER JOIN Locations l ON d.LocID = l.LocID
GROUP BY umr.ModelName, umr.UserID, l.LocID
) UserModelRightsPerLocation ON ulr.LocID = UserModelRightsPerLocation.LocID
AND ulr.UserID = UserModelRightsPerLocation.UserID
GROUP BY ulr.LocID
) UserHasModelRightInLoc ON l.LocID = UserHasModelRightInLoc.LocID
ORDER BY l.LocID
I don't know if this is possible, but I assume that there could be a way to use GROUP BY to get what I want using my first, much smaller query. The issue is that I think I need to do multiple GROUP BY in a specific order and I don't know if that's possible or makes sense in SQL.
Is there a way to get the result I want without using an aggregate function? If not, maybe narrow it down to a single one?
I find this a bit hard to follow without sample data. But based on your description, this might do what you want:
SELECT l.LocID, COUNT(DISTINCT ulr.UserID)
FROM Locations l LEFT JOIN
UserLocationRights ulr
ON l.LocID = ulr.LocID LEFT JOIN
Devices d
ON l.LocID = d.LocID LEFT JOIN
UserModelRights umr
ON d.ModelName = umr.ModelName AND
ulr.UserID = umr.UserID
GROUP BY l.LocID
ORDER BY l.LocID;

Want data added to the Query via Left Outer Joint to NOT repeat

I have a database structure (ER diagram below) that has three level of hierarchical data and the fourth level of optional data.
If I write a query to get de-normalized data of three levels - level 1 to level 3 with sample data across three tables shown as below:
When queried, this layout of the data is very straight forward and as expected as below:
Upon running the below query, I get the following output (And I have tried various combinations by clubbing the set of L1 to L4 and moving one L4 out as a another query and then joining the set L1 - L4 etc.) - again this is on the expected lines.
SELECT [Group].GroupId, [Group].GroupName, Category.CategoryId, Category.CategoryName, RLI.RLIId, RLI.RLIText, Comment.CommentId, Comment.CommentText, ManagementResponse.ManagementResponseId,
ManagementResponse.ManagementResponseTest
FROM Category INNER JOIN
[Group] ON Category.GroupId = [Group].GroupId INNER JOIN
RLI ON Category.CategoryId = RLI.CategoryId LEFT OUTER JOIN
ManagementResponse ON RLI.RLIId = ManagementResponse.RLIId LEFT OUTER JOIN
Comment ON RLI.RLIId = Comment.RLIId
However, I need data in the following format - and this is what I am unable to figure out how to get (I don't want the level 4 data to repeat as I add additional level 4 data via left outer joins):
This query will give you the final output:
WITH CommentAndResponse AS (
SELECT Comment.CommentId,
Comment.CommentText,
ManagementResponse.ManagementResponseId,
ManagementResponse.ManagementResponseTest,
COALESCE(Comment.RLIId, ManagementResponse.RLIId) AS RLIId
FROM (
(SELECT Comment.CommentId,
Comment.CommentText,
Comment.RLIId,
ROW_NUMBER() OVER (PARTITION BY Comment.RLIId ORDER BY Comment.CommentId) AS CommentRowNumber
FROM Comment) AS Comment
FULL JOIN
(SELECT ManagementResponse.ManagementResponseId,
ManagementResponse.ManagementResponseTest,
ManagementResponse.RLIId,
ROW_NUMBER() OVER (PARTITION BY ManagementResponse.RLIId ORDER BY ManagementResponse.ManagementResponseId) AS ManagementResponseRowNumber
FROM ManagementResponse) AS ManagementResponse
ON Comment.CommentRowNumber = ManagementResponse.ManagementResponseRowNumber AND Comment.RLIId = ManagementResponse.RLIId )
)
SELECT [Group].GroupId, [Group].GroupName, Category.CategoryId, Category.CategoryName, RLI.RLIId, RLI.RLIText, CommentAndResponse.CommentId, CommentAndResponse.CommentText, CommentAndResponse.ManagementResponseId, CommentAndResponse.ManagementResponseTest
FROM [Category]
INNER JOIN [Group] ON Category.GroupId = [Group].GroupId
INNER JOIN [RLI] ON Category.CategoryId = RLI.CategoryId
LEFT OUTER JOIN [CommentAndResponse] ON RLI.RLIId = CommentAndResponse.RLIId
You need to specify that Comment.CommentId is equal to ManagementResponse.ManagementResponseId or either is null. That can be part of a JOIN or a separate WHERE
SELECT [Group].GroupId, [Group].GroupName, Category.CategoryId, Category.CategoryName, RLI.RLIId, RLI.RLIText, Comment.CommentId, Comment.CommentText, ManagementResponse.ManagementResponseId,
ManagementResponse.ManagementResponseTest
FROM [Category]
INNER JOIN [Group] ON Category.GroupId = [Group].GroupId
INNER JOIN [RLI] ON Category.CategoryId = RLI.CategoryId
LEFT OUTER JOIN [ManagementResponse] ON RLI.RLIId = ManagementResponse.RLIId
LEFT OUTER JOIN [Comment] ON RLI.RLIId = Comment.RLIId
WHERE ManagementResponse.ManagementResponseId = Comment.CommentId OR ManagementResponse.ManagementResponseId IS NULL OR Comment.CommentId IS NULL
This assumes that those IDs begin equal is the relationship you want to model. The example data seems to show this, but it could be a coincidence of how you assembled the example. Alternatively, if there is no relationship between Comment and ManagementResponse besides RLIId, something like
WITH CommentAndResponse AS (
SELECT Comment.CommentId, Comment.CommentText, ManagementResponse.ManagementResponseId, ManagementResponse.ManagementResponseTest,
COALESCE(Comment.RLIId, ManagementResponse.RLIId) AS RLIId,
ROW_NUMBER() OVER (ORDER BY Comment.CommentId, ManagementResponse.ManagementResponseId, PARTITION BY Comment.RLIId, ManagementResponse.RLIId) AS rn
FROM Comment
FULL JOIN ManagementResponse ON Comment.RLIId = ManagementResponse.RLIId)
SELECT [Group].GroupId, [Group].GroupName, Category.CategoryId, Category.CategoryName, RLI.RLIId, RLI.RLIText, CommentAndResponse.CommentId, CommentAndResponse.CommentText, CommentAndResponse.ManagementResponseId, CommentAndResponse.ManagementResponseTest
FROM [Category]
INNER JOIN [Group] ON Category.GroupId = [Group].GroupId
INNER JOIN [RLI] ON Category.CategoryId = RLI.CategoryId
LEFT OUTER JOIN [CommentAndResponse] ON RLI.RLIId = CommentAndResponse.RLIId AND CommentAndResponse.rn = 1

Sql Query Issue 'BatchRelease.BatchReleaseNo' is invalid in the select list

In the below query when i execute it throws error "Column 'BatchRelease.BatchReleaseNo' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause." Please me to solve the issue.This error occurs when i sum the values.
SELECT DISTINCT BR.BatchReleaseNo,BR.CreatedOn,P.ProductName,
BRD.BatchReleaseQuantity,P.ProductCode,BOED.NoOfEmployee,
BOED.TimeInHours,EM.EmployeeType,BRPD.ProcessLoss,
MP.UnitProcessTime,MM.RequiredCostPerHour,
MM.MachineryType,
(BRD.BatchReleaseQuantity*BRD.UnitPrice) AS BatchCompletionValue,
ISNULL(
SUM((BOED.NoOfEmployee
*(BOED.TimeInHours/60 )/60)
*(EM.CostPerDay/EM.WorkingHours))
,0.0
)
FROM BatchReleaseDetails BRD
LEFT OUTER JOIN BatchRelease BR ON BR.BatchReleaseID=BRD.BatchReleaseID
LEFT OUTER JOIN Product P ON P.ProductID=BRD.ProductID
LEFT OUTER JOIN BatchOrderEmployeeDetails BOED ON BOED.BatchReleaseID=BR.BatchReleaseID
LEFT OUTER JOIN EmployeeMaster EM ON EM.EmployeeTypeID=BOED.EmployeeTypeID
LEFT OUTER JOIN BatchReleasedProcessDetails BRPD ON BRPD.BatchReleaseID=BR.BatchReleaseID
--LEFT OUTER JOIN Process PR ON PR.ProcessID=BRPD.ProcessID
LEFT OUTER JOIN MachineProcess MP ON MP.ProcessID=BRPD.ProcessID
LEFT OUTER JOIN MachineMaster MM ON MM.MachineID=MP.MachineID
GRoup BY BR.BatchReleaseNo