Is there any way to write this code avoiding intermediate steps/views in PostgreSQL coming from different tables? - postgresql

I am working in a large query I would like to eliminate intermediate
steps, so I am trying to write the two queries below in just one.
The first query (QUERY 1) select the grid id from a table called
tiles, from here i obtained an UUID who correspond to a value in a
second table so to obtain the real value of this grid id I have to
query a second query (QUERY 2). I have try to cast everything as I did
in the third query for other values, but this approach doesn't work.
Has someone an idea how can I manage to do this query (query 1 and 2)
just in one:
QUERY 1:
SELECT
jsonb_array_elements(grid_id_tile.tiledata -> '34cfea5d-c2c0-11ea-9026-02e7594ce0a0'::text) ->> 'resourceId'::text AS grid_id
FROM mv_geojson_geoms mv
LEFT JOIN tiles grid_id_tile ON tv1.resourceinstanceid = grid_id_tile.resourceinstanceid
WHERE (( SELECT resource_instances.graphid
FROM resource_instances
WHERE mv.resourceinstanceid = resource_instances.resourceinstanceid)) = '34cfe98e-c2c0-11ea-9026-02e7594ce0a0'::uuid;
QUERY 2:
SELECT grid_id.legacyid AS grid_id,
FROM table 1 (Where I have obtained the grid id)
LEFT JOIN resource_instances grid_id ON hb1.grid_id = grid_id.resourceinstanceid::text
QUERY 3:
( SELECT "values".value
FROM "values"
WHERE ((name_ft_tile.tiledata ->> '34cfea97-c2c0-11ea-9026-02e7594ce0a0'::text)::uuid) = "values".valueid) AS nametype,
FROM mv_geojson_geoms mv
LEFT JOIN tiles name_ft_tile ON mv.resourceinstanceid = name_ft_tile.resourceinstanceid AND (name_ft_tile.tiledata ->> '34cfea97-c2c0-11ea-9026-02e7594ce0a0'::text) <> ''::text
WHERE (( SELECT resource_instances.graphid
FROM resource_instances
WHERE mv.resourceinstanceid = resource_instances.resourceinstanceid)) = '34cfe98e-c2c0-11ea-9026-02e7594ce0a0'::uuid
Those are the type of data I am managing at the moment:
This is the table tiles where in the jsonb got the UUID from the feature i would like to get the gridid
This is the table resource instance where the legacyid is
So from the query 1 I get this result Gridid is a UUID
And from query 2 I get this result with the grid_id code
This is what I obtain and I would like to get directly the grid_id value without intermediate steps
The third query is a sample of similar approach I did so in one query I get the value instead of the UUID, and it is what I would like to do with the grid_id.
But when I run the similar code I get the error, because I get the element from an array:
ERROR: cannot extract elements from a scalar
CONTEXT: parallel worker
SQL state: 22023

You can literally inline the query 1 as a subquery where you've written "table 1 (Where I have obtained the grid id)":
SELECT grid_id.legacyid AS grid_id
FROM (
SELECT jsonb_array_elements(grid_id_tile.tiledata -> '34cfea5d-c2c0-11ea-9026-02e7594ce0a0'::text) ->> 'resourceId'::text AS grid_id
FROM mv_geojson_geoms mv
LEFT JOIN tiles grid_id_tile ON mv.resourceinstanceid = grid_id_tile.resourceinstanceid
JOIN resource_instances ON mv.resourceinstanceid = resource_instances.resourceinstanceid
WHERE resource_instances.graphid = '34cfe98e-c2c0-11ea-9026-02e7594ce0a0'::uuid;
) AS hb1
LEFT JOIN resource_instances grid_id ON hb1.grid_id = grid_id.resourceinstanceid::text;

Related

Return closest timestamp from Table B based on timestamp from Table A with matching Product IDs

Goal: Create a query to pull the closest cycle count event (Table C) for a product ID based on the inventory adjustments results sourced from another table (Table A).
All records from Table A will be used, but is not guaranteed to have a match in Table C.
The ID column will be present in both tables, but is not unique in either, so that pair of IDs and Timestamps together are needed for each table.
Current simplified SQL
SELECT
A.WHENOCCURRED,
A.LPID,
A.ITEM,
A.ADJQTY,
C.WHENOCCURRED,
C.LPID,
C.LOCATION,
C.ITEM,
C.QUANTITY,
C.ENTQUANTITY
FROM
A
LEFT JOIN
C
ON A.LPID = C.LPID
WHERE
A.facility = 'FACID'
AND A.WHENOCCURRED > '23-DEC-22'
AND A.ADJREASONABBREV = 'CYCLE COUNTS'
ORDER BY A.WHENOCCURRED DESC
;
This is currently pulling the first hit on C.WHENOCCURRED on the LPID matches. Want to see if there is a simpler JOIN solution before going in a direction that creates 2 temp tables based on WHENOCCURRED.
I have a functioning INDEX(MATCH(MIN()) solution in Excel but that requires exporting a couple system reports first and is extremely slow with X,XXX row tables.
If you are using Oracle 12 or later, you can use a LATERAL join and FETCH FIRST ROW ONLY:
SELECT A.WHENOCCURRED,
A.LPID,
A.ITEM,
A.ADJQTY,
C.WHENOCCURRED,
C.LPID,
C.LOCATION,
C.ITEM,
C.QUANTITY,
C.ENTQUANTITY
FROM A
LEFT OUTER JOIN LATERAL (
SELECT *
FROM C
WHERE A.LPID = C.LPID
AND A.whenoccurred <= c.whenoccurred
ORDER BY c.whenoccurred
FETCH FIRST ROW ONLY
) C
ON (1 = 1) -- The join condition is inside the lateral join
WHERE A.facility = 'FACID'
AND A.WHENOCCURRED > DATE '2022-12-23'
AND A.ADJREASONABBREV = 'CYCLE COUNTS'
ORDER BY A.WHENOCCURRED DESC;

Use postgresql query results to form another query

I am trying to select from one table using the select result from another table. I can run this in two queries but would like to optimize it into just one.
First query.. Select ids where matching other id
select id from lookuptable where paid = '547'
This results in something like this
6316352
6316353
6318409
6318410
6320468
6320469
6320470
6322526
6322527
6324586
6324587
6326648
I would like to then use this result to make another selection. I can do it manually like below. Note, there could be many rows with these values so I've been using a IN statement
select * from "othertable" where id in (6316352,6316353,6318409,6318410,6320468,6320469,6320470,6322526,6322527,6324586,6324587,6326648);
select
ot.*
from
"othertable" as ot
join
lookuptable as lt
on
ot.id = lt.id
where
lt.paid = '547'
The IN operator supports not just value lists but also subqueries, so you can literally write
select * from "othertable" where id in (select id from lookuptable where paid = '547');

PonyORM: how to get rid of "subquery uses ungrouped column"?

Please assume this data model. This is a simplified model of what I really have here but all important fields are there. Database: Postgres. I want to calculate some stats on those models and I stumbled upon this problem:
c = Customer.select().random(1)[0] # example
query = left_join(
(
p,
count(i.order.customer == c),
count((b.is_used == True) for b in i.bonuses),
count(i)
) for p in Product
for i in p.order_items)
Now trying to show results (in reality I have some more filtering on the aggregations to do)
query.show()
yields this:
ProgrammingError: subquery uses ungrouped column "i.id" from outer query
LINE 4: WHERE "i"."id" = "b"."order_item"
What can I do to correct this?
Resulting SQL looks like this:
SELECT "p"."id", COUNT(case when "order"."customer" = ? then 1 else null end), (
SELECT COUNT(DISTINCT "b"."is_used" = 1)
FROM "Bonus" "b"
WHERE "i"."id" = "b"."order_item"
), COUNT(DISTINCT "i"."id")
FROM "Product" "p"
LEFT JOIN "OrderItem" "i"
ON "p"."id" = "i"."product"
LEFT JOIN "Order" "order"
ON "i"."order" = "order"."id"
GROUP BY "p"."id"
EDIT:
My real models are made to fit a db used by Django, so I have _table_ in each class and column=something_id in all foreign keys. But aside that everything looks OK to the point I can make any simpler query with ease.
EDIT2:
Here's the gist with my test data.
It appears that I needed to rephrase the code to this form:
query = left_join(
(
p,
count(i.order.customer == c),
count(b.is_used == True),
count(i)
) for p in Product
for i in p.order_items
for b in i.bonuses)

comprare aggregate sum function to number in postgres

I have the next query which does not work:
UPDATE item
SET popularity= (CASE
WHEN (select SUM(io.quantity) from item i NATURAL JOIN itemorder io GROUP BY io.item_id) > 3 THEN TRUE
ELSE FALSE
END);
Here I want to compare each line of inner SELECT SUM value with 3 and update popularity. But SQL gives error:
ERROR: more than one row returned by a subquery used as an expression
I understand that inner SELECT returns many values, but can smb help me in how to compare each line. In other words make loop.
When using a subquery you need to get a single row back, so you're effectively doing a query for each record in the item table.
UPDATE item i
SET popularity = (SELECT SUM(io.quantity) FROM itemorder io
WHERE io.item_id = i.item_id) > 3;
An alternative (which is a postgresql extension) is to use a derived table in a FROM clause.
UPDATE item i2
SET popularity = x.orders > 3
FROM (select i.item_id, SUM(io.quantity) as orders
from item i NATURAL JOIN itemorder io GROUP BY io.item_id)
as x(item_id,orders)
WHERE i2.item_id = x.item_id
Here you're doing a single group clause as you had, and we're joining the table to be updated with the results of the group.

PostgreSQL - select the results of two subqueries

I have 2 complex queries that are both subqueries in postgres, the results of which are:
q1_results = id , delta , metric_1
q2_results = id , delta , metric_2
i'd like to combine the results of the queries, so the outer query can access either:
results_a = id , delta , metric_1 , metric_2
results_b = id , delta , combined_metric
i can't figure out how to do this. online searches keep leading me to UNION , but that keeps the metrics in the same column. i need to keep them split.
It's not entirely clear what you're asking in the question and the comments, but it sounds like you might be looking for a full join with a bunch of coalesce statements, e.g.:
-- create view at your option, e.g.:
-- create view combined_query as
select coalesce(a.id, b.id) as id,
coalesce(a.delta, b.delta) as delta,
a.metric1 as metric1,
b.metric2 as metric2,
coalesce(a.metric1,0) + coalesce(b.metric2,0) as combined
from (...) as results_a a
full join (...) as results_b b on a.id = b.id -- and a.delta = b.delta maybe?