How clever is the PostgreSQL planner - postgresql

I mainly use the R package dbplyr to interact with a PostgreSQL database. That works by "piping" operations which are then translated to SQL and executed in one query. This tends to result in many nested joins. I wonder how clever the planner is when it comes to resolving such rather verbose and un-optimized expressions. Is it even possible to write "bad queries" as long as they only use e.g. SELECT, WHERE and JOIN (and no functions, casting etc) and where the end result is the same? How would such a query look? For example, will the planner figure out which columns are needed in a hash join in order to reduce memory, even if the columns are not specified in that join but only at the end after a join involving, say, 6 tables?
For example, can I safely ignore:
Join order
When columns are selected
When filters are applied
I've found a lot of info about how the planner calculates costs and chooses a path, but not so much on how it arrives at a "minimal form" of the query at the first place. EXPLAIN ANALYZE doesn't help because it doesn't show which columns end up being selected. I'm sure someone will be unhappy with this question due to being too vague. If so, please point me in the right direction :)
EDIT:
An example.
Here is how a typical query would look in R with dbplyr. "gene_annotations" have the columns "gene" and "annotation_term". "genemaps" have "genemap", "gene", "probe", "study". Here I want to get the gene and annotation associated to a probe.
tbl(con, "gene_annotations") %>% inner_join(tbl(con, "genemaps"), by = "gene") %>%
filter(probe == 1L) %>% select(gene, annotation_term)
This translates to:
SELECT "gene", "annotation_term"
FROM (SELECT "LHS"."gene" AS "gene", "LHS"."annotation_term" AS "annotation_term", "RHS"."genemap" AS "genemap", "RHS"."probe" AS "probe", "RHS"."study" AS "study"
FROM "gene_annotations" AS "LHS"
INNER JOIN "genemaps" AS "RHS"
ON ("LHS"."gene" = "RHS"."gene")
) "dbplyr_004"
WHERE ("probe" = 1)
Can I trust that this has the exact same performance as e.g. this expression (except for the time for parsing and analyzing the expression)?
tbl(con, "gene_annotations") %>% inner_join(tbl(con, "genemaps") %>%
filter(probe == 1L) %>% select(gene) , by = "gene")
SELECT "LHS"."gene" AS "gene", "LHS"."annotation_term" AS "annotation_term"
FROM "gene_annotations" AS "LHS"
INNER JOIN (SELECT "gene"
FROM "genemaps"
WHERE ("probe" = 1)) "RHS"
ON ("LHS"."gene" = "RHS"."gene")
The plan is the same in both cases:
Nested Loop (cost=0.86..72.09 rows=546 width=8)
-> Index Only Scan using genemaps_probe_index on genemaps (cost=0.43..2.16 rows=36 width=4)
Index Cond: (probe = 1)
-> Index Only Scan using gene_annotations_pkey on gene_annotations "LHS" (cost=0.43..1.79 rows=15 width=8)
Index Cond: (gene = genemaps.gene)
I didn't want to provide an example, because I don't have an issue with this specific query. I'm wondering is if I can always disregard these issues altogether and just piece together joins until I get the end result I want.
EDIT 2:
I found out that there is a VERBOSE option to EXPLAIN where you can see which columns are returned. For the small example above the plan was identical also in that regard. Still, can I assume that holds for all reasonably complex queries? This is an example of how my queries typically look. As you can see, the SQL dbplyr generates isn't very easy to read. Here it joins six tables after various SELECT/WHERE.
SELECT "LHS"."sample_group" AS "sample_group", "LHS"."sample_group_name" AS "sample_group_name", "LHS"."sample_group_description" AS "sample_group_description", "LHS"."sample" AS "sample", "LHS"."sample_name" AS "sample_name", "LHS"."value" AS "value", "LHS"."gene" AS "gene", "LHS"."probe" AS "probe", "LHS"."gene_symbol" AS "gene_symbol", "LHS"."probe_name" AS "probe_name", "RHS"."factor_order" AS "factor_order"
FROM (SELECT "LHS"."sample_group" AS "sample_group", "LHS"."sample_group_name" AS "sample_group_name", "LHS"."sample_group_description" AS "sample_group_description", "LHS"."sample" AS "sample", "LHS"."sample_name" AS "sample_name", "LHS"."value" AS "value", "LHS"."gene" AS "gene", "LHS"."probe" AS "probe", "LHS"."gene_symbol" AS "gene_symbol", "RHS"."probe_name" AS "probe_name"
FROM (SELECT "LHS"."sample_group" AS "sample_group", "LHS"."sample_group_name" AS "sample_group_name", "LHS"."sample_group_description" AS "sample_group_description", "LHS"."sample" AS "sample", "LHS"."sample_name" AS "sample_name", "LHS"."value" AS "value", "LHS"."gene" AS "gene", "LHS"."probe" AS "probe", "RHS"."gene_symbol" AS "gene_symbol"
FROM (SELECT "sample_group", "sample_group_name", "sample_group_description", "sample", "sample_name", "value", "gene", "probe"
FROM (SELECT "LHS"."sample_group" AS "sample_group", "LHS"."sample_group_name" AS "sample_group_name", "LHS"."sample_group_description" AS "sample_group_description", "LHS"."sample" AS "sample", "LHS"."sample_name" AS "sample_name", "LHS"."genemap" AS "genemap", "LHS"."annotation_term" AS "annotation_term", "LHS"."value" AS "value", "RHS"."gene" AS "gene", "RHS"."probe" AS "probe"
FROM (SELECT "LHS"."sample_group" AS "sample_group", "LHS"."sample_group_name" AS "sample_group_name", "LHS"."sample_group_description" AS "sample_group_description", "LHS"."sample" AS "sample", "LHS"."sample_name" AS "sample_name", "RHS"."genemap" AS "genemap", "RHS"."annotation_term" AS "annotation_term", "RHS"."value" AS "value"
FROM (SELECT *
FROM (SELECT "sample_group", "sample_group_name", "sample_group_description", "sample", "sample_name"
FROM "sample_view") "dbplyr_031"
WHERE (270 = 270)) "LHS"
INNER JOIN "gene_measurements" AS "RHS"
ON ("LHS"."sample" = "RHS"."sample")
) "LHS"
INNER JOIN (SELECT "genemap", "gene", "probe"
FROM "genemaps"
WHERE ("gene" IN (54812) AND "study" = 270)) "RHS"
ON ("LHS"."genemap" = "RHS"."genemap")
) "dbplyr_032") "LHS"
INNER JOIN (SELECT "gene", "gene_symbol"
FROM "genes") "RHS"
ON ("LHS"."gene" = "RHS"."gene")
) "LHS"
INNER JOIN (SELECT "probe", "probe_name"
FROM "probes") "RHS"
ON ("LHS"."probe" = "RHS"."probe")
) "LHS"
INNER JOIN (SELECT "group", "annotation_term_value" AS "factor_order"
FROM (SELECT "LHS"."group" AS "group", "LHS"."annotation_term" AS "annotation_term", "RHS"."annotation_term_value" AS "annotation_term_value"
FROM "group_annotations" AS "LHS"
INNER JOIN (SELECT "annotation_term", "annotation_term_value"
FROM "annotation_terms"
WHERE ("annotation_type" = 111)) "RHS"
ON ("LHS"."annotation_term" = "RHS"."annotation_term")
) "dbplyr_033") "RHS"
ON ("LHS"."sample_group" = "RHS"."group")

Related

Postgres json aggregate function calls cannot be nested

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

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

Is there any function to check value present in json array? Need where condition for in_array type json function for query

What should I do for checking any string with json array?
I have tried query for 1st value of json array and it's working fine. Now when I tried for other value it's working wrong.
SELECT pc.product_category_id, pc.name, pc.caption,
pca.name as main_category_name, pbg.name as product_fabric_name,
pc.company_id
FROM product_category pc
LEFT JOIN product_category pca ON pca.product_category_id = pc.main_category_id
LEFT JOIN product_fabric_group pbg ON pbg.product_fabric_group_id = pc.product_fabric_id
WHERE 1>0 AND (pc.company_id->>0 = '4438')
ORDER BY pc.product_category_id DESC
Above query is working perfect for company_id array is equal to { 4438, 4440, 2116, 297, 1166, 2656, 4096, 5218, 570, 1091, 1534, 649, 4182, 800, 4794, 945, 934, 4126, 2686, 4551, 3185, 4339, 1033, 1376, 1417, 5197 }
I'm getting no result found for below query :
SELECT pc.product_category_id, pc.name, pc.caption,
pca.name as main_category_name, pbg.name as product_fabric_name,
pc.company_id
FROM product_category pc
LEFT JOIN product_category pca ON pca.product_category_id = pc.main_category_id
LEFT JOIN product_fabric_group pbg ON pbg.product_fabric_group_id = pc.product_fabric_id
WHERE 1>0 AND (pc.company_id->>0 = '3185')
ORDER BY pc.product_category_id DESC
Please suggest me query for company_id = 3185 which can result positive. Please help me out with this.
Use the “contains” operator #>:
... WHERE pc.company_id #> '3185'
This query can be supported by a GIN index on the jsonb column.
This won't work with type json, only with jsonb. If you have json, you can either cast to jsonb:
... WHERE CAST(pc.company_id AS jsonb) #> '3185'
or (better) convert the column to jsonb:
ALTER TABLE product_category ALTER company_id TYPE jsonb;

Postgres Complex Select in a View

I have this select clause that is working perfect:
SELECT
"Aspectos"."ID" AS "Aspecto Normativo ID",
"Aspectos"."Aspecto" AS "Aspecto Normativo",
"Fatores"."ID", "Fatores"."Fator" AS "Fator Normativo",
"Diagnostico"."Vinculo_Final",
"Fatores_1"."ID",
"Fatores_1"."Fator" AS "Fator Determinativo",
"Aspectos_1"."ID" AS "Aspecto Determinativo ID",
"Aspectos_1"."Aspecto" AS "Aspecto Determinativo",
Count("Itens"."ID") AS "No Itens",
Count("Itens"."ID") AS "Pri"
FROM "Diagnostico" INNER JOIN ("Aspectos" AS "Aspectos_1"
INNER JOIN (("Fontes" INNER JOIN "Itens" ON "Fontes"."ID" = "Itens"."Fonte")
INNER JOIN ("Fatores" AS "Fatores_1"
INNER JOIN ("Aspectos"
INNER JOIN ("Vinculos"
INNER JOIN "Fatores"
ON "Vinculos"."Fator_Normativo" = "Fatores"."ID")
ON ("Aspectos"."ID" = "Fatores"."Aspecto")
AND ("Aspectos"."ID" = "Fatores"."Aspecto"))
ON "Fatores_1"."ID" = "Vinculos"."Fator_Determinativo")
ON "Itens"."ID" = "Vinculos"."Item")
ON "Aspectos_1"."ID" = "Fatores_1"."Aspecto")
ON "Diagnostico"."ID" = "Vinculos"."Diagnostico_ID"
GROUP BY "Aspectos"."ID", "Aspectos"."Aspecto",
"Fatores"."ID", "Fatores"."Fator",
"Diagnostico"."Vinculo_Final",
"Fatores_1"."ID",
"Fatores_1"."Fator",
"Aspectos_1"."ID",
"Aspectos_1"."Aspecto"
ORDER BY "Aspectos"."ID", "Aspectos_1"."ID",
"Fatores"."Fator", "Fatores_1"."Fator";
But when I try to CREATE A VIEW with this same select I'm getting thuis error:
ERROR: column "ID" specified more than one time
Can anybody help me on this.
Thanks
You have "Fatores"."ID" (line 4) and "Fatores_1"."ID" (line 6). Give them different aliases.
For such complex queries it is recommended to have only 1 (one) column in per line in the statement for better visibility. Also it is recommended to always give aliases to the columns.

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.