Sequelize order by two nested associations - postgresql

I try to use the order for both my sub-queries. But sequelize generate a bad query and use this order by on main-query.
Here is my query:
Model.findAll({
order: sequelize.literal('("asset->forOrder"."value" - "asset.currenthours") desc),
offset: 0,
limit: 10,
include: [{
model: Asset,
as: 'asset',
include: [{
model: ThresholdService,
required: false,
as: 'thresholdservices'
}, {
model: ThresholdService,
where: {property: 'hours'},
required: false,
duplicating: false,
as: 'forOrder'
}],
}]
})
I expected to get query like this:
SELECT ..., "asset->forOrder"."asset_id", "asset->forOrder"."value"
FROM (
SELECT ...
FROM "machineidentity" AS "machineidentity"
LIMIT 10 OFFSET 0
) AS "machineidentity"
LEFT OUTER JOIN "asset" AS "asset" ON "machineidentity"."unique_id" = "asset"."machineIdentityId"
LEFT OUTER JOIN "thresholdservice" AS "asset->thresholdservices" ON "asset"."id" = "asset->thresholdservices"."asset_id"
LEFT OUTER JOIN "thresholdservice" AS "asset->forOrder" ON "asset"."id" = "asset->forOrder"."asset_id" AND "asset->forOrder"."property" = 'hours'
ORDER BY ("asset->forOrder"."value" - "asset"."currenthours") DESC;
but have:
SELECT ..., "asset->forOrder"."asset_id", "asset->forOrder"."value"
FROM (
SELECT ...
FROM "machineidentity" AS "machineidentity"
ORDER BY ("asset->forOrder"."value" - "asset"."currenthours") DESC
LIMIT 10 OFFSET 0
) AS "machineidentity"
LEFT OUTER JOIN "asset" AS "asset" ON "machineidentity"."unique_id" = "asset"."machineIdentityId"
LEFT OUTER JOIN "thresholdservice" AS "asset->thresholdservices" ON "asset"."id" = "asset->thresholdservices"."asset_id"
LEFT OUTER JOIN "thresholdservice" AS "asset->forOrder" ON "asset"."id" = "asset->forOrder"."asset_id" AND "asset->forOrder"."property" = 'hours'
ORDER BY ("asset->forOrder"."value" - "asset"."currenthours") DESC;
ORDER BY appear in machineidentity query.

I found in sequelize such code:
if (
subQuery
&& Array.isArray(order)
&& order[0]
&& !(order[0] instanceof Association)
&& !(typeof order[0] === 'function' && order[0].prototype instanceof Model)
&& !(typeof order[0].model === 'function' && order[0].model.prototype instanceof Model)
&& !(typeof order[0] === 'string' && model && model.associations !== undefined && model.associations[order[0]])
) {
subQueryOrder.push(this.quote(order, model, '->'));
}
mainQueryOrder.push(this.quote(order, model, '->'));
I have just created order, which not satisfied this if.
So, right now my order, looks like:
[['asset.forOrder', 'value', sequelize.literal('-(machine.asset.currentkilometers - machine.asset.initialvalueinkm)')]]

Related

LEFT JOIN on table returns array with one element instead of empty array, when using json_build_object

I have the following query:
SELECT
u.*,
array_agg(
json_build_object(
'id', usn.id,
'schemaName', usn.schema_name
)
) AS schemas
FROM dev.users u
FULL OUTER JOIN dev.user_schema_names usn ON u.id = usn.user_id
WHERE u.email = $1
GROUP BY u.id
But for some odd reason, this returns the following:
{
id: 1,
email: 'test#test.com',
schemas: [ { id: null, schemaName: null } ]
}
The dev.user_schema_names has no records in it. I am expecting schemas to be an empty array []. If I insert records in dev.user_schema_names, then it works just fine, however.
What am I doing wrong? Should I be using something else instead of json_build_object?

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

Kentico document query API always returns empty result

I have the following query:
var newsItems = tree.SelectNodes()
.Types(pageTypesArray)
.Path(path)
.OrderBy(orderBy)
.CombineWithDefaultCulture(false)
.Page(page, count)
.OnCurrentSite()
.NestingLevel(-1)
.Culture(CurrentDocument.DocumentCulture)
.InCategories(categories)
.TopN(topN)
.Where("ListableDocumentImage is not null AND ListableDocumentImage != ''")
.Columns(columns);
Which translates like so:
WITH AllData AS
(
SELECT TOP 6 * for brevity, ROW_NUMBER() OVER (ORDER BY [NewsOccurrenceDate] DESC) AS [CMS_RN]
FROM View_CMS_Tree_Joined AS V WITH (NOLOCK, NOEXPAND) INNER JOIN SOS_News AS C WITH (NOLOCK) ON [V].[DocumentForeignKeyValue] =
[C].[NewsID] AND V.ClassName = N'News' LEFT OUTER JOIN COM_SKU AS S WITH (NOLOCK) ON [V].[NodeSKUID] = [S].[SKUID]
WHERE [NodeSiteID] = #NodeSiteID AND (([DocumentCanBePublished] = 1 AND ([DocumentPublishFrom] IS NULL OR [DocumentPublishFrom] <= #Now)
AND ([DocumentPublishTo] IS NULL OR [DocumentPublishTo] >= #Now))
AND [NodeAliasPath] LIKE #NodeAliasPath AND [DocumentCulture] = #DocumentCulture
**AND 0 = 1)** <<<------------------- WHERE DID THIS COME FROM?????
)
SELECT *, (SELECT COUNT(*) FROM AllData) AS [CMS_TOT]
FROM AllData
WHERE CMS_RN BETWEEN 4 AND 6
ORDER BY CMS_RN
Has anyone ever come across anything like this before? I can't figure out why they're sticking in the AND 0=1 in my where clause.
Properly structuring your document API call will help with this. In your query results, you can see your WHERE condition is not even being added so it does make a difference the order of the methods being called.
For instance:
var newsItems = tree.SelectNodes()
.Types(pageTypesArray)
.Path(path)
.Where("ListableDocumentImage is not null AND ListableDocumentImage != ''")
.TopN(topN)
.OrderBy(orderBy)
.CombineWithDefaultCulture(false)
.Page(page, count)
.NestingLevel(-1)
.Culture(CurrentDocument.DocumentCulture)
.InCategories(categories)
.OnCurrentSite()
.Columns(columns);

Map SQL with JOIN, GROUP BY, and SUM to Entity Framework query

I'd like to map the following SQL to EF query. I found a few similar topics, but still failed to achieve the mapping. {0}...{2} are SQL parameters.
SELECT TaskGroup.Project AS Project
SUM(Datediff(minute, WorkLog.StartTime, WorkLog.EndTime)) / 60 AS Hours
FROM WorkLog INNER JOIN TaskDefinition ON WorkLog.TaskDefinitionID = TaskDefinition.ID
INNER JOIN TaskGroup ON TaskDefinition.TaskGroupID = TaskGroup.ID
WHERE WorkLog.EmployeeID = {0} AND WorkLog.Status = 5 AND
WorkLog.StartTime >= {1} AND WorkLog.EndTime < {2}
GROUP BY TaskGroup.Project
What about this?
var query = (from wl in WorkLog
join td in TaskDefinition on wl.TaskDefinitionID equals td.ID
join tg in TaskGroup on td.TaskGroupID equals tg.ID
where wl.EmployeeID == { 0} && wl.Status == 5
&& wl.StartTime >= { 1} && wl.EndTime < { 2}
select new
{
Project = tg.Project,
StartTime = wl.StartTime,
EndTime = wl.EndTime
})
.GroupBy(o => o.Project)
.Select(g => new
{
Project = g.Key,
Hours = g.Sum(o => (o.EndTime - o.StartTime).Minutes) / 60
});

Error thrown when trying to chain a text search with a search on a join table that uses group_by

I have three models, Story, Post and Tag. Story is in a one-to-many relationship with Post, and a many-to-many relationship with Tag.
I use the following scope to search for stories that have a least one tag that matches an array of tags:
scope :in_tags, lambda {|category_array, tag_array|
Story.joins('LEFT OUTER JOIN stories_tags ON stories_tags.story_id = stories.id').
joins('LEFT OUTER JOIN tags ON tags.id = stories_tags.tag_id').
where("tags.name in (:tag_array)", :tag_array => tag_array ).
group("stories.id")
}
Note that I use GROUP_BY so that the scope doesn't return a story multiple times if that story has multiple matching tags.
I use the following pg_search_scope to search for stories or posts with specified text:
pg_search_scope :with_text,
:against => :title,
:using => { :tsearch => { :dictionary => "english" }},
:associated_against => { :posts => :contents }
Both of these scopes work fine independent of each other. When I try to chain them together, however, I experience the postgreSQL error:
ActiveRecord::StatementInvalid (PG::Error: ERROR: column "pg_search_79dd68cf7f962ac568b3d7.pg_search_c5f43d73058486e1799d26" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: ...e"::text, '')) || to_tsvector('english', coalesce(pg_search_...
^
: SELECT "stories".*, ((ts_rank((to_tsvector('english', coalesce("stories"."title"::text, '')) || to_tsvector('english', coalesce(pg_search_79dd68cf7f962ac568b3d7.pg_search_c5f43d73058486e1799d26::text, ''))), (to_tsquery('english', ''' ' || 'track' || ' ''')), 0))) AS pg_search_rank FROM "stories" LEFT OUTER JOIN stories_tags ON stories_tags.story_id = stories.id LEFT OUTER JOIN tags ON tags.id = stories_tags.tag_id LEFT OUTER JOIN (SELECT "stories"."id" AS id, string_agg("posts"."contents"::text, ' ') AS pg_search_c5f43d73058486e1799d26 FROM "stories" INNER JOIN "posts" ON "posts"."story_id" = "stories"."id" GROUP BY "stories"."id") pg_search_79dd68cf7f962ac568b3d7 ON pg_search_79dd68cf7f962ac568b3d7.id = "stories"."id" WHERE (tags.name in (sports') AND (((to_tsvector('english', coalesce("stories"."title"::text, '')) || to_tsvector('english', coalesce(pg_search_79dd68cf7f962ac568b3d7.pg_search_c5f43d73058486e1799d26::text, ''))) ## (to_tsquery('english', ''' ' || 'track' || ' ''')))) GROUP BY stories.id ORDER BY latest_post_id DESC LIMIT 5000 OFFSET 0):
Is there any way to use pg_search with a scope that requires a join table with a GROUP_BY clause?
I ended up having to switch from the .group() method (which I couldn't seem to get working with pg_search) to select("DISTINCT(stories.id), stories.*). I also made use of ActiveRecords#preload so to eagerly load the associated tag records