Postgres json aggregate function calls cannot be nested - postgresql

I have this select statement, I want to export them to json array with an another nested json agregate function but postgres says that "aggregate function calls cannot be nested", I can not figure aout how i can do this.
select json_agg(json_build_object(
'plan_number', plan.id,
'plan_carrier_code', carrier_plan.carrier_code,
'plan_name', plan.plan_name,
'plan_mac', mac.mac_name,
'plan_termination_date', plan.termination_date,
'plan_mod_start_date', plan.mod_start_date,
'plan_mod_user', plan.mod_user,
'plan_opt_brandcode_g_on_mn_as_generic_copay', plan.opt_brandcode_g_on_mn_as_generic_copay,
'plan_opt_exclude_daw2_from_ded_calculations', plan.opt_exclude_daw2_from_ded_calculations,
'plan_opt_exclude_daw2_from_oop_calculations', plan.opt_exclude_daw2_from_oop_calculations,
'plan_opt_limit_patient_pay_to_pay', plan.opt_limit_patient_pay_to_pay,
'plan_opt_only_pay_primary_claims', plan.opt_only_pay_primary_claims,
'plan_opt_allow_discontinued_drugs', plan.opt_allow_discontinued_drugs,
'plan_opt_allow_negative_payments_to_pharmacy', plan.opt_allow_negative_payments_to_pharmacy,
'plan_opt_process_y_drugs_as_preferred', plan.opt_process_y_drugs_as_preferred,
'plan_opt_reject_otc', plan.opt_reject_otc,
'plan_opt_reject_repackaged_drugs', plan.opt_reject_repackaged_drugs,
'plan_opt_test_only', plan.opt_test_only,
'plan_opt_cost_effective_pricing', plan.opt_cost_effective_pricing,
'plan_opt_original_mony_for_copay', plan.opt_original_mony_for_copay,
'plan_daw_differential', json_agg(json_build_object(
'plan_daw_differential_daw_code', plan_daw_differential.daw_code,
'plan_daw_differential_claim_type', plan_daw_differential.claim_type,
'plan_daw_differential_updated_at', plan_daw_differential.updated_at,
'plan_daw_differential_updated_by', plan_daw_differential.updated_by
))
)) as plan
from splan.groups_plan_list gpl
left join splan.plan plan on plan.id = gpl.plan_id
left join splan.carrier carrier_plan on carrier_plan.id = plan.carrier_id
left join splan.plan_daw_differential plan_daw_differential on plan_daw_differential.parent_id = plan.id
left join sdrug.mac mac on mac.id = plan.mac_id
where gpl.parent_id = 69;
but it throws me an error that said "aggregate function calls cannot be nested"
the expected result can be:
[
{
"plan_number":1,
"plan_carrier_code":"lltest",
"plan_daw_differential":[
{
"plan_daw_differential_daw_code":"0505",
"plan_daw_differential_claim_type":"02"
},
{
"plan_daw_differential_daw_code":"0505",
"plan_daw_differential_claim_type":"02"
}
]
}
]

Options:
use subquery (or join lateral) to evaluate plan_daw_differential element for every plan element.
using GROUP BY plan... gpl... carrier_plan... mac...
Because the solutions differ in execution plan you will have to pick one that fits your requirements the most.
I would go with first option in most cases. It is more compact easier to write and maintain. The only reason to pick the second would be requirement to filter the plan using data from plan_daw_differential table.
Examples:
Subquery:
select json_agg(json_build_object(
'plan_number', plan.id,
'plan_carrier_code', carrier_plan.carrier_code,
'plan_name', plan.plan_name,
'plan_mac', mac.mac_name,
'plan_termination_date', plan.termination_date,
'plan_mod_start_date', plan.mod_start_date,
'plan_mod_user', plan.mod_user,
'plan_opt_brandcode_g_on_mn_as_generic_copay', plan.opt_brandcode_g_on_mn_as_generic_copay,
'plan_opt_exclude_daw2_from_ded_calculations', plan.opt_exclude_daw2_from_ded_calculations,
'plan_opt_exclude_daw2_from_oop_calculations', plan.opt_exclude_daw2_from_oop_calculations,
'plan_opt_limit_patient_pay_to_pay', plan.opt_limit_patient_pay_to_pay,
'plan_opt_only_pay_primary_claims', plan.opt_only_pay_primary_claims,
'plan_opt_allow_discontinued_drugs', plan.opt_allow_discontinued_drugs,
'plan_opt_allow_negative_payments_to_pharmacy', plan.opt_allow_negative_payments_to_pharmacy,
'plan_opt_process_y_drugs_as_preferred', plan.opt_process_y_drugs_as_preferred,
'plan_opt_reject_otc', plan.opt_reject_otc,
'plan_opt_reject_repackaged_drugs', plan.opt_reject_repackaged_drugs,
'plan_opt_test_only', plan.opt_test_only,
'plan_opt_cost_effective_pricing', plan.opt_cost_effective_pricing,
'plan_opt_original_mony_for_copay', plan.opt_original_mony_for_copay,
'plan_daw_differential', (
SELECT
json_agg(json_build_object(
'plan_daw_differential_daw_code', plan_daw_differential.daw_code,
'plan_daw_differential_claim_type', plan_daw_differential.claim_type,
'plan_daw_differential_updated_at', plan_daw_differential.updated_at,
'plan_daw_differential_updated_by', plan_daw_differential.updated_by
))
FROM
splan.plan_daw_differential plan_daw_differential
WHERE
plan_daw_differential.parent_id = plan.id )
)) as plan
from
splan.groups_plan_list gpl
left join splan.plan plan on plan.id = gpl.plan_id
left join splan.carrier carrier_plan on carrier_plan.id = plan.carrier_id
left join sdrug.mac mac on mac.id = plan.mac_id
where
gpl.parent_id = 69;
Grouping:
select json_agg(json_build_object(
'plan_number', plan_number,
'plan_carrier_code', plan_carrier_code,
'plan_name', plan_name,
'plan_mac', plan_mac,
'plan_termination_date', plan_termination_date,
'plan_mod_start_date', plan_mod_start_date,
'plan_mod_user', plan_mod_user,
'plan_opt_brandcode_g_on_mn_as_generic_copay', plan_opt_brandcode_g_on_mn_as_generic_copay,
'plan_opt_exclude_daw2_from_ded_calculations', plan_opt_exclude_daw2_from_ded_calculations,
'plan_opt_exclude_daw2_from_oop_calculations', plan_opt_exclude_daw2_from_oop_calculations,
'plan_opt_limit_patient_pay_to_pay', plan_opt_limit_patient_pay_to_pay,
'plan_opt_only_pay_primary_claims', plan_opt_only_pay_primary_claims,
'plan_opt_allow_discontinued_drugs', plan_opt_allow_discontinued_drugs,
'plan_opt_allow_negative_payments_to_pharmacy', plan_opt_allow_negative_payments_to_pharmacy,
'plan_opt_process_y_drugs_as_preferred', plan_opt_process_y_drugs_as_preferred,
'plan_opt_reject_otc', plan_opt_reject_otc,
'plan_opt_reject_repackaged_drugs', plan_opt_reject_repackaged_drugs,
'plan_opt_test_only', plan_opt_test_only,
'plan_opt_cost_effective_pricing', plan_opt_cost_effective_pricing,
'plan_opt_original_mony_for_copay', plan_opt_original_mony_for_copay,
'plan_daw_differential', draw_differential_arr
)) as plan
FROM (
SELECT
plan.id AS plan_number,
carrier_plan.carrier_code AS plan_carrier_code,
plan.plan_name AS plan_name,
mac.mac_name AS plan_mac,
plan.termination_date AS plan_termination_date,
plan.mod_start_date AS plan_mod_start_date,
plan.mod_user AS plan_mod_user,
plan.opt_brandcode_g_on_mn_as_generic_copay AS plan_opt_brandcode_g_on_mn_as_generic_copay,
plan.opt_exclude_daw2_from_ded_calculations AS plan_opt_exclude_daw2_from_ded_calculations,
plan.opt_exclude_daw2_from_oop_calculations AS plan_opt_exclude_daw2_from_oop_calculations,
plan.opt_limit_patient_pay_to_pay AS plan_opt_limit_patient_pay_to_pay,
plan.opt_only_pay_primary_claims AS plan_opt_only_pay_primary_claims,
plan.opt_allow_discontinued_drugs AS plan_opt_allow_discontinued_drugs,
plan.opt_allow_negative_payments_to_pharmacy AS plan_opt_allow_negative_payments_to_pharmacy,
plan.opt_process_y_drugs_as_preferred AS plan_opt_process_y_drugs_as_preferred,
plan.opt_reject_otc AS plan_opt_reject_otc,
plan.opt_reject_repackaged_drugs AS plan_opt_reject_repackaged_drugs,
plan.opt_test_only AS plan_opt_test_only,
plan.opt_cost_effective_pricing AS plan_opt_cost_effective_pricing,
plan.opt_original_mony_for_copay AS plan_opt_original_mony_for_copay,
json_agg(json_build_object(
'plan_daw_differential_daw_code', plan_daw_differential.daw_code,
'plan_daw_differential_claim_type', plan_daw_differential.claim_type,
'plan_daw_differential_updated_at', plan_daw_differential.updated_at,
'plan_daw_differential_updated_by', plan_daw_differential.updated_by
)) as draw_differential_arr
FROM
splan.groups_plan_list gpl
left join splan.plan plan on plan.id = gpl.plan_id
left join splan.carrier carrier_plan on carrier_plan.id = plan.carrier_id
left join splan.plan_daw_differential plan_daw_differential on plan_daw_differential.parent_id = plan.id
left join sdrug.mac mac on mac.id = plan.mac_id
WHERE
gpl.parent_id = 69
GROUP BY
plan.id,
carrier_plan.carrier_code,
plan.plan_name,
mac.mac_name,
plan.termination_date,
plan.mod_start_date,
plan.mod_user,
plan.opt_brandcode_g_on_mn_as_generic_copay,
plan.opt_exclude_daw2_from_ded_calculations,
plan.opt_exclude_daw2_from_oop_calculations,
plan.opt_limit_patient_pay_to_pay,
plan.opt_only_pay_primary_claims,
plan.opt_allow_discontinued_drugs,
plan.opt_allow_negative_payments_to_pharmacy,
plan.opt_process_y_drugs_as_preferred,
plan.opt_reject_otc,
plan.opt_reject_repackaged_drugs,
plan.opt_test_only,
plan.opt_cost_effective_pricing,
plan.opt_original_mony_for_copay
) AS plan_row

Related

Postgres Error: missing FROM-clause entry for table

I have a query and am using left joins. I have the left join clause as follows:
left outer join ( select pup.brokerage_code, pcz.zip, count (pup.aggregate_id) as VerifiedAgentCount
from partner_user_profiles pup
join partner_user_roles pure on pure.user_profile_id = pup.id
join profile_coverage_zips pcz on pcz.profile_id = pup.id
where lower(pure.role) = 'agent'
and pup.verification_status like 'Verified%'
group by pup.brokerage_code, pcz.zip) vac on vac.brokerage_code = b.brokerage_code and pcz.zip = bcz.zip
However I am getting the error message saying that I am missing the FROM entry clause for "pcz" however I aliased the table in the join clause so I am not sure what is wrong.
You have defined the table alias pcz within the sub-select however the alias no longer exists when the outside the sub-select. At the point you have used it the appropriate alias is the one for the entire sub-select, in this case vac. So: vac.zip = = bcz.zip
left outer join ( select pup.brokerage_code, pcz.zip, count (pup.aggregate_id) as VerifiedAgentCount
from partner_user_profiles pup
join partner_user_roles pure on pure.user_profile_id = pup.id
join profile_coverage_zips pcz on pcz.profile_id = pup.id
where lower(pure.role) = 'agent'
and pup.verification_status like 'Verified%'
group by pup.brokerage_code, pcz.zip
) vac on vac.brokerage_code = b.brokerage_code
and vac.zip = bcz.zip

Postgresql, how to SELECT json object without duplicated rows

I'm trying to find out how to get JSON object results of selected rows, and not to show duplicated rows.
My current query:
SELECT DISTINCT ON (vp.id) jsonb_agg(jsonb_build_object('affiliate',a.*)) as affiliates, jsonb_agg(jsonb_build_object('vendor',vp.*)) as vendors FROM
affiliates a
INNER JOIN related_affiliates ra ON a.id = ra.affiliate_id
INNER JOIN related_vendors rv ON ra.product_id = rv.product_id
INNER JOIN vendor_partners vp ON rv.vendor_partner_id = vp.id
WHERE ra.product_id = 79 AND a.is_active = true
GROUP BY vp.id
The results that I receive from this is:
[
affiliates: {
affiliate: affiliate1
affiliate: affiliate2
},
vendors: {
vendor: vendor1,
vendor: vendor1,
}
As you can see in the second record, vendor is still vendor1 because there are no more results, so I'd like to also know if there's a way to remove duplicates.
Thanks.
First point : the result you display here above doesn't conform the json type : the keys are not double-quoted, the string values are not double-quoted, having dupplicated keys in the same json object ('{"affiliate": "affiliate1", "affiliate": "affiliate2"}' :: json) is not be accepted with the jsonb type (but it is with the json type).
Second point : you can try to add the DISTINCT key word directly in the jsonb_agg function :
jsonb_agg(DISTINCT jsonb_build_object('vendor',vp.*))
and remove the DISTINCT ON (vp.id) clause.
You can also add an ORDER BY clause directly in any aggregate function. For more information, see the manual.
You could aggregate first, then join on the results of the aggregates:
SELECT a.affiliates, v.vendors
FROM (
select af.id, jsonb_agg(jsonb_build_object('affiliate',af.*)) as affiliates
from affiliates af
group by af.id
) a
JOIN related_affiliates ra ON a.id = ra.affiliate_id
JOIN related_vendors rv ON ra.product_id = rv.product_id
JOIN (
select vp.id, jsonb_agg(jsonb_build_object('vendor',vp.*)) as vendors
from vendor_partners vp
group by vp.id
) v ON rv.vendor_partner_id = v.id
WHERE ra.product_id = 79
AND a.is_active = true

Implementing Concat + RANK OVER SQL Clause in C# LINQ

I need to implement the following T-SQL clause ....
SELECT
CONCAT( RANK() OVER (ORDER BY [Order].codOrder, [PackedOrder].codPackedProduct ), '/2') as Item,
[Order].codOrder as [OF],
[PackedOrder].codLine as [Ligne],
[PackedOrder].codPackedProduct as [Material], ----------------------
[Product].lblPProduct as [Product],
[PackedProduct].lblPackedProduct as [MaterialDescription],
[PackedOrder].codPackedBatch as [Lot],
[Product].codCustomerColor as [ReferenceClient],
[PackedOrder].nbrPackedQuantity as [Quantity],
[PackedOrder].nbrLabelToPrint as [DejaImprime]
FROM [Order] INNER JOIN PackedOrder
ON [Order].codOrder = PackedOrder.codOrder INNER JOIN Product
ON [Order].codProduct = Product.codProduct INNER JOIN PackedProduct
ON PackedOrder.codPackedProduct = PackedProduct.codPackedProduct
Where [Order].codOrder = 708243075
So Far, I'm able to do:
var result =
from order1 in Orders
join packedorder1 in PackedOrders on order1.codOrder equals packedorder1.codOrder
join product1 in Products on order1.codProduct equals product1.codProduct
join packedproduct1 in PackedProducts on packedorder1.codPackedProduct equals packedproduct1.codPackedProduct
where order1.codOrder == _order.codOrder
select new FinishedProductPrintingM
{
OF = order1.codOrder,
Ligne = packedorder1.codLine,
Material = packedorder1.codPackedProduct,
Produit = product1.codProductType,
MaterialDescription = packedproduct1.lblPackedProduct,
Lot = packedorder1.codPackedBatch,
RéférenceClient = product1.codCustomerColor,
Quantité = packedorder1.nbrPackedQuantity,
Déjàimprimé = packedorder1.nbrLabelPrinted
};
Please let me know if its possible or not. I need to display the Items in such a way.Please feel free to add your valuable comments.
I am not aware how to use concat and Rank over function in LINQ.
Can anyone help me to convert my SQL query into LINQ?

Cannot get view to work on SQL Server

I am trying to create a view that includes columns froms several tables.
This is what it looks like:
And this is my query:
SELECT
Billing.WebPortalBilling.WebPortalBillingId,
Billing.WebPortalBilling.CorporationId,
Billing.WebPortalBilling.TokenId,
Billing.WebPortalBilling.GatewaySupportFee,
Billing.WebPortalBilling.GatewayPerTransactionFee,
Billing.WebPortalBilling.PortalPerCustomerFee,
Billing.WebPortalBilling.PortalSupportFee,
Customer.Account.AccountNumber,
Billing.WebPortalBilling.IsActive,
Customer.Customer.Name,
Customer.Customer.TaxCode,
Company.CorporationStructure.Branch
FROM
Company.CorporationStructure
RIGHT OUTER JOIN
Customer.Account ON Company.CorporationStructure.CorporationStructureId = Customer.Account.CorporationStructureId
RIGHT OUTER JOIN
Customer.Customer ON Company.CorporationStructure.Branch = Customer.Customer.Branch
RIGHT OUTER JOIN
Billing.WebPortalBilling ON Customer.Account.CorporationId = Billing.WebPortalBilling.CorporationId
WHERE
(Billing.WebPortalBilling.IsActive = 1)
It's only returning 1 record, which is not correct. I'm trying to tie the Customer's name back to the WebPortalBilling table along with the account number and branth in the other two tables.
I'm new to sql, so be kind.
Thanks!
As commented the where is killing the outer
Try
SELECT
Billing.WebPortalBilling.WebPortalBillingId,
Billing.WebPortalBilling.CorporationId,
Billing.WebPortalBilling.TokenId,
Billing.WebPortalBilling.GatewaySupportFee,
Billing.WebPortalBilling.GatewayPerTransactionFee,
Billing.WebPortalBilling.PortalPerCustomerFee,
Billing.WebPortalBilling.PortalSupportFee,
Customer.Account.AccountNumber,
Billing.WebPortalBilling.IsActive,
Customer.Customer.Name,
Customer.Customer.TaxCode,
Company.CorporationStructure.Branch
FROM
Company.CorporationStructure
RIGHT OUTER JOIN
Customer.Account ON Company.CorporationStructure.CorporationStructureId = Customer.Account.CorporationStructureId
RIGHT OUTER JOIN
Customer.Customer ON Company.CorporationStructure.Branch = Customer.Customer.Branch
RIGHT OUTER JOIN Billing.WebPortalBilling
ON Customer.Account.CorporationId = Billing.WebPortalBilling.CorporationId
AND Billing.WebPortalBilling.IsActive = 1
Try this, I think left joins are clearer.
SELECT
B.WebPortalBillingId,
B.CorporationId,
B.TokenId,
B.GatewaySupportFee,
B.GatewayPerTransactionFee,
B.PortalPerCustomerFee,
B.PortalSupportFee,
C.AccountNumber,
B.IsActive,
C.Name,
C.TaxCode,
CS.Branch
FROM Customer.Customer C
LEFT JOIN Company.CorporationStructure CS ON CS.Branch = C.Branch
LEFT JOIN Customer.Account A ON CS.CorporationStructureId = A.CorporationStructureId
LEFT JOIN Billing.WebPortalBilling B ON A.CorporationId = B.CorporationId
WHERE B.IsActive = 1

postgres sql query counting two sets of objects

I have this join query below. I am having one issue with it.
The shippedUnits column comes out wrong. It just counts the total items. The issue is I am counting two sets of objects that have everything in common except the shipped field.
SELECT count(*) as "units", (select count("EsnsVmas".*) from "EsnsVmas" where
"EsnsVmas"."shipped" = false AND "EsnsVmas"."VmaId" = 2 AND "EsnsVmas"."approved" =
true) as "shippedUnits", "Vmas".*, "Vendors"."name" as "name", "EsnsVmas".id as
"OrderItemId", "PurchaseOrderItems"."price", "Grades"."name" as "vendorGrade",
"Items"."name" as "model", "Items".id as "ItemId", "Grades".id as "GradeId"
FROM "Vmas"
JOIN "EsnsVmas" on ("EsnsVmas"."VmaId" = "Vmas".id)
JOIN "Esns" on ("EsnsVmas"."EsnId" = "Esns".id)
JOIN "PurchaseOrderItems" on ("Esns"."PurchaseOrderItemId" =
"PurchaseOrderItems".id)
JOIN "Items" on ("PurchaseOrderItems"."ItemId" = "Items".id)
JOIN "Grades" on ("PurchaseOrderItems"."GradeId" = "Grades".id)
JOIN "Vendors" on ("Vmas"."VendorId" = "Vendors".id)
WHERE "Vmas".id =2 AND "EsnsVmas"."approved" = true
GROUP BY "Vmas".id, "PurchaseOrderItems".id, "Grades".id, "Items".id, "Vendors".id, "EsnsVmas".id ;
It still seems that there is no relation between the inner and outer queries other than the hardcoded VmaId = "2". Since I don't have the tables in a database I can't test to make sure it works - but here's my first shot at a possible fix:
SELECT count(*) as "units", (select count("EsnsVmas".*) from "EsnsVmas" e2 where
e2."shipped" = false AND e2."VmaId" = "Vmas".id AND e2."approved" =
true AND "EsnsVmas".id = e2.id) as "shippedUnits", "Vmas".*, "Vendors"."name" as "name", "EsnsVmas".id as
"OrderItemId", "PurchaseOrderItems"."price", "Grades"."name" as "vendorGrade",
"Items"."name" as "model", "Items".id as "ItemId", "Grades".id as "GradeId"
FROM "Vmas"
JOIN "EsnsVmas" on ("EsnsVmas"."VmaId" = "Vmas".id)
JOIN "Esns" on ("EsnsVmas"."EsnId" = "Esns".id)
JOIN "PurchaseOrderItems" on ("Esns"."PurchaseOrderItemId" =
"PurchaseOrderItems".id)
JOIN "Items" on ("PurchaseOrderItems"."ItemId" = "Items".id)
JOIN "Grades" on ("PurchaseOrderItems"."GradeId" = "Grades".id)
JOIN "Vendors" on ("Vmas"."VendorId" = "Vendors".id)
WHERE "Vmas".id =2 AND "EsnsVmas"."approved" = true
GROUP BY "Vmas".id, "PurchaseOrderItems".id, "Grades".id, "Items".id, "Vendors".id, "EsnsVmas".id ;
This changed two things. First was relating back with "EsnsVmas".id = e2.id at the end of the subselect (I aliased the EsnsVmas table in the subselect to e2). The other thing was changing e2."VmaId" = "Vmas".id (instead of hardcoding it to 2) which shouldn't affect the output but allows you to change the id in only one place.